Confusion with call to "puts" in ruby - ruby

We all know the fact that in ruby the . operator with an object left to the . helps to send the message (right to the .).
With the above principle here with this - "100".to_s , we can say that . operator is sending the message to_s to the object 100. Nice one!
So what about the puts("hello")? Here are my questions to local ruby experts:
where the . operator?
who is receiver here?

Receiver in this case is implicit self. puts is a method of Kernel. All classes include Kernel module, so all objects have a puts method on them. The only thing is: it's private. Private methods can only be called with implicit self (or using send)
puts 'foo' # >> foo
1.puts 'bar' # ~> -:3:in `<main>': private method `puts' called for 1:Fixnum (NoMethodError)
1.send :puts, 'bar' # >> bar

The receiver is omitted, and is self in that context. Therefore, the . is omitted too. puts is a method on Kernel, and whatever the receiver is, it can access puts since Kernel is included in any class that has an instance.

Related

Do methods have to be always inside classes in Ruby?

Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
Technically they are aways defined inside a class, but this doesn't mean you always need to open a class to define a method.
Here is what might look like a top-level function in other languages:
def foo
puts self
puts self.class
end
If we simply call foo, we'll get:
main
Object
This actually defined a private instance method in the Object class. We see that self in the top-level scope is a special object called main.
On the other hand, we can try to call this method on other stuff:
'bar'.foo #!> private method `foo' called for "bar":String (NoMethodError)
This errorred out as foo is private. We can use a special method called send to invoke private methods:
'bar'.send :foo
Gets us:
bar
String
We can also define methods in the so-called singleton classes. You can think of them as classes with only a single instance. For example:
foo = 'foo'
def foo.bar
puts 'baz'
end
foo.bar # => baz
'quix'.bar # !> undefined method `bar' for "quix":String
'foo'.bar # !> undefined method `bar' for "foo":String
puts (foo.singleton_class.instance_methods - Object.instance_methods).first
# => bar
Here the bar method was defined on the singleton class of foo. Note that even another string with the same contents is still a difference instance, hence it doesn't have the bar method.
Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
No.
Methods have to be always inside modules. (Class are modules, too.)
Example:
module Foo
def bar; end
end
There is no class here.

Confusion with method call from IRB in Ruby

I was playing with method definition and calling to them in the main of IRB.
def show
p "hi"
end
#=> nil
show
#"hi"
#=> "hi"
self.show
#"hi"
#=> "hi"
The above are good and understood.
Now let's try something different:
def Foo
p "hi"
end
#=> nil
Foo
#NameError: uninitialized constant Foo
#from (irb):4
#from C:/Ruby193/bin/irb:12:in `<main>'
While the call to Foo has thrown an error as above,how does the below remove that?
self.Foo
#"hi"
#=> "hi"
In Ruby, you can call methods without a receiver and without an argument list. However, this means that there is an ambiguity: does foo mean "call method foo on the implicit receiver self without arguments, i.e. equivalent to self.foo()" or does it mean "dereference the variable foo"? Ruby can't know which you mean, so there are some simple rules.
For a local variable, the rule is that foo is always a method call, unless foo is statically known at parse time to be a local variable. So, when is it statically known to be a variable? When there was an assignment to that variable which was parsed (but not necessarily executed!) before the use.
Example:
foo # method call
if false
foo = 42 # will never be executed, but *will* be parsed
end
foo # variable dereference, since the `foo` assignment was parsed
For constant variables, the rule is even simpler: Foo is always interpreted as a constant dereference. Period.
So, how do you call a method with such a name? Easy: like I said, the ambiguity arises only for method calls with no argument list and no explicit receiver. So, if we add either one or both of those, Ruby will know that we are trying to call a method and not dereference a variable:
foo()
self.foo
self.foo()
Foo()
self.Foo
self.Foo()
Of course, in the example you gave above, only the first one will work. When you define a method at the top-level, it is added as a private method to Object, and private methods can only be called without an explicit receiver, even if that receiver is self. So, self.Foo won't work, because Foo is private. (Except in IRb, where, for convenience reasons, top-level methods are public.)

Ruby global scope

When answering another question, I realized that the following program does not quite do what I thought it does.
puts "test"
self.puts "test" # => private method `puts' called for main:Object (NoMethodError)
The exception surprises me, as I always thought that top-level method calls would be resolved by the main object instance, but this doesn't seem to be the case.
Who's the actual receiver of the first call and how is it resolved? Is this a special rule that only applies to method calls at the top-level scope?
Here is a good discussion that talks about this question.
The top level methods, which are provided by Kernel, are automatically included to the Object class. This means the Kernel methods will appear in everything.
The error private method 'puts' called for main:Object (NoMethodError) is just stating that puts exists but is privately scoped.
ree-1.8.7-2011.03 :001 > puts "test"
test
ree-1.8.7-2011.03 :004 > self.send(:puts, "hi" )
hi
UPDATE
There is no magic for Kernel methods. There is no scope hopping or anything. I think the confusion lines in what the scope is when using self. You do not have access to private methods using self.
class PutsTest
def success_puts
private_puts
end
def failed_puts
# trying to access a private method from self
self.private_puts
end
private
def private_puts
puts 'hi'
end
end
By using self, you are changing the scope from calling the method inside of PutsTest to calling from the outside of PutsTest
ree-1.8.7-2011.03 :095 > test = PutsTest.new
ree-1.8.7-2011.03 :096 > test.success_puts
hi
ree-1.8.7-2011.03 :097 > test.failed_puts
NoMethodError: private method `private_puts' called for #<PutsTest:0xd62c48>

Ruby any way to catch messages before method_missing?

I understand that method_missing is something of a last resort when Ruby is processing messages. My understanding is that it goes up the Object hierarchy looking for a declared method matching the symbol, then back down looking for the lowest declared method_missing. This is much slower than a standard method call.
Is it possible to intercept sent messages before this point? I tried overriding send, and this works when the call to send is explicit, but not when it is implicit.
Not that I know of.
The most performant bet is usually to use method_missing to dynamically add the method being to a called to the class so that the overhead is only ever incurred once. From then on it calls the method like any other method.
Such as:
class Foo
def method_missing(name, str)
# log something out when we call method_missing so we know it only happens once
puts "Defining method named: #{name}"
# Define the new instance method
self.class.class_eval <<-CODE
def #{name}(arg1)
puts 'you passed in: ' + arg1.to_s
end
CODE
# Run the instance method we just created to return the value on this first run
send name, str
end
end
# See if it works
f = Foo.new
f.echo_string 'wtf'
f.echo_string 'hello'
f.echo_string 'yay!'
Which spits out this when run:
Defining method named: echo_string
you passed in: wtf
you passed in: hello
you passed in: yay!

Why do both ways of accesing module functions exist in Ruby?

module A
def self.func
puts "func"
end
end
>> A.func
func
>> A::func
func
Why do both . and :: exist? Why not only .?
The scope resolution operator (::) can resolve constants, instance methods, and class methods, so we can use that operator for essentially any method as long as we are looking in the right place.
Additionally, since the method "func" is defined as a class method of module A (by self.func, analogous to a "static" method) it belongs directly to the module (which is itself an object) so it can be called with the dot operator with the module as the receiver. Note that instances of module A do not have any visibility to "func", since it is a class method:
aye = Object.new.extend(A)
aye::func # raises NoMethodError
aye.func # raises NoMethodError
If the method was defined as an instance method then it could only be called with the dot operator on instances of the module.
module B
def func2
puts "OK!"
end
end
B::func2 # raises NoMethodError
B.func2 # raises NoMethodError
bee = Object.new.extend(B)
bee::func2 # "OK!"
bee.func2 # "OK!"

Resources