I've seen code like this:
def some_method
# ...
end.another_method
What does the end.another_method part do?
I believe that your example is wrong, as what you are doing here is defining a method and calling a method on the result of a method definition (not a method call), which is always (usually?) nil.
There's a similar form which fmendez is referring to, but end is the end of a block, not a method definition in that case.
So, for example:
array.map do |element|
element * element
end.sum
would, hypothetically, return a sum of squares of elements of given array.
But, if you are doing method chaining like this, it is more common to use bracket style blocks instead of do..end, so the above example would read:
array.map{ |element|
element * element
}.sum
Blocks in Ruby are method arguments, not unlike any other method arguments (apart from the dedicated syntax), so putting dot after end is not different than putting the dot after ) in
'hello'.concat(' world!').capitalize
Which is also an example of method chaining.
In Ruby, the . is the message sending operator. (In other languages, it would be called a method calling operator instead.) So, when you say
foo.bar
it means "evaluate foo and send the message bar to the result of evaluating foo".
In this particular case, you are sending the message another_method to the result of evaluating
def some_method; end
The Ruby Language Specification says that the value of a method definition expression is undefined and should be ignored; and on most Ruby implementations, method definition expressions simply evaluate to nil, which isn't terribly useful.
However, on some implementations, method definition expressions do evaluate to something more useful than nil. On Rubinius, for example, they evaluate to the CompiledMethod object for the method being defined. And CompiledMethod has a rich API, so sending messages to a CompiledMethod object definitely makes sense.
It has also been proposed that method definition expressions should return a Symbol corresponding to the name of the method being defined or a Method object.
Put simply: the dot in this particular case means the exact same thing it always means in Ruby: send a message, call a method, invoke a member function, whatever you want to call it.
Related
As I understood return inside a Proc terminates the current method. So in the following example I would expect to see:
a1 > b1 > proc > a2. But actually it never reaches a2, why?
def a
puts "a1"
l = Proc.new {puts "proc"; return}
b l
puts "a2"
end
def b x
puts "b1"
x.call
puts "b2"
end
a
As a general rule, return always returns from the closest lexically enclosing method definition expression.
In this case, the closest lexically enclosing method definition expression is def a, therefore, return returns from a.
It does not actually matter that the return is inside a block in this case. The general rule is, well, general, so it applies regardless of where the return appears.
If we look more specifically at blocks, though, we can see that it still makes sense: in blocks, local variables are captured lexically, self is captured lexically, so it makes sense that return also behaves lexically. It is a general property of blocks that if you want to understand what is going on in a block, you only need to look lexically outwards.
And if we get even more specific, first going from the general rule to blocks, and now from blocks to Procs, the behavior still makes sense: a Proc is essentially a reified block, so it makes sense for a Proc to behave like a block.
There are some exceptions, though, to the general rule, and one important one are lambdas. Talking about lambdas in Ruby is always a little bit weird because lambdas are Procs but they behave differently from Procs. IMO, lambdas should have a separate class alongside Procs. Since lambdas are Procs, it makes it weird to talk about the differences between lambdas and Procs which are not lambdas (which don't have a standardized name and thus are confusingly also called Procs).
The behavior of a lambda differs from the behavior of a non-lambda Proc in two ways, one of which is relevant to your question:
Parameter binding in non-lambda Procs has the same semantics as parameter binding in blocks, whereas parameter binding in lambdas has the same semantics as parameter binding in message sends / method invocations.
In non-lambda Procs, return returns from the closest lexically enclosing method definition expression, just like in blocks, whereas in lambdas, return returns from the lambda itself, just like return in methods.
So, in both of these aspects, non-lambda Procs behave like blocks and lambdas behave like methods. I memorize it like this: "Proc" rhymes with "block" and both "lambda" and "method" are Greek.
As you probably know, there are some methods which also alter the behavior of blocks that are passed to them. E.g. instance_eval and instance_exec change the value of self, and define_method actually does change the behavior of return.
But since you didn't ask about blocks in general, and also didn't ask about lambdas specifically, and there are no reflective methods in your question, the general rules still applies to non-lambda Procs like the one shown in your question: return returns from the closest lexically enclosing method definition expression.
I'm analyzing a block of code written in ruby.
I don't know the language and I need to understand an operation.
def restore
m = ObjectName.where(prop: User.where(email: 'admin#email.com').first.element_id).last
m.todo!
m.waiting!
...
end
what "m.todo!" and "m.waiting!" are doing?
I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
Thank you very much
! and ? are valid parts of a method name in Ruby. They don't have any special meaning, though ! is conventionally used for mutative or destructive actions, and ? is conventionally used for predicate methods.
In this example, there are two methods named todo! and waiting! being called - nothing fancier. If I had to guess, those are methods which simply perform a combined "update a state variable and save" operation (hence, mutative).
In Ruby, foo.bar is the syntax for a message send. It will first evaluate the expression foo (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message bar to the resulting object.
Once you know what message send in Ruby looks like, it is easy to see what m.todo! does: It will first evaluate the expression m (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message todo! to the resulting object.
Method names ending in ! are typically used to mark the "more surprising" of a pair of methods. So, if you have two Methods, both of which do similar things, then the one with the bang at the end is the "more surprising" one. A good example are Process::exit and Process::exit!. Both exit the currently running Ruby process, but the "normal" version (i.e. the one without the bang) runs the exit handlers normally, whereas the "surprising" Version exits immediately without running the exit handlers.
Note: there seems to be a lot of misunderstanding About the naming convention for bang methods. So, let me be clear:
Bang methods have absolutely nothing to do with mutation or destruction. It is simply about surprise. See the Process::exit! example above which has nothing to do with mutation.
Bang methods are always paired with a non-bang method. They mark the "more surprising" variant of a pair of methods. If there is no pair of methods, there is no bang. See, for example Array#collect!, which does have a bang because it is the more surprising variant of Array#collect, since it mutates its receiver; however, Array#append does not have a bang even though it also mutates its receiver because there is no corresponding "less surprising" method.
what "m.todo!" and "m.waiting!" are doing? I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
They do whatever the author of those methods wants. You will have to look that up in the documentation. Those are not methods of the Ruby core or standard library.
I have the following ruby method: a single do iteration without any break, next, or return. Here, cats is an array of cat objects; is_cat_red evaluates to true if cat has a color property of red.
def get_non_red_cats cats
cats.each do |cat|
!is_cat_red?(cat)
end
end
What does the method return (what does the loop evaluate to)?
This is some unusual code and it depends entirely on what the cats method does. You can pass a block to any Ruby method and that method can get executed zero more more times at any point between immediately and the end of the program's execution.
The return value is whatever cats returns, which is not clear from this snippet.
Imagine this in JavaScript terms as that language is a lot less ambiguous:
function get_non_red_cats(cats) {
return cats(function(cat) {
return !is_cat_red?(cat);
}
}
Where this shows that cats is just a function that, potentially, takes a function. It might ignore your function, too.
Now if this is cats.each that changes things as that's probably the Enumerable each method which has well-defined behaviour.
In that case the return value is whatever cats is.
There is no loop in your code. Ruby has two kinds of loops: while and for/in. (Actually, the latter is just syntactic sugar for each.)
In Ruby, an expression evaluates to the value of the last sub-expression evaluated inside the expression. A message send evaluates to the return value of the method that was executed as a result of the message send. The return value of a method is either explicitly the value of the return expression that ended the method execution or implicitly the value of the last expression evaluated inside the method body. (Note that the last expression evaluated inside the body is also what a module or class definition expression evaluates to. A method definition expression however evaluates to a Symbol denoting the name of the method.)
So, what does get_non_red_cats return? Well, there is no return in it, so it returns the value of the last expression evaluated inside the method body. The last expression evaluated inside the method body is a message send of the message each to the object referenced by the parameter binding cats. Ergo, the return value of get_non_red_cats is the return value of the method that gets executed as a result of sending the each message to cats.
And that is all we positively know.
We can make some assumptions, though. In general, each should return self. That's what all implementations of each in the entire core library and standard library do, and it is part of the standard "Iterable" Protocol in Ruby. It would be highly unusual and highly confusing if that were not the case. So, we can assume that whatever implementation of each ends up being executed, it will return self, i.e. the receiver of the message send, i.e. the object referenced by the parameter binding cats.
In other words: the method get_non_red_cats simply returns whatever was passed in as an argument. It is a pretty boring method. In fact, it is the identity method, which is pretty much the most boring method possible.
However, it could have a side-effect. You didn't ask about side-effects, only the return value, but let's look at it anyway.
Since each is supposed to simply return its receiver, it is in some sense also an identity method and thus extremely boring. However, each is generally supposed to evaluate the block it is passed, passing each element of the collection in turn as an argument. But, it ignores the value that the block evaluates to; the block is evaluated purely for its side-effect. Note that each with a block that has no side-effect makes no sense whatsoever. If the block has no side-effect, then the only thing interesting about the block is its value, but each ignores the block's value, and simply returns self.
foo.each do
# something that has no side-effect
end
is fully equivalent to
foo
Another Ruby convention is that message sends that end in a question mark ? should be used for asking questions (duh!) I.e. a message send that ends in a question mark should return something that is suitable to used as a conditional. It also generally shouldn't have a side-effect. (This is called the Command-Query Separation Principle and is a fundamental design principle of Object-Oriented Software Construction.)
And lastly, the ! unary prefix operator, when applied to something that is intended to be used in a conditional (i.e. a boolean value or something equivalent) is generally not supposed to have side-effect. Ergo, since the message send in the block ends with a question mark, it is not supposed to have a side-effect, and the ! operator is also not supposed to have a side-effect, we can assume that the entire block has no side-effect.
This, in turn, means that each shouldn't have a side-effect, and thus get_non_red_cats doesn't have a side-effect. As a result, the only other thing get_non_red_cats can do, is return a value, and it very likely simply returns the value that was passed in.
Ergo, the entire method is equivalent to
def get_non_red_cats(cats)
cats
end
All of this is assuming that the author followed standard Ruby conventions. If she didn't, then this method could do and return anything whatsoever, it could format your harddrive, launch a nuclear attack, return 42, or do absolutely nothing at all.
I am trying to learn the Ruby lexer and parser (whitequark parser) to know more about the procedure to further generate machine code from a Ruby script.
On parsing the following Ruby code string.
def add(a, b)
return a + b
end
puts add 1, 2
It results in the following S-expression notation.
s(:begin,
s(:def, :add,
s(:args,
s(:arg, :a),
s(:arg, :b)),
s(:return,
s(:send,
s(:lvar, :a), :+,
s(:lvar, :b)))),
s(:send, nil, :puts,
s(:send, nil, :add,
s(:int, 1),
s(:int, 3))))
Can anyone please explain me the definition of the :send keyword in the resultant S-expression notation?
Ruby is built on top of “everything is an object” paradigm. That said, everything, including numbers, is an object.
Operators, as we see them in plain ruby code, are nothing but a syntactic sugar for respective object’s methods calls:
3.14.+(42)
#⇒ 45.14
The above is exactly how Ruby treats 3.14 + 42 short notation. It, in turn, might be written using generic Object#send:
3.14.send :+, 42
#⇒ 45.14
The latter should be read as: “send the message :+ with argument[s] (42) to the receiver 3.14.”
Ruby is an object-oriented language. In object-oriented programming, we do stuff by having objects send messages to other objects. For example,
foo.bar(baz)
means that self sends the message bar to the object obtained by dereferencing the local variable foo, passing the object obtained by dereferencing the local variable baz as argument. (Assuming that foo and baz are local variables. They could also be message sends, since Ruby allows you to leave out the receiver if it is self and the argument list if it is empty. Note that this would be statically known by the parser at this point, however, since local variables are created statically at parse time.)
In your code, there are several message sends:
a + b
sends the message + to the object in variable a passing the object in variable b
puts add 1, 2
sends to message add to self passing the literal integers 1 and 2 as arguments, then sends the message puts to self passing the result of the above message send as an argument.
Note that this has nothing to do with Object#send / Object#public_send. Those two are reflective methods that allow you to specify the message dynamically instead of statically in the source code. They are typically implemented internally by delegating to the same private internal runtime routine that the AST interpreter delegates to. Not the other way around. The interpreter does not call Object#send (otherwise, you could customize method lookup rules in Ruby by monkey-patching Object#send, which you can easily try is not the case), rather both Object#send and the interpreter call the same private internal implementation detail.
The rules of Ruby's super keyword is that if it is called without arguments, all of the original arguments are forwarded. If it is called with explicit arguments, the explicit arguments are exclusively passed in.
In this example, arguments should never be forwarded, since I am calling super with exact arguments.
Example:
#doc = Nokogiri::HTML::DocumentFragment.parse("<body></body>")
class Cat < Nokogiri::XML::Node
def initialize(arg1, arg2)
super("cat", arg2) # Pass arg2 to super
# Do something with arg1 later
end
end
When calling: Cat.new("dog", #doc) I expect to get back a <cat></cat> tag, and I expect the first argument to be ignored. Instead I am getting a <dog></dog> tag.
Is there a reason this case would defy expected behavior?
If you look at the source to nokogiri, it's actually the new method that sets the node's name, not the initialize method. Nothing mysterious is happening with regards to invoking super, it's just that the initialize method doesn't do anything with those arguments.
I assume this is because the new method is the one that is supposed to be allocating storage and so on for the object, which in nokogiri's case means creating the underlying libxml node, which is the thing that contain's the node's name.