Passing Multiple Code Blocks as Arguments in Ruby

Passing multiple code blocks as arguments in Ruby

You can't pass multiple blocks, per se, but you can pass multiple procs or lambdas:

Using 1.9 syntax:

opportunity ->{ @some_array.empty? }, ->{ @some_other_array.empty? }

and in the method itself:

def opportunity(lambda1, lambda2)
if lambda1.()
@opportunities += 1
end
if lambda2.()
@performances += 1
end
end

How to pass multiple blocks to method in ruby?

You can use Proc:

def xyz(x, a, &b)
puts x
a.call
b.call
end

xyz(3, Proc.new { puts 'foo' }) { puts 'bar' }

# or simpler

xyz(3, proc { puts 'foo' }) { puts 'bar' }

rails/ruby, passing multiple blocks as arguments

Maybe this (2 Proc used)?

Definition:

def collapsible_content(proc1, proc2)
content_tag(:div, some_options) do
content_tag(:div, some_other_options) do
concat button_tag(proc1.call)
concat hidden_content(proc2.call)
end
end
end

def hidden_content(proc)
content_tag(:div, class: "collapsible-content-body") do
content_tag(:div, proc.call)
end
end

Usage:

<%= collapsible_content(Proc.new{ page_heading(venue.title) }, Proc.new{ venues_facility_opening_times(venue) }) %>

Thanks to this post: Passing multiple code blocks as arguments in Ruby

Passing multiple arguments to a block

sum is the accumulator object, for example the following code:

(1..10).inject(0) do |sum, num| #sum is initialized to 0 and passed in as the accumulator
sum + num #since sum is the accumulator, the result of this addition is stored in sum
end

The above code is the same as:

sum = 0
(1..10).each do
|num|
sum = sum + num
end

You can give the accumulator object any valid variable name, of course better with a meaningful name in the context.

Passing multiple arguments to send

Ruby has a splat operator, the unary prefix * operator that can be used in two places with dual meanings:

  • in a parameter list in a method, block, or lambda definition, it means "package all remaining arguments into an Array and bind it to this parameter"
  • in an argument list of a message send or a yield as well as the left-hand side of an assignment expression, it means "explode this Array into its individual elements as if they had been written individually in its place"

So, for example:

foo(*some_array)

is equivalent to

foo(some_array[0], some_array[1], some_array[2], …, some_array[some_array.size])

So, in your case, all you need to do is

send(*ARGV)

Note, that this obviously allows anyone who can manipulate ARGV to execute any arbitrary Ruby code, including but not limited to, erasing the hard disk, or launching the proverbial nuclear missiles. But, your original code has that same flaw. You really should perform validation here, but that is orthogonal to your question.

Ruby block taking array or multiple parameters

Ruby's block mechanics have a quirk to them, that is if you're iterating over something that contains arrays you can expand them out into different variables:

[ %w[ a b ], %w[ c d ] ].each do |a, b|
puts 'a=%s b=%s' % [ a, b ]
end

This pattern is very useful when using Hash#each and you want to break out the key and value parts of the pair: each { |k,v| ... } is very common in Ruby code.

If your block takes more than one argument and the element being iterated is an array then it switches how the arguments are interpreted. You can always force-expand:

[ %w[ a b ], %w[ c d ] ].each do |(a, b)|
puts 'a=%s b=%s' % [ a, b ]
end

That's useful for cases where things are more complex:

[ %w[ a b ], %w[ c d ] ].each_with_index do |(a, b), i|
puts 'a=%s b=%s @ %d' % [ a, b, i ]
end

Since in this case it's iterating over an array and another element that's tacked on, so each item is actually a tuple of the form %w[ a b ], 0 internally, which will be converted to an array if your block only accepts one argument.

This is much the same principle you can use when defining variables:

a, b = %w[ a b ]
a
# => 'a'
b
# => 'b'

That actually assigns independent values to a and b. Contrast with:

a, b = [ %w[ a b ] ]
a
# => [ 'a', 'b' ]
b
# => nil

How do Ruby multiple code blocks work in conjunction/when chained?

You can interpret the expression via these equivalent substitutions:

# orig
arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }

# same as
pairs = arr.product(arr)
pairs.reject { |a,b| a == b }.any? { |a,b| a + b == n }

# same as
pairs = arr.product(arr)
different_pairs = pairs.reject { |a,b| a == b }
different_pairs.any? { |a,b| a + b == n }

Each block is an argument for the respective method -- one for reject, and one for any?. They are evaluated in order, and are not combined. The parts that make up the expression can be wrapped in parenthesis to show this:

((arr.product(arr)).reject { |a,b| a == b }).any? { |a,b| a + b == n }

# broken up lines:
(
(
arr.product(arr) # pairs
).reject { |a,b| a == b } # different_pairs
).any? { |a,b| a + b == n }

Blocks in Ruby Are Method Arguments

Blocks in Ruby are first-class syntax structures for passing closures as arguments to methods. If you're more familiar with object-oriented concepts than functional ones, here is an example of an object (kind of) acting as a closure:

class MultiplyPairStrategy
def perform(a, b)
a * b
end
end

def convert_using_strategy(pairs, strategy)
new_array = []
for pair in pairs do
new_array << strategy.perform(*pair)
end
new_array
end

pairs = [
[2, 3],
[5, 4],
]

multiply_pair = MultiplyPairStrategy.new
convert_using_strategy(pairs, multiply_pair) # => [6, 20]

Which is the same as:

multiply_pair = Proc.new { |a, b| a * b }
pairs.map(&multiply_pair)

Which is the same as the most idiomatic:

pairs.map { |a, b| a * b }

Is it possible to pass more than one block to a method in Ruby?

You can't pass multiple blocks in that way, but you can pass multiple proc or lambda objects:

irb(main):005:0> def foo(b1, b2)
irb(main):006:1> b1.call
irb(main):007:1> b2.call
irb(main):008:1> end
=> nil
irb(main):009:0> foo(Proc.new {puts 'one'}, Proc.new {puts 'two'})
one
two
=> nil
irb(main):010:0>

Passing Range#step multiple arguments

Multiplication doesn't return a Range, so that isn't Range#step -- it's Numeric#step, which takes an endpoint and a step amount.



Related Topics



Leave a reply



Submit