This question already has answers here:
class << self vs self.method with Ruby: what's better?
(6 answers)
Closed 8 years ago.
My understanding is that:
class Example
class << self
def my_method; end
end
end
is equivalent to:
class Example
def self.my_method; end
end
but is that correct?
They are equivalent, but choose the latter for clarity reasons. When you have a class that is many lines long you may miss the class method definition when using class << self.
Another good reason to use class << self is when you need accessors on the class level:
class Foo
class << self
attr_accessor :bar
end
end
Beware that this is often not what you want as it is not thread safe. But that's a design problem. If you need it, you need it.
In the case of class << self all methods defined below will be class methods up until the class << self is closed. For a class method at a singular level or multiple ones if you wish you can define the method as self.foo.
class Test
def self.foo
end
def bar
end
end
class Test
class << self
def foo
end
end
def bar
end
end
In both of these cases you will end up with a class method "foo" and an instance method "bar". Both ways accomplish the same thing.
Related
While watching this video I came across an interesting question posed by the presenter, Dave Thomas. He is talking about the syntax we see all the time in Ruby class method definitions:
class Foo
class << self
def bar
puts "inside class method"
end
def self.baz
puts "inside anonymous superclass method"
end
end
end
Of course, we can access Foo.bar, but how does one go about baz? Dave Thomas talks about the class << self syntax inserting an anonymous superclass into the hierarchy. I tried the following:
Calling Foo.superclass.bazdoesn't work because Foo.superclass is just Object.
I poked around the available methods of the ancestry hierarchy to no avail.
Test.class_eval 'self.self.baz'...now things are getting a little ridiculous.
Thoughts?
The problem is presented around 44:23 in the video.
At the end of the video, we are offered several answers to this question.
First, something pretty ugly. You can reopen the class:
class Foo
class << self
baz
end
end
And another way. Since class definitions are executed, you can return the inner self into a variable:
meta = class Foo
class << self
def self.baz
puts "inside anonymous superclass method"
end
self # return self here
end
end
meta.baz
Or, most elegantly you can open Class and add a method to it:
class Class
def meta
class << self
self
end
end
end
# class Foo ...
Foo.meta.baz
which turns out to be just a reimplementation of Object#singleton_class.
attr_accessor does not work on the following code. The error says "undefined method 'things' for Parent:Class (NoMethodError)":
class Parent
##things = []
attr_accessor :things
end
Parent.things << :car
p Parent.things
However the following code works
class Parent
##things = []
def self.things
##things
end
def things
##things
end
end
Parent.things << :car
p Parent.things
attr_accessor defines accessor methods for an instance. If you want class level auto-generated accessors you could use it on the metaclass
class Parent
#things = []
class << self
attr_accessor :things
end
end
Parent.things #=> []
Parent.things << :car
Parent.things #=> [:car]
but note that this creates a class level instance variable not a class variable. This is likely what you want anyway, as class variables behave differently than you might expect when dealing w/ inheritance. See "Class and Instance Variables In Ruby".
attr_accessor generates accessors for instance variables. Class variables in Ruby are a very different thing, and they are usually not what you want. What you probably want here is a class instance variable. You can use attr_accessor with class instance variables like so:
class Something
class << self
attr_accessor :things
end
end
Then you can write Something.things = 12 and it will work.
Just some clarification: class variables won't be accessible using attr_accessor. It's all about instance variables:
class SomeClass
class << self
attr_accessor :things
end
#things = []
end
because in Ruby, class is an instance of the class "Class" (God, I love to say that) and attr_accessor sets accessor methods for instance variables.
This is probably the simplest way.
class Parent
def self.things
##things ||= []
end
end
Parent.things << :car
p Parent.things
Аlso note that a singleton method is a method only for a single object. In Ruby, a Class is also an object, so it too can have singleton methods! So be aware of when you might be calling them.
Example:
class SomeClass
class << self
def test
end
end
end
test_obj = SomeClass.new
def test_obj.test_2
end
class << test_obj
def test_3
end
end
puts "Singleton methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton methods of test_obj"
puts test_obj.singleton_methods
Singleton methods of SomeClass
test
Singleton methods of test_obj
test_2
test_3
Parent.class_variable_get(:##things)
That would be the built-in way. In most cases this should be sufficient I think. No need to have a class variable accessor in the instance.
class Parent
#things = []
singleton_class.send(:attr_accessor, :things)
end
This pattern is most useful when you are defining accessors dynamically or creating them inside a method:
class Foo
def self.add_accessor(name)
singleton_class.send(:attr_accessor, name)
end
end
Foo.add_accessor :things
Foo.things = [:car]
Foo.things # => [:car]
I'm greatly confused by Ruby's behavior when defining const_missing and other class methods inside a class << self definition as opposed to using the def self.foo syntax.
I was trying to do something like this:
class Foo
class << self
def foo
puts MISSING
end
def const_missing(name)
puts "#{name} missing"
end
end
end
Foo.foo
I mostly use the the class << self syntax to define class methods. However, it did not work as expected. const_missing is never called. The above results in a NameError.
Defining both methods like this works as expected:
def self.foo
puts MISSING
end
def self.const_missing(name)
puts "#{name} missing"
end
I thought that the class << self syntax is just another way to define class methods, but completely equivalent to def self.foo? I've tested the above with MRI 1.8.7, 1.9.2 and JRuby 1.5.6. So obviously I'm missing something here?
Any hint is greatly appreciated.
Thanks, Martin
class << self is not a shortcut to define class methods. This syntax (I don't know the exact naming) opens the eigenclass from a object (in your case, a class). With that you can define methods to the object (not instance methods). But when you call a constant into the eigenclass, you are calling a constant from the eigenclass, not from the class. In this case you have to define a class method on the eigenclass to the const_missing, two ways to do that:
class Test
class << self
def foo
p MISSING
end
# First way: (syntax sugar for the second way)
def self.const_missing(name)
name
end
# Second way:
class << self # eigenclass of the eigenclass of the class
def const_missing(name)
name
end
end
end
end
Test.foo #=> :MISSING
In the following fragment, is it possible to refer to the FOO constant from outside the module, and if so, how?
module X
class << self
FOO = 2
end
end
class <<X
self
end::FOO
or
class Object
def metaclass
class <<self
self
end
end
end
X.metaclass::FOO
This question already has answers here:
Ruby Definition of Self
(3 answers)
Closed 7 years ago.
What does ruby self represent? what is it? what does it mean? Could some please explain it to me? in simple terms please
And what is its function in a class?
class MyClass
def method.self
end
end
self refers to the object that is currently in context.
In your example, self is the class itself and def self.method is defining a class method. For example:
class MyClass
def self.method
puts "Hello!"
end
end
> MyClass.method
#=> "Hello"
You can also use self on instances of a class.
class MyClass
def method_a
puts "Hello!"
end
def method_b
self.method_a
end
end
> m = MyClass.new
> m.method_b
#=> "Hello!"
In this case, self refers to the instance of MyClass.
There is a good blog post on self in Ruby here, or, as it was pointed out in the comments, there is some more on this in the Ruby documentation.