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 thisArray
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
How to Avoid Trailing Empty Items Being Removed When Splitting Strings
Google Plus API Shutdown Today, Which Alternative Can Be Used to Authentication
How to Add an Array to Another Array in Ruby and Not End Up With a Multi-Dimensional Result
How to Do Relative Time in Rails
Ruby: What Does the Comment "Frozen_String_Literal: True" Do
How to Understand the Difference Between Class_Eval() and Instance_Eval()
Paperclip::Errors::Missingrequired
validatorerror With Rails 4
Ruby 1.9.2 and Rails 3 Cannot Open Rails Console
Why Doesn't My Cron Job Work Properly
Using God to Monitor Unicorn - Start Exited with Non-Zero Code = 1
How to Prompt for a Sudo Password Using Ruby
How to Wait for Process to Finish Using Io.Popen
What's the Precedence of Ruby'S Method Call