I need some help understanding what's going on here. It's a block inside of a method. Basically I get everything here except the call in the if statement wasABlock_nowAProc.call. This is not defined here, so what is it calling?
class Array
def eachEven(&wasABlock_nowAProc)
isEven = true # We start with "true" because arrays start with 0, which is even.
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
isEven = (not isEven) # Toggle from even to odd, or odd to even.
end
end
end
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
puts oddBall.to_s+' is NOT an even number!'
end
def eachEven(&wasABlock_nowAProc) declares that the eachEven method accepts a block, which is the do ... end stuff from your two examples. It is then accessible within the method as a .callable Proc/Lambda object with the name wasABlock_nowAProc.
wasABlock_nowAProc.call object basically invokes the attached block from within the method and passes it one argument, object.
Do a google search for "ruby block to proc" and any of the first results should give you a thorough explanation.
Basically, when you define a method parameter with an & prefix (as in def eachEven(&wasABlock_nowAProc)), it tells Ruby that this method is expecting to receive a Proc object as an argument. In the method body you can then do stuff with Proc, such as use the #call method to run it or pass it on to another method.
Now, it's rare for Ruby programmer to manually create Proc objects. It's much more common to just use a block (less typing, easier to read, etc). If you try to pass a block to method that requires a Proc, well, Ruby handles that just fine. It magically converts the block to a Proc and uses that.
In this particular example, the only reason I can see to define the &wasABlock_nowAProc parameter is to tell Ruby to raise an error if the method is called with a block. You could remove the parameter and replace the #call line with yield to achieve the same functionality.
Related
New to Ruby so apologies in advance if this is a dumb question. I have a need to supply a value to a block but would like not to update everywhere called.
Let's say I have the following block:
{ base.call_my_test }
It get's passed to a function where I'd like to wrap it in another block but supply that other blocks value to it such as:
def test(&block)
MyTest.with_base_object do |base|
#neither of these work
block.instance_variable_set(:#base, base) # Doesn't work
block.define_singleton_method(:hi) do
return base
end
block.call <---- Is it possible to define base here?
end
end
In the above example, is it possible to define base on the block without passing as an argument? I tried instance_variable_set as well as define_singleton_method but I can't seem to get anything to be defined as it always says base is undefined.
Not sure if this is even possible but figured I'd ask.
First, blocks in Ruby are non-rigid Proc objects. That means that you can pass extra arguments, and anyone who doesn't expect arguments will silently ignore them.
def test(&block)
base = Object.new
block.call(base)
end
test { |x| puts "Works with an object #{x}." }
test { puts "Works without an object as well!" }
So if you control the block where you need base to be defined, then you can simply add the argument. Any other uses of the test function will simply ignore the extra argument, even if they're not declared to take one.
But this is assuming you control any of the blocks at all. It sounds like you have some blocks somewhere out there that you can't change, and you automagically want to inject the name base into their scope. You can change the class instance that a block is being invoked for by passing the block to instance_eval.
Buyer beware: This will completely change self. If the block in question tries to view self or call any other methods on the object (it thinks) it's enclosed in, it will fail.
class HasBase
attr_reader :base
def initialize(base)
#base = base
end
end
def test(&block)
base = Object.new
HasBase.new(base).instance_eval(&block)
end
test { puts "I can see my #{base} from here!" }
Depending on your specific needs, you can start augmenting this to work with whatever your callers need. For instance, you can write method_missing to fall back to the proc's original binding. But that's getting into some deep magic, and you probably don't want to play with that footgun in production for very long.
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
Here is an expectation that utilizes a custom RSpec matcher, yield_variables:
specify { expect{ |p| [3,4,5].my_each(&p) }.to yield_variables [3,4,5] }
my yield_variables matcher's matches? method utilizes a custom class called Probe (Probe is a stripped down version of RSpec's yield probe):
...
def matches? block
ap Probe.probe block
# note i am inspecting what is returned by Probe.probe with ap
end
...
# Probe class is what all my questions are about!
class Probe
attr_accessor :yielded_args
def initialize
self.yielded_args = []
end
def self.probe(block)
probe = new
block.call(probe)
probe.yielded_args
end
def to_proc
Proc.new { |*args| yielded_args << args }
end
end
Now my ap inside matches? reports this: [3,4,5] That is what I expect. However, I have no idea how the Probe class works!!
Problem 1) the matches? block
Normally, the argument we pass to matches? is what we expect the subject to return. i.e, I expect [3,4,5] to be passed into block.
Instead, |p| [3,4,5].my_each(&p) is passed into block, as a proc. Why is this?
Problem 2) block.call(probe)
I'm a bit shakey on procs so please explain slowly. But basically, here we take a new instance of my Probe class and 'send' the block to it, as an argument. That's how I'd explain it to the best of my abilities, but I might have it totally wrong so please explain slowly.
Problem 3) How is to_proc called?
How on earth is .to_proc called automatically? I believe it's called automatically by block.call(probe). Is to_proc an automatically called method like initialize? Is it automatically called whenever the class is sent to a proc? (Btw, the phrase the class is sent to a proc doesn't even make 100% sense to me - please explain. The block isn't passed into the class as an argument anymore. Or if the block is passed as an argument the block.call syntax feels really weird and backwards)
Problem 4) to_proc
How does to_proc have access to the expectation's subject i.e. |p| [3,4,5].my_each(&p) ? How is Proc.new 's *args automatically populated with every single possible yield argument, even though I've only passed in |p| ? How does Proc.new loop along with my my_each, incrementally placing all my args in an array? How does Proc.new have any knowledge of the subject |p| [3,4,5].my_each(&p)? How?? Explain please, and thanks.
Block based marchers work a little differently to other matchers. Typically you want to do something that would not be possible if the expression you were interested in was evaluated and the result passed to you.
For example the raises_error matcher wants to execute the block itself to see that the correct exception is raised and the change matcher wants to evaluate some other expression before and after to see if it changes in the specified way. This is why you are passed a block rather than the value.
The block you are passing to expect takes 1 argument and uses this as the block in the call to my_each, so when your Probe.probe method calls the block it has to pass something as the value. You've phrased as "sending the block to the probe instance" but it is the other way around: the block is called using probe as its argument.
The block executes and calls my_each. Inside here p is the instance of Probe. Prefixing an argument with a & tells ruby that this argument should be used as the method's block (the method being my_each). If the argument is not already a proc ruby calls to_proc on it. This is how Probe#to_proc is called
Assuming that my_each behaves in a similar way to normal each it will call its block (ie the return value of to_proc) once for each of the values in the array.
Normally your matcher would then compare the return value from Probe.probe to the actual value.
I am working on Ruby Koans about_message_passing.rb and got the code working for method_missing as follows:
def method_missing(method_name, *args, &block)
#messages << method_name
#object.__send__(method_name, *args, &block)
end
This code seems to work, but I do not quite understand why the splat in needed in *args and the & is needed with the block.
If I were defining a method, I understand that the * and & are used to denote an array argument and block argument respectively, but what does it mean when they are used with the send method to invoke a method on an object?
I'll take these one at a time. take method_missing out of this completely, since it just makes what's going on confusing. It's actually completely unrelated to that.
The splat * does 2 things. In the arguments of a method definition, it soaks up multiple arguments into an array. When used in method invocation it splats out an array into individual arguments. Using both allows you to forward any number of arguments to another method.
def foo(*args)
bar(*args)
end
def bar(a, b, c)
puts a
puts b
puts c
end
foo(1,2,3) # prints 1, 2 and then 3
Since you are basically forwarding all arguments, this is the same pattern.
The & is for the block argument. There can be exactly one of these per method invocation, it's the block that hangs off the end. It's a special argument, in that it doesn't go in the arguments directly. You can capture the block to a variable by capturing add &someblock as the last argument in a method definition.
Then you can pass a block in a method invocation using the same syntax.
def foo(&block)
bar(&block)
end
def bar
yield
end
foo { puts 'hello' } # prints hello
This allows you pass the hanging block to another method, without invoking it. It's not always required because you usually just use yield to execute whatever block was passed. But if you want to do something besides just execute it, you need to capture a reference to the block itself.
So if you combine these 2 things, you get the ultimate method forwarder. You capture all of any number of arguments, and any block that was hanging off the end, and send those to another method.
# forwards everything to the method `bar`
def foo(*args, &block)
bar(*args, &block)
end
Lastly, send is just a method. It expects a name of a method, followed by any number of arguments (not an array), and can optionally handle a hanging block.
In other words:
foo.send methodName, *args, &block
The splat in the method definition means "take all unmatched arguments and put them in an array" (in ruby 1.8 this was always the last arguments, but in 1.9 splats can occur in the middle).
Using it in a method call is the reverse: it means take this array and use its contents as the arguments
foo(a,b) #call foo with 2 arguments: a and b
foo([a,b]) #call foo with a single array argument
foo(*[a,b]) # call foo with 2 arguments: a and b
& is similar: in a method definition it captures the block and turns it into a proc, but in a method call it turns a proc (or proc like object - anything responding to to_proc will do) into the block for that method
You need both of these for method_missing because (in general) you want to pass along all the arguments and the block from the original method call.
To my knowledge, anytime you pass a block directly, it is with the syntax &block_name.
Also, the method signature for Object#send takes endless arguments, not an array. So by passing the splatted values *args, it is the same as if you had passed the comma-delimited args.
Presenting the Idiom
I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:
module Foo
class Bar
def baz
end
end
end
Foo.constants.map(&Foo.method(:const_get)).grep(Class)
=> [Foo::Bar]
However, I don't fully understand the idiom in use here. In particular, I don't understand the use of &Foo, which seems to be some sort of closure, or how this specific invocation of #grep operates on the result.
Parsing the Idiom
So far, I've been able to parse bits and pieces of this, but I'm not really seeing how it all fits together. Here's what I think I understand about the sample code.
Foo.constants returns an array of module constants as symbols.
method(:const_get) uses Object#method to perform a method lookup and return a closure.
Foo.method(:const_get).call :Bar is a closure that returns a qualified path to a constant within the class.
&Foo seems to be some sort of special lambda. The docs say:
The & argument preserves the tricks if a Proc object is given by & argument.
I'm not sure I fully understand what that means in this specific context, either. Why a Proc? What "tricks," and why are they necessary here?
grep(Class) is operating on the value of the #map method, but its features are not obvious.
Why is this #map construct returning a greppable Array instead of an Enumerator?
Foo.constants.map(&Foo.method(:const_get)).class
=> Array
How does grepping for a class named Class actually work, and why is that particular construction necessary here?
[Foo::Bar].grep Class
=> [Foo::Bar]
The Question, Restated
I'd really like to understand this idiom in its entirety. Can anyone fill in the gaps here, and explain how the pieces all fit together?
&Foo.method(:const_get) is the method const_get of the Foo object. Here's another example:
m = 1.method(:+)
#=> #<Method: Fixnum#+>
m.call(1)
#=> 2
(1..3).map(&m)
#=> [2, 3, 4]
So in the end this is just a pointfree way of saying Foo.constants.map { |c| Foo.const_get(c) }. grep uses === to select elements, so it would only get constants that refer to classes, not other values. This can be verified by adding another constant to Foo, e.g. Baz = 1, which will not get grepped.
If you have further questions please add them as comments and I'll try to clarify them.
Your parse of the idiom is pretty spot on, but I'll go through it and try to clear up any questions you mentioned.
1. Foo.constants
As you mentioned, this returns an array of module constant names as symbols.
2. Array#map
You obviously know what this does, but I want to include it for completeness. Map takes a block and calls that block with each element as an argument. It returns an Array of the results of these block calls.
3. Object#method
Also as you mentioned, this does a method lookup. This is important because a method without parentheses in Ruby is a method call of that method without any arguments.
4. &
This operator is for converting things to blocks. We need this because blocks are not first-class objects in Ruby. Because of this second-class status, we have no way to create blocks which stand alone, but we can convert Procs into blocks (but only when we are passing them to a function)! The & operator is our way of doing this conversion. Whenever we want to pass a Proc object as if it were a block, we can prepend it with the & operator and pass it as the last argument to our function. But & can actually convert more than just Proc objects, it can convert anything that has a to_proc method!
In our case, we have a Method object, which does have a to_proc method. The difference between a Proc object and a Method object lies in their context. A Method object is bound to a class instance and has access to the variables which belong to that class. A Proc is bound to the context in which it is created; that is, it has access to the scope in which it was created. Method#to_proc bundles up the context of the method so that the resulting Proc has access to the same variables. You can find more about the & operator here.
5. grep(Class)
The way Enumerable#grep works is that it runs argument === x for all x in the enumerable. The ordering of the arguments to === is very important in this case, since it's calling Class.=== rather than Foo::Bar.===. We can see the difference between these two by running:
irb(main):043:0> Class === Foo::Bar
=> true
irb(main):044:0> Foo::Bar === Class
=> false
Module#=== (Class inherits its === method from Method) returns True when the argument is an instance of Module or one of its descendants (like Class!), which will filter out constants which are not of type Module or Class.
You can find the documentation for Module#=== here.
The first thing to know is that:
& calls to_proc on the object succeeding it and uses the proc produced as the methods' block.
Now you have to drill down to how exactly the to_proc method is implemented in a specific class.
1. Symbol
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Or something like this. From the above code you clearly see that the proc produced calls the method (with name == the symbol) on the object and passes the arguments to the method. For a quick example:
[1,2,3].reduce(&:+)
#=> 6
which does exactly that. It executes like this:
Calls :+.to_proc and gets a proc object back => #<Proc:0x007fea74028238>
It takes the proc and passes it as the block to the reduce method, thus instead of calling [1,2,3].reduce { |el1, el2| el1 + el2 } it calls
[1,2,3].reduce { |el1, el2| el1.send(:+, el2) }.
2. Method
class Method
def to_proc
Proc.new do |*args|
self.call(*args)
end
end
end
Which as you can see it has a different implementation of Symbol#to_proc. To illustrate this consider again the reduce example, but now let as see how it uses a method instead:
def add(x, y); x + y end
my_proc = method(:add)
[1,2,3].reduce(&my_proc)
#=> 6
In the above example is calling [1,2,3].reduce { |el1, el2| my_proc(el1, el2) }.
Now on why the map method returns an Array instead of an Enumerator is because you are passing it a block, try this instead:
[1,2,3].map.class
#=> Enumerator
Last but not least the grep on an Array is selecting the elements that are === to its argument. Hope this clarifies your concerns.
Your sequence is equivalent to:
c_names = Foo.constants #=> ["Bar"]
cs = c_names.map { |c_name| Foo.__send__(:const_get, c_name) } #=> [Foo::Bar]
cs.select{ |c| Class === c } #=> [Foo::Bar]
You can consider Object#method as (roughly):
class Object
def method(m)
lambda{ |*args| self.__send__(m, *args) }
end
end
grep is described here http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-grep
=== for Class (which is subclass of Module) is described here http://ruby-doc.org/core-1.9.3/Module.html#method-i-3D-3D-3D
UPDATE: And you need to grep because there can be other constants:
module Foo
PI = 3.14
...
end
and you probably don't need them.