Muhammad Umer
Muhammad Umer

Reputation: 18097

Check how many parameters block being passed has, and then invoke yield with different parameters

I want to know if something like this is possible, as hash.each does two different things based on arguments passed to block

{ "a"=>3, "b"=>2}.each {|k| puts k}

{ "a"=>3, "b"=>2}.each {|k,v| puts k}

Both output different things, and not just what's below..

a
b
..
a
b

I get this

a
3
b
2
..
a
b

So I want to know if there is a way to get my function to do something custom depending on the number of arguments of block being passed to it.

like this

def my_method
   if yield.args==2
     yield("hi","bro")
   else 
     yield("what's up")
   end
end

my_method {|a,b| puts a; puts b;} #"hi" "bro"

my_method {|a| puts a; } #"whats up"

Upvotes: 0

Views: 88

Answers (2)

ndnenkov
ndnenkov

Reputation: 36101

def my_method(&block)
  if block.arity == 2
    yield("hi", "bro")
  else 
    yield("what's up")
  end
end

Also look at the documentation since Proc#arity has special behavior for default/named arguments, etc.

Upvotes: 3

Jörg W Mittag
Jörg W Mittag

Reputation: 369458

You can capture the block as a Proc and then inspect its parameters:

def my_method(&blk)
  blk.parameters
end

my_method {|a|}
# => [[:opt, :a]]

my_method {|a, b|}
# => [[:opt, :a], [:opt, :b]]

Note, however, that this is not what happens with Hash#each. Hash#each just follows the Enumerable#each protocol and always yields one single item to the block, which is a two-element Array of key and value. Normal block parameter binding then takes care of the rest:

def my_method
  yield ['Hello', 'World']
end

my_method {|a| p a }
# ["Hello", "World"]

my_method {|a, b| p a, b }
# "Hello"
# "World"

my_method {|a, b, c| p a, b, c }
# "Hello"
# "World"
# nil

Upvotes: 2

Related Questions