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>
Related
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.
Given the following class:
class Foo
def a
dup.tap { |foo| foo.bar }
end
def b
dup.tap(&:bar)
end
protected
def bar
puts 'bar'
end
end
It seems like both Foo#a and Foo#b should be equivalent, but they're not:
> Foo.new.a
bar
=> #<Foo:0x007fe64a951ab8>
> Foo.new.b
NoMethodError: protected method `bar' called for #<Foo:0x007fe64a940a88>
Is there a reason for this? Is this a bug?
Tested on Ruby 2.2.3p173
Let's start by noting that in Ruby, as you probably know, in a method a declared on a class Foo, I can invoke protected methods on any instance of Foo.
How does Ruby determine whether we're in a method declared on class Foo though? To understand this, we'll have to dig into the internals of method invocation. I'll be using examples from version 2.2 of MRI, but presumably the behavior and implementation are the same in other versions (I'd love to see results from testing this on JRuby or Rubinious, though).
Ruby does this in rb_call0. As the comment suggests, self is used to determine whether we can call protected methods. self is retrieved in rb_call from the current thread's call frame info. Then, in rb_method_call_status, we check that this value of self is of the same class on which a protected method is defined.
Blocks confuse the issue somewhat. Remember that local variables in a Ruby method are captured by any block declared in that method. This means that in the block, self is the same self on which the method was invoked. Let's look at an example:
class Foo
def give_me_a_block!
puts "making a block, self is #{self}"
Proc.new do
puts "self in block0 is #{self}"
end
end
end
proc = Foo.new.give_me_a_block!
proc.call
Running this, we see the same instance of Foo is the same at all levels, even though we called the proc from a completely different object.
So, now we understand why it's possible to call a protected method on another instance of the same class from within a block in a method.
Now let's look at why a proc created with &:bar can't do this. When we place an & sign before a method argument we do two things: instruct ruby to pass this argument as a block, and instruct it to call to_proc on it.
This means invoking the method Symbol#to_proc. This method is implemented in C, but when we invoke a C method, the pointer to self on the current frame becomes the receiver of that C method -- in this case, it becomes the symbol :bar. So we're looking at the instance of foo we got as though we are in a method of class Symbol, and we can't invoke a protected method.
That's a mouthful, but hopefully it makes enough sense. Let me know if you have any suggestions as to how I might improve it!
Imagine I want to write my own math operators like "+"
The simple version would be:
def plus(a,b)
return a+b
end
But this is not what the real "+" does.
I want 3.add(4) # =>7
But how do I tell ruby to take the object that I used my method on?
I tried
def add(c)
return self+c
end
But I get the error message:
:in <main>': private methodadd' called for 3:Fixnum (NoMethodError)
The problem
You defined the method:
def add(c)
return self + c
end
and attempted to use it thus:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
Understanding this error message
This error message tells you exactly what the problem is. I think your problem is simply that you don't understand how Ruby invokes methods on objects.
When Ruby sees 3.add(4) it first looks at the receiver, 3, and determines:
3.class #=> Fixnum
This tells it where the method add is defined: in the class Fixnum or in one of Fixnum's ancestor's classes or modules.
So it looks for it there, doesn't find it, and issues an error message. We can confirm it's not there:
Fixnum.instance_methods.include?(:add)
#=> false
So where is add defined?
You did define it, though, so where is it? Let's find out:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods returns an array of all of public instance methods defined on Object and Object's ancestors. add is not among those, so we conclude add is a protected or private method:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
Let's try invoking that method on an instance of Object:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
That makes sense, considering that Object#add is private. We can, however invoke private methods with Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
As an exercise, make sure you understand the steps Ruby took that led to her raising this exception (that the instance method + is not defined on Object, or equivalently, that the instance of Object does not have a method +).
By the way, where did you define add? By that, I mean what what was the value of self when you defined it? Let's see:
self #=> main
self.class #=> Object
We see that add must be defined on the class for which its receiver is an instance. (A mouthful, yes, but it's important, so make sure you understand that).
Why is Object#add private rather than public?
Consider:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
The is because A inherits greet from Object:
A.ancestors.include?(Object) #=> true
If Object#greet were public, every built-in class and every class you define would have a public instance method greet. That would result in a great deal of misery. (Suppose you had a method great and mistyped it greet!) Even the private greet could cause trouble.)
Where should add be defined?
Since add.class => Fixnum, we define it thus:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
Had I included the line puts "self#{self}" after class Fixnum it would have printed "Fixnum". Salting your code with puts statements that show the value of self often helps in understanding what's going on.
One last thing:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
Why did this not return Fixnum? Since method has no explicit receiver (i.e., no xx.method), Ruby assumes the receiver to be self, which here is:
self #=> main
so she looks for the method method in self.class => Object, and you know what she finds (or, I should say, doesn't find). Instead, we need to write:
Fixnum.instance_method(:add).owner #=> Fixnum
or
3.method(:add).owner #=> Fixnum
Here 3 can of course be replaced by any instance of Fixnum.
Note I've simplified this explanation somewhat. In searching for a method, Ruby also looks in the receiver's singleton class. This is not an issue for immediate objects (numbers, symbols, true, false and nil), however, as they do not have singleton classes:
3.singleton_class #=> TypeError: can't define singleton
By contrast, for example:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
The plus-sign (+) in ruby can be overridden pretty much like any other method (you can look for operator-overloading):
class MyOperator
attr_accessor :text
def initialize(text)
#text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
So there is not much magic to it. But you have to be careful if the overloading the operators make sense in your context.
I'm trying to use reflective methods in Ruby, and running into a behavior that I find really surpising.
The following examples seems to work differently in IRB and when called a ruby script:
Example 1:
def myfun; end
p respond_to?(:myfun)
In IRb, this says 'true',
In script: 'false'.
Example 2:
ml = methods
def myfun; end
p methods - ml
In IRb, this says [:myfun].
In script: [].
I found this under 1.8, 1.9 MRI, JRuby 1.5.6, etc - so I assume this is normal.
Why is the difference?
I was pretty sure 'respond_to?' is the way to see if a method is available - why is that not working in the above case?
This function - method on "main" object - is defined as private in ruby script.
You can check this easily:
ml = private_methods
def myfun; end
p private_methods - ml #=> [:myfun]
p respond_to?(:myfun, true) #=> true
If you call it explicitly on self you will get an error:
self.myfun
# NoMethodError: private method ‘myfun’ called for main:Object
On the other hand, in IRB your method is defined as public. Under the hood it looks something like this:
class Object
def irb_binding
# this is where your entered code is evaluated
def myfun; :ok; end # you can define methods in other methods
self.myfun # and they are public by default
end
end
p irb_binding # :ok
IRB could easily evaluate at the top level but instead it creates a separate environment with the method so that local variables are not shared:
require "irb"
foo = :ok
IRB.start
#>> foo
# NameError: undefined local variable or method `foo' for main:Object
I think methods being public is just a coincidence due to the implementation and it doesn't matter much. These methods are temporary anyway.
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.