Every time I've seen empty parameters, it appeared in a method like this:
def method_name(arguments)
#stuff to be executed
end
And then a method is called. Now I've come across this:
x = something()
What am I looking at? I am aware it is a variable, but what is the empty part?
Imagine a situation where you have a variable something and a method something. Whenever you refer something() you are referring to the method.
def something
"Java"
end
something = "Ruby"
a = something #=> value of a is "Ruby"
a = something() #=> value of a is "Java" # got from method
Ruby method parameters are very flexible. According to the method definition, the parameters that are given in the call can be passed directly, defaulted if absent, or compressed to a single Array parameter.
This short program demonstrates. The way parameter checking works is
Parameters supplied in the call are first allocated to all the individual non-defaulted parameters in the method definition, from first to last.
If there are insufficient actual parameters to match all non-defaulted formal parameters, a wrong number of arguments (N for M) (ArgumentError) is raised.
If any actual parameters remain then they are then allocated to all defaulted parameters, from first to last.
If any actual parameters still remain, then they will be bundled into an array and allocated to a splat parameter, if one has been defined.
If any actual parameters still remain, and no splat parameters have been defined, a wrong number of arguments (N for M) (ArgumentError) is raised.
This program demonstrates some of those situations. The commented lines would raise the error described.
def method_name(arguments)
puts "method_name(#{arguments})"
end
def something()
puts 'something()'
end
def something_else(param = 99)
puts "something_else(#{param})"
end
def something_more(param = 99, *rest)
puts "something_else(#{param}, #{rest})"
end
#method_name()
method_name(1)
#something(1)
something()
something_else()
something_else(42)
something_more()
something_more(1)
something_more(1, 2)
output
method_name(1)
something()
something_else(99)
something_else(42)
something_more(99, [])
something_more(1, [])
something_more(1, [2])
In ruby, parentheses are optional, so in your example, calling method_name is the equivalent of calling method_name(), however your method requires an argument. Perhaps this would illustrate it better:
def method_name(arguments={})
#do stuff
end
This method has an optional parameter of a hash. You can call this method with any of: method_name, method_name(), or method_name(argument1: "something")
Related
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 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.
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".
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.
I know what this means:
def f(*args)
...
end
But what does this mean and why would you want to use it? Can it appear with named parameters, too?
def f(*)
...
end
def f(*) has the same effect as def f(*args), except that it does not name the globbed argument array. You might use it if you want the function to accept any number of arguments but don't actually need to refer to them within the function -- for example, if you are overriding a method but calling super without passing an explicit argument list, which results in the original arguments being passed to super.
You can write def f(a, b, *) as well.