Reputation: 2056
I'm trying to send a parameter to a Ruby proc
p1 = [54, 21, 45, 76, 12, 11, 67, 5]
qualify = proc { |age, other| age > other }
puts p1.select(&qualify(30))
This is the error I get:
undefined method `qualify' for main:Object
age comes from the iteration of the array
, and I want to have that last parameter
(30) to get into the proc
.
Is a proc
the right tool to be using for this? I'm new to proc. I'm unclear how to get that parameter
in there.
Upvotes: 4
Views: 3727
Reputation: 211590
The easy way is to shuffle up how you define this:
p1 = [54, 21, 45, 76, 12, 11, 67, 5]
qualify = proc { |age| age > 30 }
puts p1.select(&qualify).join(',')
By moving the 30
into the qualify
proc you've baked in the condition, it's no longer dynamic. Remember, the only methods that can be used with the shorthand &:
trick are zero-argument ones, or single argument ones with &
on a proc.
You could also use a closure to have the comparison variable exposed:
p1 = [54, 21, 45, 76, 12, 11, 67, 5]
required = 30
qualify = proc { |age| age > required }
puts p1.select(&qualify).join(',')
required = 10
puts p1.select(&qualify).join(',')
The better way is to just spell it out, that's what Ruby is all about. Here in a more idiomatic form:
p1 = [54, 21, 45, 76, 12, 11, 67, 5]
puts p1.select { |age| age > 30 }
The only reason for an intermediate Proc is if you'd want to, for some reason, save that somewhere and re-use it later.
Upvotes: 4
Reputation: 1060
Use the select statement in the proc itself, so that the proc would calculate and return an array.
2.1.5 :119 > qualify = proc { |age_array, age_limit| age_array.select { |age| age > age_limit } }
=> #<Proc:0xe7bc2cc@(irb):119>
2.1.5 :120 >
2.1.5 :121 >
2.1.5 :122 > qualify.call(p1, 30)
=> [54, 45, 76, 67]
Upvotes: 3
Reputation: 23327
In order to use qualify
in as select
predicate, you need to reduce its arity (number of accepted arguments) through partial application. In other words - you need a new proc that would have other
set to 30
. It can be done with Method#curry
, but it requires changing order of parameters:
qualify = proc { |other, age| age > other }
qualify.curry.call(30).call(10)
# => false
qualify.curry.call(30).call(40)
#=> true
I order to be able to pass this proc to select using &
, you need to assign it so that it's available in the main object, e.g. by assigning it to an instance variable:
@qualify_30 = qualify.curry.call(30)
Now you can call:
p1.select{ |age| @qualify_30.call(age) }
# => [54, 45, 76, 67]
or:
p1.select(&@qualify_30)
# => [54, 45, 76, 67]
or inline:
p1.select(&qualify.curry.call(30))
# => [54, 45, 76, 67]
Upvotes: 4