Pass parameters to passed-in block in Ruby - ruby

I want to pass a block to a function, and then call that block with some additional parameters as follows:
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map &block # Need some way to pass in 'x' here
end
def a_usage_that_works
foo do |value|
value
end
end
def a_usage_that_doesnt_work
foo do |value, x|
x # How do I pass in x?
end
end
# rspec to demonstrate problem / required result
describe "spike" do
it "works" do
a_usage_that_works.should == [1,2,3]
end
it "doesn't work" do
a_usage_that_doesnt_work.should == [7, 7, 7]
end
end
How can I pass in the additional parameter to the block?

Create another block and call first one from it.
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map {|elem| block.call(elem, x)}
end

You pass to the block by yielding to it.
def foo(&block)
some_array = [1,2,3]
x = 7
some_array.map{|el| yield el, x}
end
p foo{|p1, p2| p2} #=>[7,7,7]
p foo{|p1, p2| p1} #=>[1,2,3]

You can use a higher-order function to generate a simplified function:
Let's assume that the block we pass to foo will accept value, x.
Naive strategy, using an inline-defined x:
def foo(&block)
some_array = (1..3).to_a
x = 7
simple_func = proc {|value| block.call(value, x) }
result = some_array.map &simple_func
end
Strategy using separation of concerns:
def get_simple_func(block)
# This assumes x won't change per iteration.
# If it can change, you can move the calculation inside the proc.
# Moving it inside also allows the calculation to depend on "value", in case you want that.
x = complex_calculation_for_x()
proc {|value| block.call(value, x) }
end
def foo(&block)
some_array = (1..3).to_a
simple_func = get_simple_func(block)
result = some_array.map &simple_func
end
Obviously you shouldn't use this when x is a literal value because it would be over-engineering. But as the calculation of x becomes more complex, separating it out makes the code more readable. Also, foo can focus on the specific task of applying the function to some_array.

Related

How do I make a function that accepts an anonymous function using 'do' keyword syntax?

When using array.each you can specify the function in two forms:
Curly Braces:
a = [1,2,3]
a.each { |x| puts x * x }
Output:
1
4
9
=> [1, 2, 3]
'do' Syntax:
a = [1,2,3]
a.each do |x|
puts (x * x)
end
Output:
1
4
9
=> [1, 2, 3]
Question:
How can I replicate the 'do' syntax style with my own custom function? The closest to the curly brace style I can get is:
What I've tried:
def PutWith2Arg(proc)
puts proc.call(2)
end
PutWith2Arg(Proc.new { |x| x + 100 })
Output:
102
=> nil
The do |foo| … end and { |foo| … } syntaxes are equivalent. These are 'blocks' in Ruby, and any method can get them. To call them you need to either:
def my_method # No need to declare that the method will get a block
yield(42) if block_given? # Pass 42 to the block, if supplied
end
my_method do |n|
puts "#{n} times 2 equals #{n*2}"
end
#=> "42 times 2 equals 84"
my_method{ |n| puts "#{n} times 2 equals #{n*2}" }
#=> "42 times 2 equals 84"
my_method # does nothing because no block was passed
or, for more sophisticated uses:
def my_method( &blk ) # convert the passed block to a Proc named blk
blk.call( 42 ) if blk
end
# Same results when you call my_method, with or without a block
The latter style is useful when you need to pass the block on to another method. If you have a Proc or Lambda referenced by a variable, you can pass it to a method as the block for that method using the & syntax:
def my_method( &blk ) # convert the passed block to a Proc named blk
[1,2,3].each( &blk ) # invoke 'each' using the same block passed to me
end
my_method{ |x| p x=>x**2 }
#=> {1=>1}
#=> {2=>4}
#=> {3=>9}
For more details, this webpage is fairly instructive.

Is there an abstraction for the declare-update-return pattern?

When writing iterative code with mutation in ruby, I often find myself following this pattern:
def build_x some_data
x = [] # or x = {}
some_data.each do |data|
x.some_in_place_update! (... data ...)
end
x
end
(x often does not have the same shape as some_data, so a simple map will not do.)
Is there a more idiomatic or better way to write code that follows this pattern?
[edit] A real example:
def to_hierarchy stuff
h = {}
stuff.each do |thing|
path = thing.uri.split("/").drop(4)
sub_h = h
path.each do |segment|
sub_h[segment] ||= {}
sub_h = sub_h[segment]
end
sub_h.merge!(
data: thing.data,
)
end
h
end
This begins with a flat list of things, which have related but distinct uris. It transforms this flat list into a hierarchy, grouping related things that share the same segments of a uri. This follows the pattern I described: initialize h, loop over some data and mutate h along the way, and then spit out h at the end.
[edit2] Another related example
def count_data obj
i = if obj[:data] then 1 else 0
obj.each do |k, v|
i += count_statements v unless :data == k
end
i
end
Your to_hierarchy example could be done with each_with_object:
def to_hierarchy stuff
stuff.each_with_object({}) do |thing, h|
#...
end
end
each_with_object passes the extra object to the block and returns that object when the iteration is done.
If you're more of a traditionalist, you could use inject:
def to_hierarchy stuff
stuff.inject({}) do |h, thing|
#...
h
end
end
Note the block argument order change and that the block has to return h so that inject can feed it back into the next block invocation.
Your general example could be written as:
def build_x some_data
some_data.each_with_object([]) do |data, x|
x.some_in_place_update! (... data ...)
end
end
or:
def build_x some_data
some_data.inject({}) do |x, data|
x.some_in_place_update! (... data ...)
x
end
end
Ah! You want each_with_object. Like this
def to_hierarchy stuff
stuff.each_with_object({}) do |thing, h|
path = thing.uri.split("/").drop(4)
sub_h = h
path.each do |segment|
sub_h[segment] ||= {}
sub_h = sub_h[segment]
end
sub_h.merge!(
data: thing.data,
)
end
end

Ruby : Rubeque - difficult with *n or n

I'm doing http://www.rubeque.com/problems/queue-continuum/solutions/51a26923ba804b00020000df and I spent a while there. I can't realize why this code doesn't pass
def initialize(queue)
#q = queue
end
def pop(n=1)
#q.shift(n)
end
def push(arr)
arr.each { |x|
#q.push(x)
}
return true
end
def to_a
#q
end
but this works perfectly.
def initialize(queue)
#q = queue
end
def pop(*n)
#q.shift(*n)
end
def push(arr)
#q.push(*arr)
return true
end
def to_a
#q
end
i'm totally confused about
def pop(*n)
#q.shift(*n)
end
and
def push(arr)
#q.push(*arr)
end
why should I take (arr) as array and than change it into... *arr which is Array of array? I'm confused, please help!
The splat works in two ways.
When receiving arguments, it combines arguments into an array.
def foo *args; args end
foo(1) # => [1]
foo(1, 2, 3) # => [1, 2, 3]
When giving arguments, it decomposes an array into arguments.
def bar x, y, z; y end
bar(*[1, 2, 3]) # => 2
def baz x; x end
baz(1) # => [1]
baz(1, 2, 3) # => Error
The *arr you are wondering is the latter case. It is not an object like [1, 2, 3] (hence, not an array of arrays). It is a part of arguments (like 1, 2, 3) passed to a method.
There are other uses of splats (as in array literals, case statements, etc.), but their function is either of the two uses above.

Are there something like Python generators in Ruby?

I am new to Ruby, is there a way to yield values from Ruby functions? If yes, how? If not, what are my options to write lazy code?
Ruby's yield keyword is something very different from the Python keyword with the same name, so don't be confused by it. Ruby's yield keyword is syntactic sugar for calling a block associated with a method.
The closest equivalent is Ruby's Enumerator class. For example, the equivalent of the Python:
def eternal_sequence():
i = 0
while True:
yield i
i += 1
is this:
def eternal_sequence
Enumerator.new do |enum|
i = 0
while true
enum.yield i # <- Notice that this is the yield method of the enumerator, not the yield keyword
i +=1
end
end
end
You can also create Enumerators for existing enumeration methods with enum_for. For example, ('a'..'z').enum_for(:each_with_index) gives you an enumerator of the lowercase letters along with their place in the alphabet. You get this for free with the standard Enumerable methods like each_with_index in 1.9, so you can just write ('a'..'z').each_with_index to get the enumerator.
I've seen Fibers used in that way, look at an example from this article:
fib = Fiber.new do
x, y = 0, 1
loop do
Fiber.yield y
x,y = y,x+y
end
end
20.times { puts fib.resume }
If you are looking to lazily generate values, #Chuck's answer is the correct one.
If you are looking to lazily iterate over a collection, Ruby 2.0 introduced the new .lazy enumerator.
range = 1..Float::INFINITY
puts range.map { |x| x+1 }.first(10) # infinite loop
puts range.lazy.map { |x| x+1 }.first(10) # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Ruby supports generators out of the box using Enumerable::Generator:
require 'generator'
# Generator from an Enumerable object
g = Generator.new(['A', 'B', 'C', 'Z'])
while g.next?
puts g.next
end
# Generator from a block
g = Generator.new { |g|
for i in 'A'..'C'
g.yield i
end
g.yield 'Z'
}
# The same result as above
while g.next?
puts g.next
end
https://ruby-doc.org/stdlib-1.8.7/libdoc/generator/rdoc/Generator.html
Class Enumerator and its method next behave similar
https://docs.ruby-lang.org/en/3.1/Enumerator.html#method-i-next
range = 1..Float::INFINITY
enumerator = range.each
puts enumerator.class # => Enumerator
puts enumerator.next # => 1
puts enumerator.next # => 2
puts enumerator.next # => 3

conditional chaining in ruby

Is there a good way to chain methods conditionally in Ruby?
What I want to do functionally is
if a && b && c
my_object.some_method_because_of_a.some_method_because_of_b.some_method_because_of_c
elsif a && b && !c
my_object.some_method_because_of_a.some_method_because_of_b
elsif a && !b && c
my_object.some_method_because_of_a.some_method_because_of_c
etc...
So depending on a number of conditions I want to work out what methods to call in the method chain.
So far my best attempt to do this in a "good way" is to conditionally build the string of methods, and use eval, but surely there is a better, more ruby, way?
You could put your methods into an array and then execute everything in this array
l= []
l << :method_a if a
l << :method_b if b
l << :method_c if c
l.inject(object) { |obj, method| obj.send(method) }
Object#send executes the method with the given name. Enumerable#inject iterates over the array, while giving the block the last returned value and the current array item.
If you want your method to take arguments you could also do it this way
l= []
l << [:method_a, arg_a1, arg_a2] if a
l << [:method_b, arg_b1] if b
l << [:method_c, arg_c1, arg_c2, arg_c3] if c
l.inject(object) { |obj, method_and_args| obj.send(*method_and_args) }
You can use tap:
my_object.tap{|o|o.method_a if a}.tap{|o|o.method_b if b}.tap{|o|o.method_c if c}
Sample class to demonstrate chaining methods that return a copied instance without modifying the caller.
This might be a lib required by your app.
class Foo
attr_accessor :field
def initialize
#field=[]
end
def dup
# Note: objects in #field aren't dup'ed!
super.tap{|e| e.field=e.field.dup }
end
def a
dup.tap{|e| e.field << :a }
end
def b
dup.tap{|e| e.field << :b }
end
def c
dup.tap{|e| e.field << :c }
end
end
monkeypatch: this is what you want to add to your app to enable conditional chaining
class Object
# passes self to block and returns result of block.
# More cumbersome to call than #chain_if, but useful if you want to put
# complex conditions in the block, or call a different method when your cond is false.
def chain_block(&block)
yield self
end
# passes self to block
# bool:
# if false, returns caller without executing block.
# if true, return result of block.
# Useful if your condition is simple, and you want to merely pass along the previous caller in the chain if false.
def chain_if(bool, &block)
bool ? yield(self) : self
end
end
Sample usage
# sample usage: chain_block
>> cond_a, cond_b, cond_c = true, false, true
>> f.chain_block{|e| cond_a ? e.a : e }.chain_block{|e| cond_b ? e.b : e }.chain_block{|e| cond_c ? e.c : e }
=> #<Foo:0x007fe71027ab60 #field=[:a, :c]>
# sample usage: chain_if
>> cond_a, cond_b, cond_c = false, true, false
>> f.chain_if(cond_a, &:a).chain_if(cond_b, &:b).chain_if(cond_c, &:c)
=> #<Foo:0x007fe7106a7e90 #field=[:b]>
# The chain_if call can also allow args
>> obj.chain_if(cond) {|e| e.argified_method(args) }
Although the inject method is perfectly valid, that kind of Enumerable use does confuse people and suffers from the limitation of not being able to pass arbitrary parameters.
A pattern like this may be better for this application:
object = my_object
if (a)
object = object.method_a(:arg_a)
end
if (b)
object = object.method_b
end
if (c)
object = object.method_c('arg_c1', 'arg_c2')
end
I've found this to be useful when using named scopes. For instance:
scope = Person
if (params[:filter_by_age])
scope = scope.in_age_group(params[:filter_by_age])
end
if (params[:country])
scope = scope.in_country(params[:country])
end
# Usually a will_paginate-type call is made here, too
#people = scope.all
Use #yield_self or, since Ruby 2.6, #then!
my_object.
then{ |o| a ? o.some_method_because_of_a : o }.
then{ |o| b ? o.some_method_because_of_b : o }.
then{ |o| c ? o.some_method_because_of_c : o }
Here's a more functional programming way.
Use break in order to get tap() to return the result. (tap is in only in rails as is mentioned in the other answer)
'hey'.tap{ |x| x + " what's" if true }
.tap{ |x| x + "noooooo" if false }
.tap{ |x| x + ' up' if true }
# => "hey"
'hey'.tap{ |x| break x + " what's" if true }
.tap{ |x| break x + "noooooo" if false }
.tap{ |x| break x + ' up' if true }
# => "hey what's up"
Maybe your situation is more complicated than this, but why not:
my_object.method_a if a
my_object.method_b if b
my_object.method_c if c
I use this pattern:
class A
def some_method_because_of_a
...
return self
end
def some_method_because_of_b
...
return self
end
end
a = A.new
a.some_method_because_of_a().some_method_because_of_b()
If you're using Rails, you can use #try. Instead of
foo ? (foo.bar ? foo.bar.baz : nil) : nil
write:
foo.try(:bar).try(:baz)
or, with arguments:
foo.try(:bar, arg: 3).try(:baz)
Not defined in vanilla ruby, but it isn't a lot of code.
What I wouldn't give for CoffeeScript's ?. operator.
I ended up writing the following:
class Object
# A naïve Either implementation.
# Allows for chainable conditions.
# (a -> Bool), Symbol, Symbol, ...Any -> Any
def either(pred, left, right, *args)
cond = case pred
when Symbol
self.send(pred)
when Proc
pred.call
else
pred
end
if cond
self.send right, *args
else
self.send left
end
end
# The up-coming identity method...
def itself
self
end
end
a = []
# => []
a.either(:empty?, :itself, :push, 1)
# => [1]
a.either(:empty?, :itself, :push, 1)
# => [1]
a.either(true, :itself, :push, 2)
# => [1, 2]

Resources