2scottish
2scottish

Reputation: 683

How do I pass a statement as an argument to a block within a method?

I'm trying figure out how to pass a statement as a method argument - to be used as part of the block filter criteria. For example, I have the following code:

def method
  other_method.persons.each do |ped|

    next if ped.first_name.nil? or ped.last_name.nil?

    puts ped.id
    puts ped.full_name
  end
end

What I'd like to be able to do is as follows (so I can potentially change the filter criteria used in the method). Is it possible to pass a statement including the block reference to the block from a argument?:

def method(statement)
  other_method.persons.each do |ped|

    next if statement

    puts ped.id
    puts ped.full_name
  end
end

I appreciate some direction on this.

Upvotes: 2

Views: 129

Answers (2)

Catnapper
Catnapper

Reputation: 1905

Ped = Struct.new(:first_name, :last_name, :full_name, :id)

# generate some test data
peds = ['Bob', 'Hope', 'Bob Hope', 1, 'Bing', nil, 'Bing Crosby', 2, nil, 'Bacon', 'Kevin Bacon', 3].each_slice(4).map{ |x,y,z,id| Ped.new(x,y,z,id) }

filter_criteria = lambda { |ped| ped.first_name.nil? or ped.last_name.nil? }

peds.find_all(&filter_criteria).each { |ped| p ped }

Output:

#<struct Ped first_name="Bing", last_name=nil, full_name="Bing Crosby", id=2>
#<struct Ped first_name=nil, last_name="Bacon", full_name="Kevin Bacon", id=3>

Change out filter_criteria with another Proc/lambda to change the filtering. An alternative is to wrap the find_all in a method to take a filtering block like this:

def filter list, &criteria
  list.find_all(&criteria)
end

filter(pedlist) { |ped| some filter criteria }.each { |ped| do something }

and the resulting enumerable can then be used as needed.

Upvotes: 0

dbenhur
dbenhur

Reputation: 20408

You don't pass "statements" you pass blocks. A passed block is called via yield or captured into a proc and called with Proc#call.

def method
  other_method.persons.each do |ped|
    next if yield(ped)

    puts ped.id
    puts ped.full_name
  end
end

method { |ped| ped.first_name.nil? or ped.last_name.nil? }

Upvotes: 6

Related Questions