Can I evaluate a block inside a Proc? - ruby

Can I yield a block inside a Proc? Consider this example:
a = Proc.new do
yield
end
a.call do
puts "x"
end
What I'm trying to achieve is to print x, but interpreting this with ruby 2.0 raises LocalJumpError: no block given (yield).

No you can't, because the Proc you've created is an independent yield - that is, it's a yield that has no block in its context. Although you can call procs with specified parameters and thereby pass the parameters into the proc, yield doesn't work based on specified parameters; it executes the block found within the proc's closure. And the proc's closure is predefined; it is not modified just because you call it later with a block.
So it's equivalent of just typing 'yield' straight into irb (not within any method definitions) which returns the LocalJumpError: no block given (yield) error.

#Rebitzele has explained why your code doesn't work: the yield keyword is shorthand notation for calling an anonymous block that has been passed to a method, and in this case there isn't even a method.
But you can of course give the block a name and then call it like you would call any other callable object:
a = ->&block { block.() }
a.() do puts 'x' end
# x

Related

Explain the usage of procs in an rspec context

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.

What is being called in this Ruby method?

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.

Ruby: the yield inside of a block

Here is an example of scan:
"abcdeabcabc".scan("a")
So it returns an array of 3 a's. Another example of scan:
"abcdeabcabc".scan("a") {|x| puts x}
which just output each "a", but still output an array, and this time it is actually the original string that it returns.
So from the documentation and the behavior above, the scan either returns an array (no block is given), or returns the original string before which some side-effects take place. The point is that both cases returns something.
Then what will happen if I put a "yield" inside of the block? What will be returned? Or, none? What will be the type of the return value?
"abcdeabcabc".scan("a") {|x| yield x}
The above will not work as Ruby complains that no block is given. Which makes some sense to me. But if it is part of a class method, say, self-implemented "each", then the following works:
class Test
def my_each
"abcdeabcabc".scan("a") {|x| yield x}
end
end
# => :my_each
t = Test.new
# => #<Test:0x007ff00a8d79b0>
t.my_each {|x| puts "so this is #{x}"}
# it works. Outpus 3 a's then return the original string.
So, what is the return value of the my_each method of Test class? Is that a list of yield's or something? But as discussed before "abcdeabcabc".scan("a") {|x| yield x} segment will be complained by Ruby until a block is given. What happened internally to give the block of my_each to the segment inside of my_each implementation?
The block is passed similarly to the argument of that function. This can be specified explicitly, like so:
class Test
def my_each(&block)
"abcdeabcabc".scan("a") do |x|
puts "!!! block"
yield x
# Could be replaced with: block.call(x)
end
end
end
Technically, it's exactly the same (puts put in there for clarification), its presence is not checked the way it is usually done for arguments. Should you forget to give it a block, the function will halt on the first yield it has to execute with exactly the same LocalJumpError (at least, that's what I get on Rubinius). However, notice the "!!! block" in the console before it happens.
It works like that for a reason. You could check whether your function is given a block, if it is specified explicitly as above, using if block, and then skip the yields. A good example of that is a content_tag helper for Rails. Calls of this helper can be block-nested. A simplistic example:
content_tag :div do
content_tag :div
end
...to produce output like:
<div>
<div></div>
</div>
So, the block is executed "on top" (in terms of call stack) of your method. It is called each time a yield happens as some sort of function call on a block. It's not accumulated anywhere to execute the block afterwards.
UPD:
The Enumerator returned by many eaches is explicitly constructed by many iterators to save context of what should happen.
It could be implemented like this on my_each:
class Test
def my_each(&block)
if block
"abcdeabcabc".scan("a") { |x| yield x }
else
Enumerator.new(self, :my_each)
end
end
end
Since a block is given to scan, the original string is returned. It does not matter what is done inside the block.
"abcdeabcabc".scan("a") {|x| yield x}
In the above case, #scan is passing the each matched character to the block associated to it.
Now inside the block of #scan, you are calling yield, which actually then calling the block you passed to the method my_each. Value of x is passed to the block you passed with the method my_each call.
It is too simple, no confusions.
what is the return value of the my_each method of Test class?
As per your current code, the return value should be the #scan method return value, which in turn causes the result of the last statement of the block associated with the method #my_each (if called) or the receiver on which you called the method #scan.
Is that a list of yield's or something?
Yes, yield will be called, as many matches will be found by the #scan method.
Consider the below example :-
"abcdeabcabc".scan("w") {|x| yield x}
Here the block associated with the method #scan will not be called, as #scan didn't find any match, that's why yield wouldn't be called also and as a result method #my_each wouldn't output block expression(passed with the method) result, but "abcdeabcabc".

What is the purpose of blocks?

I've just started on ruby and can't wrap my head around blocks
How is it different from an anonymous function?
On what instance would I want to use it?
And when would I choose it over an anonymous function?
Ruby doesn't have anonymous functions like JavaScript (for example) has. Blocks have 3 basic uses:
Creating Procs
Creating lambdas
With functions
An example of where blocks are similar to anonymous functions is here (Ruby and JavaScript).
Ruby:
[1,2,3,4,5].each do |e| #do starts the block
puts e
end #end ends it
JS (jQuery):
$.each([1,2,3,4,5], function(e) { //Anonymous *function* starts here
console.log(e);
}); //Ends here
The power of Ruby blocks (and anonymous functions) is the fact that they can be passed to any method (including those you define). So if I want my own each method, here's how it could be done:
class Array
def my_each
i = 0
while(i<self.length)
yield self[i]
i+=1
end
end
end
For example, when you declare a method like this:
def foo(&block)
end
block is a Proc object representing the block passed. So Proc.new, could look like this:
def Proc.new(&block)
block
end
Blocks, by necessity, are bound to a method. They can only be turned into an object by a method like I described above. Although I'm not sure of the exact implementation of lambda (it does extra arg checking), but it is the same idea.
So the fundamental idea of a block is this: A block of code, bound to a method, that can either be contained in a Proc object by an & argument, or called by the yield keyword.

ruby block and returning something from block

I am using ruby 1.8.7.
p = lambda { return 10;}
def lab(block)
puts 'before'
puts block.call
puts 'after'
end
lab p
Above code output is
before
10
after
I refactored same code into this
def lab(&block)
puts 'before'
puts block.call
puts 'after'
end
lab { return 10; }
Now I am getting LocalJumpError: unexpected return.
To me both the code are doing same thing. Yes in the first case I am passing a proc and in the second case I am passing a block. But &block converts that block into proc. So proc.call should behave same.
And yes I have seen this post Using 'return' in a Ruby block
When you pass in the block with &, you're converting it to a proc. The important point is that a proc and a lambda are different (lambda is actually a subclass of proc), specifically in how they deal with return.
So your refactored code is actually the equivalent of:
p = Proc.new { return 10;}
def lab(block)
puts 'before'
puts block.call
puts 'after'
end
lab p
which also generates a LocalJumpError.
Here's why: A proc's return returns from its lexical scope, but a lambda returns to its execution scope. So whereas the lambda returns to lab, the proc passed into it returns to the outer scope in which it was declared. The local jump error means it has nowhere to go, because there's no enclosing function.
The Ruby Programming Language says it best:
Procs have block-like behavior and lambdas have method-like behavior
You just have to keep track of what you're using where. As others have suggested, all you need to do is drop the return from your block, and things will work as intended.
return inside a block will return from the method the block is in, not from the block. To return from the block use next (it's named that way because with iterator-methods like each and map returning from the block basically means jumping to the next iteration of the loop).
Note that when the return value is the last evaluated expression in the block, you don't need any kind of return statement at all, i.e. lab { 10 } will do the same thing.
The {} block includes the context in which it is given, so the return tries to return from the line lab { return 10; }. You can actually make this work (sometimes even in a useful manner) by placing that line inside a method, which will then return (i.e. "after" is not printed).
To return the 10 to block.call, omit the return (or substitute next).
I think you just need to dereference the block before you pass it:
foo = lambda { return 10 }
def trace_block(&fn)
puts 'before calling fn'
puts fn.call
puts 'after caling fn'
end
trace_block(&foo)
Output:
before calling fn
10
after caling fn
More info:
Understanding Ruby Blocks, Procs and Lambdas
Ruby Blocks 101

Resources