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!"
Related
This question already has answers here:
Ruby what class gets a method when there is no explicit receiver?
(2 answers)
Closed 7 months ago.
In Ruby every method is assigned to an object (right?). Ruby provides a lot of "built in" methods and gives the ability to the user to create "user defined" methods.
Built in methods are all defined in a class like String, Integer, Array and so on. Built in methods are all invoked placing a dot after an object followed by the method call.
string = "example"
string = string.reverse
However, when I define a method with the syntax
def method_name (args)
#body
end
to which object is this method assigned? And why when I have to call a method that I have defined I don't use the "dot syntax" but I just write its name and pass it some arguments without applying it to an object, like this:
method_name args
In Ruby every method is assigned to an object (right?)
Incorrect. In Ruby, methods are assigned to modules (including classes). When you call a method on an object, Ruby runtime searches for the method along the object's class's ancestor chain (the object's singleton class -> the object's class ->
the superclass -> superclass's superclass -> ... -> BasicObject). If the method is found, it is bound to the object and gets called, otherwise the Ruby runtime searches for a special method called method_missing and bind it to the current object and calls it.
to which object is this method assigned?
It's assigned to the class Object, as a private instance method.
def foo
:foo
end
Object.private_instance_methods.grep(/foo/)
#=> [:foo]
I guess Ruby does this in order to make top-level "functions" look global.
class A
def self.a
foo
end
def a
foo
end
end
A.a #=> :foo
A.new.a #=> :foo
There is top-level object in Ruby -- main
def method_name(args)
# body
end
self
# => main
self.methods.grep(/method_name/)
# => [:method_name]
main is an instance of Object. Any methods defined in main become instance methods of Object
Object.private_instance_methods.grep(/method_name/)
# => [:method_name]
This makes them available everywhere (because all classes are descendants of Object), meaning that we can call the method without a receiver inside classes
For example
def foo
puts "foo"
end
class X
def y
foo
end
end
# will print foo
X.new.y
# will raise private method `foo' called for #<X:0x000055e406a0f060> (NoMethodError)
# to reproduce don't use irb, just usual file
X.new.foo
Read more
Is there a way to specify a class method such that when the object is used as if it were a function, that method is called? Something like this:
class MyClass
def some_magic_method(*args)
# stuff happens
end
end
# create object
myob = MyClass.new
# implicitly call some_magic_method
myob 'x'
You could write a command class and make use of a ruby shortcut
class MyClass
def self.call(text)
puts text
end
end
MyClass.('x')
Here MyClass.() defaults to the call class method.
As mentioned by #CarySwoveland in the comments you can use method_missing. A basic example is as follows:
class MyClass
def method_missing(method_name, *args)
if method_name.match?(/[xyz]/)
send(:magic_method, args.first)
else
super
end
end
def magic_method(a)
a = 'none' if a.nil?
"xyz-magic method; argument(s): #{a}"
end
end
myob = MyClass.new
myob.x #=> "xyz-magic method; argument(s): none"
myob.x(1) #=> "xyz-magic method; argument(s): 1"
myob.y #=> "xyz-magic method; argument(s): none"
myob.z #=> "xyz-magic method; argument(s): none"
This captures all methods named x, y or z. Our else branch sends all other undefined methods to the original method_missing:
myob.v #=> test.rb:7:in `method_missing': undefined method `v' for
#<MyClass:0x000000021914f8> (NoMethodError)
#from test.rb:25:in `<main>'
What methods you capture is up to you and is determined by the regex /[xyz]/ in this case.
Key methods: BasicObject#method_missing, Object#send. For further info check out this question, read Eloquent Ruby by Russ Olsen (from which this answer references)
You meant to invoke some class' instance method when the object is invoked as a function. This is already supported: instance method call gets called when you "invoke" an object via the functional invocation method () (for more details, see here How do I reference a function in Ruby?).
class C
def call(x)
puts "Called with #{x}"
end
end
obj = C.new
obj.(88) # Called with 88 => nil
obj (88) # NoMethodError: undefined method `obj' for main:Object
If you do want the latter syntax, a horrible trick is the following one (but works only at the top-level, unless you carry along the bindings):
module Kernel
def method_missing(name,*args)
obj = begin
TOPLEVEL_BINDING.local_variable_get(name)
rescue
nil
end
return super if obj.nil?
obj.send :call, *args
end
end
obj = C.new
obj 88 # Called with OK => nil
This example also wants to communicate that you should always keep in mind
who is the receiver of your method calls, and what syntaxes are available for calling methods (especially when you leave out dots and parentheses).
class D
def obj; C.new end
def f
#(obj) 88 # BAD
(obj).(88)
#obj() 88 # BAD
obj().(88)
end
end
The point is that you do not actually have functions, but methods that get called on objects. If you omit the receiver of a method call, the receiver defaults to self, the current object. But in your example, myob does not appear as an explicit receiver (since there is not following dot as in myob.), hence the current object is looked for a method myob.
I would like to implement something with a rescue-like syntax.
begin
raise "Failed"
rescue Exception => e
puts e
end
This works, and e is assigned to the corresponding value. But used in a method, this will raise an exception saying that e is undefined. In other words, how can rescue assigns something to e this way without throwing an undefined error?
class MyClass
def to_s
"hello"
end
end
def my_method
puts e.to_s
end
my_method(MyClass => e)
#=> undefined local variable or method `e' for main:Object
Perhaps what you are looking for is:
class MyClass
def self.hello
puts "This is a class method."
end
def bye
puts "This is an instance method."
end
end
def my_method(params)
klass = params[:class]
puts klass.hello # Call a class method
inst = klass.new # Create an instance
puts inst.bye # Call an instance method
end
my_method(:class => MyClass)
Three things to note:
Although the rescue syntax and the "named parameter" syntax look the same, all they have in common is the => operator. In the first case, you are telling to rescue the Exception "into" the variable e, effectively storing it in that variable. In the second case, you are telling Ruby to collect all parameters passed to the method and store them in a hash, using the supplied key/value pairs. Effectively, you are storing MyClass in the params hash, under the key :class.
In your above example, the to_s definition will not be callable on MyClass itself, because you defined it as an instance method. Instance methods are only available when you create an "instance" of the class with inst = MyClass.new. Then, you can call inst.to_s. Think of the class as an abstract "type" of thing, and of the instance as a concrete thing of that type. If you want the method to be available on the class, not the instances, you need to prefix it with self. I have illustrated the two different syntaxes above.
Again in your example, you are using def MyClass, which Ruby will interpret as "define a method with the name MyClass". If you want to define a class, you need to use class MyClass instead.
Hope this clarifies things a bit.
Documentation I've read tells me to use Module.method to access methods in a module. However, I can use Module::method as well. Is this syntactic sugar, or am I confused?
module Cat
FURRY_LEVEL = 4
def self.sound
%w{meow purr hiss zzzz}.sample
end
end
puts Cat.sound # This works.
puts Cat::sound # This also works. Why?!
puts Cat.FURRY_LEVEL # Expected error occurs here.
puts Cat::FURRY_LEVEL # This works.
Constant resolution always requires that you use ::.
Method invocation is idiomatically and usually a period (.), but :: is also legal. This is not just true for so-called module methods, but for invoking any method on any object:
class Foo
def bar
puts "hi"
end
end
Foo.new::bar
#=> hi
It's not so much "syntax sugar" as it is simply alternative syntax, such as the ability to write if or case statements with either a newline, then and newline, or just then.
It is specifically allowed because Ruby allows methods with the same name as a constant, and sometimes it makes sense to think that they are the same item:
class Foo
class Bar
attr_accessor :x
def initialize( x )
self.x = x
end
end
def self.Bar( size )
Foo::Bar.new( size )
end
end
p Foo::Bar #=> Foo::Bar (the class)
p Foo::Bar(42) #=> #<Foo::Bar:0x2d54fc0 #x=42> (instance result from method call)
You see this commonly in Ruby in the Nokogiri library, which has (for example) the Nokogiri::XML module as well as the Nokogiri.XML method. When creating an XML document, many people choose to write
#doc = Nokogiri::XML( my_xml )
You see this also in the Sequel library, where you can write either:
class User < Sequel::Model # Simple class inheritance
class User < Sequel::Model(DB[:regular_users]) # Set which table to use
Again, we have a method (Sequel.Model) named the same as a constant (Sequel::Model). The second line could also be written as
class User < Sequel.Model(DB[:regular_users])
…but it doesn't look quite as nice.
The :: is called scope resolution operator, which is used to find out under what scope the method, class or constant is defined.
In the following example, we use :: to access class Base which is defined under module ActiveRecord
ActiveRecord::Base.connection_config
# => {:pool=>5, :timeout=>5000, :database=>"db/development.sqlite3", :adapter=>"sqlite3"}
We use :: to access constants defined in module
> Cat::FURRY_LEVEL
=> 4
> Cat.FURRY_LEVEL
=> undefined method `FURRY_LEVEL' for Cat:Module (NoMethodError)
The . operator is used to call a module method(defined with self.) of a module.
Summary: Even though both :: and . does the same job here, it is used for different purpose. You can read more from here.
How is this explained? Can I replace self with some other object?
This syntax is used in ruby to access an object's metaclass, or singleton class. The metaclass is used to store methods for an individual object.
obj = # whatever...
class <<obj
# here, self is defined as obj's metaclass
# so foo will be an instance method of obj's metaclass
# meaning that we can call obj.foo
def foo
# ...
end
end
# this is equivalent to the above
def obj.foo
# ...
end
This is a core part of the language, and isn't defined in any library.
Also see _why's explanation of metaclasses:
http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
Also regarding "self" and replacing it, I've seen this mentioned a few other places - it's difficult for me to think of a good use-case for that feature, though it would sure confuse me. Perhaps there is one. In any case, it is invalid syntax in Ruby to try to change the value of "self":
>> self = Object.new
SyntaxError: compile error
(irb):1: Can't change the value of self
self = Object.new
^
from (irb):1
from :0
In Ruby, and in all other languages that have this concept of "self" or "this", it's used as a pointer to "here", as in, this current object, or class, or metaclass, or whichever object represents what "here" means. Since Ruby is interpreted line-by-line, "self" means the enclosing object when the compiler encounters that keyword.
class Array
self # Means Array class (which is an object, actually)
def self.class_method
self # still means Array class, since you're in a class method
end
def hello
self # Means the current instance of Array
end
class << self
self # Means the metaclass (or "eigenclass") of the Array
end
end
You use that syntax to add class methods, which you call on the class, instead of on a particular instance of that class.
For example:
class Foo
class << self
def do_foo
# something useful
end
end
end
Now you can call Foo.do_foo even if you don't have an object of type Foo.
This is equivalent:
class Foo
def self.do_foo
# something useful
end
end