how to pass a Ruby iterator as a parameter? - ruby

I'd like to write a method that yields values in one place and pass it as a parameter to another method that will invoke it with a block. I'm convinced it can be done but somehow I'm not able to find the right syntax.
Here's some sample (non-working) code to illustrate what I'm trying to achieve:
def yielder
yield 1
yield 2
yield 3
end
def user(block)
block.call { |x| puts x }
end
# later...
user(&yielder)
$ ruby x.rb
x.rb:2:in `yielder': no block given (yield) (LocalJumpError)
from x.rb:12:in `<main>'
FWIW, in my real code, yielder and user are in different classes.
Update
Thanks for your answers. As Andrew Grimm mentioned, I want the iterator method to take parameters. My original example left this detail out. This snippet provides an iterator that counts up to a given number. To make it work, I made the inner block explicit. It does what I want, but it's a bit ugly. If anyone can improve on this I'd be very interested in seeing how.
def make_iter(upto)
def iter(upto, block)
(1 .. upto).each do |v|
block.call(v)
end
end
lambda { |block| iter(upto, block) }
end
def user(obj)
obj.call Proc.new { |x| puts x }
end
# later...
user(make_iter(3))

This doesn't use a lambda or unbound method, but it is the simplest way to go...
def f
yield 1
yield 2
end
def g x
send x do |n|
p n
end
end
g :f

When you write &yielder, you're calling yielder and then trying to apply the & (convert-to-Proc) operator on the result. Of course, calling yielder without a block is a no-go. What you want is to get a reference to the method itself. Just change that line to user(method :yielder) and it will work.

I think this might be along the lines of what you want to do:
def yielder
yield 1
yield 2
yield 3
end
def user(meth)
meth.call { |x| puts x }
end
# later...
user( Object.method(:yielder) )
Some related info here: http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html

As it has been pointed out the baseline problem is that when you try to pass a function as a parameter Ruby executes it – as a side effect of parenthesis being optional.
I liked the simplicity of the symbol method that was mentioned before, but I would be afraid of my future self forgetting that one needs to pass the iterator as a symbol to make that work. Being readability a desired feature, you may then wrap your iterator into an object, which you can pass around without fear of having code unexpectedly executed.
Anonymous object as iterator
That is: using an anonymous object with just one fuction as iterator. Pretty immediate to read and understand. But due to the restrictions in the way Ruby handles scope the iterator cannot easily receive parameters: any parameters received in the function iterator are not automatically available within each.
def iterator
def each
yield("Value 1")
yield("Value 2")
yield("Value 3")
end
end
def iterate(my_iterator)
my_iterator.each do |value|
puts value
end
end
iterate iterator
Proc object as iterator
Using a Proc object as iterator lets you easily use any variables passed to the iterator constructor. The dark side: this starts looking weird. Reading the Proc.new block is not immediate for the untrained eye. Also: not being able to use yield makes it a bit uglier IMHO.
def iterator(prefix:)
Proc.new { |&block|
block.call("#{prefix} Value 1")
block.call("#{prefix} Value 2")
block.call("#{prefix} Value 3")
}
end
def iterate(my_iterator)
my_iterator.call do |value|
puts value
end
end
iterate iterator(prefix: 'The')
Lambda as iterator
Ideal if you want to obfuscate your code so hard that no one else besides you can read it.
def iterator(prefix:)
-> (&block) {
block.call("#{prefix} Value 1")
block.call("#{prefix} Value 2")
block.call("#{prefix} Value 3")
}
end
def iterate(my_iterator)
my_iterator.call do |value|
puts value
end
end
iterate iterator(prefix: 'The')
Class as iterator
And finally the good ol' OOP approach. A bit verbose to initialize for my taste, but with little or none surprise effect.
class Iterator
def initialize(prefix:)
#prefix = prefix
end
def each
yield("#{#prefix} Value 1")
yield("#{#prefix} Value 2")
yield("#{#prefix} Value 3")
end
end
def iterate(my_iterator)
my_iterator.each do |value|
puts value
end
end
iterate Iterator.new(prefix: 'The')

Related

In this for/each statement, why do I need to specify an each method using &block in the class of the object I am iterating through?

That title is not the best, so I will explain further here.
I have a Card class and a Deck class, and in Main, I am creating a Deck of Cards and then printing out all the Cards in the Deck. I've made a to_string method for Card (below):
def to_string
puts "#{self.rank} of #{self.suit}"
end
and then used that and a for/each statement in Main to print all the Cards in Deck:
for card in deck
puts card.to_string
end
But I received an error saying that there was an "undefined method 'each' for #Deck: (NoMethodError). I did some searching and found that the solution was to add this method to my Deck class:
def each(&block)
#deck.each(&block)
end
I do understand (or, I think I do) how .each works, as I used it in creating all the Card objects for my Deck--it will go through an array and grab each array item in turn. So it made sense that for card in deck is basically deck.each. But I'm not really sure what &block is doing here. I did some research on what blocks are (to my understanding, basically "anonymous code"--so for example, the instructions inside of a array.each statement. A method that isn't a formally written method) but I still don't know what &block itself does.
Every method in Ruby can (but doesn't have to) take an optional block argument, denoted with an ampersand & before the argument name. This argument is given the value of an explicit block when the method is called.
We can see this behavior explicitly by writing a function which simply returns its block.
def foo(&block)
p block
end
Then if we run
> foo() # Note: No block argument
nil
> foo { 1 } # Note: Block provided
#<Proc:0x...>
So if you pass an explicit block to a method, it gets passed as a Proc object to the method. This is how .each works. The line
[1, 2, 3].each { |x| puts x }
calls each on [1, 2, 3], passing a block argument whose call method runs puts x. You can think of it as similar to
[1, 2, 3].each(->(x) { puts x })
Here, we pass a regular argument which happens to be a lambda. This is not equivalent to the above (block arguments are treated as special), but we could theoretically have implemented each either way; the block syntax is just more convenient.
As you've correctly surmised, for loops desugar to something kind of like .each. Roughly speaking, the following two are equivalent.
for i in [1, 2, 3]
foo i
end
 
i = nil
[1, 2, 3].each do |i|
foo i
end
Note that for loops actually go to additional effort to ensure that the variable does escape the loop scope, whereas using .each directly produces a local-only variable that doesn't escape. For this reason, .each is generally considered more idiomatic in Ruby anyway, and most Ruby code shies away from explicit for loops in general. (IMO .each is also prettier and more consistent with all of the other aspects of Ruby syntax)
I'm not sure I succeed to clarify this properly, just a try...
Actually for item in deck is actually syntax sugar for those, that previously learned some procedural language, like Pascal or C, and is equivalent for method call: deck.each { |item| ... }. The part in curly brackets is a block or anynomous function. So, your code:
for card in deck
puts card
Is actually translated to call of each on deck object:
deck.each { |card| puts card }
What actually does this method - you define it for collection of something and it should pass its item one after another to given block. And inside block we can use those item as a variable with name we like (card in example).
You can actually ignore item in block, for example:
deck.each { puts "Hello" }
And if your deck has 52 cards, you'll see 52 times "Hello".
What is most interesting, is that having defined only this each method you actually can have a bunch of others, like count, min, max, map, etc. For this, you only need to include mixin Enumerable in your class.
Like this:
class Deck
include Enumerable
def each(&block)
#deck.each(&block)
And now, if you call deck.count it will actually return 52, or whatever is the number of cards, you've put there.
How it works: it actually executes something like:
c = 0
deck.each { c = c + 1 }
c
Well, hope that helps...
why do I need to specify an each method using &block in the class of the object I am iterating through?
You don't have to use the &block syntax.
each is supposed to yield each element to the given block, e.g.:
class Foo
def each
yield 1
yield 2
yield 3
end
end
foo = Foo.new
for i in foo
puts i
end
# or more idiomatic:
foo.each do |i|
puts i
end
Since you rarely yield hard-coded values, there's usually some kind of loop within each, e.g.:
class Foo
def each
1.upto(3) do |i|
yield i
end
end
end
In your case, the loop is based on #deck.each, so you could write:
def each
#deck.each do |card|
yield card
end
end
In order to make each more useful, it should also return an enumerator if no block is given:
def each
return enum_for(:each) unless block_given?
#deck.each do |card|
yield card
end
end
So what about that &block syntax?
If you read the documentation for Array#each you might notice that it already does all these things – it yields the elements to the block and returns an enumerator if no block is given. So you could avoid writing the above code just by passing the block that was given to your each along to Array#each.
But how can we refer to the given block? That's what the &block syntax is for – it assigns the block to a variable block which can be passed as a block argument to another method using the same &block syntax:
def each(&block)
#deck.each(&block)
end
Some considerations:
you should avoid for and prefer each-style loops
to_string should just return the string, not print it. You can omit self and you should call it to_s:
def to_s
"#{rank} of #{suit}"
end
which allows you to directly puts your card:
deck.each do |card|
puts card
end
it might be cleaner to call the method each_card

Ruby - Is &prc different than &block?

I'm writing a simple method that adds num to the return value of the block that is passed to it and I noticed that &block and &prc both work. I know that a proc is an object and can be assigned to a variable which could be handy. Is that the only difference though? Is there any difference between these two when it comes to performance, convention, or versatility? Is it ever better to use &block instead of &prc?
def adder(num = 1, &block)
yield + num
end
vs.
def adder(num = 1, &prc)
yield + num
end
Is there any difference between these two when it comes to
performance, convention, or versatility?
There is no difference between these, you able to name it as you want, it's just a name. Some devs call it &blk some &block or &b or &foo ...
>> def foo &foo
>> yield
>> end
=> :foo
>> foo do
?> puts '1'
>> end
1
Strictly saying & is an operator which you can apply to any object, and it will take care of converting that object to a Proc by calling to_proc().
>> def bar(&some_proc)
>> some_proc
>> end
=> :bar
>> p = bar { puts 'Call proc' }
=> #<Proc:0x005601e6d69c80#(irb):4>
>> p.call
=> Call proc
>> p.class
=> Proc
Only the one thing is important, the name should be informative.
Line any argument to your method the name is largely subjective. Typically you'll see &block used if only by convention, but the name itself can be anything you want so long as it's a valid variable name.
In your example you're declaring a block name but not actually using the name. Keep in mind that any Ruby method can be given a block, there's no way to restrict this, but it's up to the method itself to use the block if it wants. That block can be called zero or more times either immediately or at some point in the future. Giving the block to the method surrenders control, so be sure to read the documentation on any given method carefully. There can be surprises.
If you need to chain through a block, declare it with a name:
def passes_through(&block)
[ 1, 2, 3, 4 ].each(&block)
end
If you are going to yield on the block there's no need here:
def direct_call
[ 1, 2, 3, 4 ].each do |n|
yield n
end
end
If you're going to preserve the call and use it later, that's also a case for naming it:
def preserved_call(&block)
#callback = block
end
def make_callback
#callback and #callback.call
end
Any method can check if a block was supplied:
def tests_for_block
if (block_given?)
yield 'value'
else
'value'
end
end
There's a small but measurable cost to capturing a block by declaring it in the method signature, a lot of computation has to be done to properly capture all the variables that might be used in a closure situation. In performance sensitive code you'll want to avoid this.
You can dynamically create a block:
def captures_conditionally
if (block_given?)
#callback = Proc.new
end
end
The Proc.new method will assume control over whatever block has been supplied to the method if one has been.
in your example, there is not a difference between &block and &prc, because in each case you are just passing a block to be call into the method.
Block and proc are similar in that they are both blocks of code.
[1,2,3].each {|x| puts x }
everything within the {} is the block.
A proc is just a block of code that you can name and can be called at a later time.
put_element = Proc.new {|x| puts x}
then you use put_element as an argument in your function.

Ruby - Singleton module with each. Returning a value gives an Enumerator. How can I get the value instead?

Example code:
module Creatures
class << self
def to_h
{
squirtle: {full_name: 'Squirtle T. Turtle'},
pikachu: {full_name: 'Pikachu B. Pikachu'}
}
end
def keys
to_h.keys
end
def collect
to_h.keys.collect
end
def each
to_h.keys.each
end
end
end
module CompanionHelper
def get_companion_creature_experience(companion_data)
Creatures.each do |creature|
return companion_data[creature]["#{creature}_experience".to_sym] if companion_data.has_key?(creature)
end
end
end
include CompanionHelper
companion_data = {squirtle: {squirtle_experience: 8000}}
get_companion_creature_experience(companion_data)
Forgive me if the example is contrived. The original code is from the insurance world but I can't copy and paste it :)
The crux of the problem is I want to use Creatures.each in another module, pass it a block, and have it work just like Creatures.keys.each would work (i.e. w/ the given example companion data I get 8000 for get_companion_creature_experience(companion_data).
Currently I get Enumerator instead.
Problem is that to_h.keys.each returns Enumerator which does not expect any arguments. Pass a block inside each since you want to use it:
def each &block
to_h.keys.each &block
end
Or you can yield it:
def each
to_h.keys.each do |k|
yield k
end
end

Understanding the control flow using `each` and `yield`

I came across this code:
class RandomSequence
def initialize(limit,num)
#limit,#num = limit,num
end
def each
#num.times { yield (rand * #limit).floor }
end
end
i = -1
RandomSequence.new(10,4).each do |num|
i = num if i < num
end
Is it the case that the each method is called only once and will compute four different values, and then for each of those values we execute code block between do and end? Is my understanding of control flow correct?
Your understanding is close. The random number will be generated, then a block yielded, then another generated, etc 4 times. You can verify this easily by adding puts statements into you blocks to see when they are executed.
class RandomSequence
def initialize(limit,num)
#limit,#num = limit,num
end
def each
puts "in each"
#num.times { yield (rand.tap {|x| puts "Generated #{x}" } * #limit).floor }
end
end
i = -1
RandomSequence.new(10,4).each do |num|
puts "in block"
i = num if i < num
end
Outputs
in each
Generated 0.6724385316643955
in block
Generated 0.8906983274750662
in block
Generated 0.49038868732214036
in block
Generated 0.38100454011243456
in block
The each method on the RandomSequence class is called once. In it #num.times which creates an Enumerator. The Enumerator is iterated over and the block with the yield statement is called (with the argument to it ignored).
The yield statement calls the block that's passed to the each method passing the value of (rand * #limit).floor. In your code the block is not bound to a variable, i.e you could get a reference to the block by doing:
def each(&block)
#... do stuff with block, e.g. block.call("some args")
end
which can be useful at times.
A bit off topic, but one thing I found scary with Ruby starting out is that a return statement returns the flow of execution from where it was defined.
def create_proc
puts "Creating proc"
Proc.new do
puts "In proc!"
return "some value" # notice the explicit return
end
end
def do_stuff
my_proc = create_proc
my_proc.call # This will cause a runtime error
end
If the explicit return is removed everything works there is no error... Lesson being that in ruby you should probably avoid using explicit returns.

Ruby: Yield within enumerable

I'd like to be able to yield within an enumerable block, in order to create some boilerplate benchmarking code.
Basically I'd like to do something this (simplified):
def iterator( enumerable, &block )
iterations = enumerable.size
counter = 0
enumerable.each do |item|
counter +=1
puts "Iterating #{counter}/#{iterations}..."
yield
end
end
Then I'd like to be able to use this method in order to wrap this boilerplate benchmarking code around a block I would be iterating, so that I could call something like:
# assuming foo is an enumerable collection of objects
iterator foo do
item.slow_method
item.mundane_method
item.save
end
... and when this code executed I would get the following log output:
Iterating 1/1234...
Iterating 2/1234...
Iterating 3/1234...
It seems like this kind of thing must be possible, but I haven't been able to figure out the syntax, nor what such a thing is called (in order to look it up).
The problem is I need to wrap boilerplate both OUTSIDE the enumerable object that is going to iterate, and also INSIDE the iteration block. I can pass an enumerable object in just fine, but I can't seem to call methods on the iterated objects from within the block I pass in.
I hope this explanation makes sense, I'm having a hard time describing it. Please leave comments if you need clarification on anything, I'll try to explain better.
Ruby's yield statement can take arguments. You would want to say
yield item
This passes the "current" item to your "outside" block.
Hope I understood the question correctly.
ADDENDUM
And here is the code to show it in action:
class Item
def initialize(id)
#id = id
end
def slow_method()
puts "slow ##id"
end
def mundane_method()
puts "mundane ##id"
end
def save()
puts "save ##id"
end
end
foo = [Item.new(100), Item.new(200), Item.new(300)]
def iterator(enumerable, &block)
iterations = enumerable.size
counter = 0
enumerable.each do |item|
counter +=1
puts "Iterating #{counter}/#{iterations}..."
yield item
end
end
iterator foo do |item|
item.slow_method
item.mundane_method
item.save
end

Resources