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
Related
How to access a class inside a class << self in Ruby? In the code sample, it's SecondClass.func which should be accessed.
class MainClass
class << self
class SecondClass
def self.func
p 'Hi!'
end
end
end
end
UPDATE
It can be accessed like:
MainClass.singleton_class::SecondClass.func
It can be accessed like:
MainClass.singleton_class::SecondClass.func
Can somebody help me distinguish When we create methods inside class << self block and when we define normal methods.
I saw somewhere code like this, but I don't know concisely the use cases of them
class Foo
def initialize
end
def bar
end
class << self
def foobar
end
end
end
The methods defined right inside a class block are instance methods:
class Foo
def bar
end
end
Methods defined within class << self inside a class block are class methods:
class Foo
class << self
def baz
end
end
end
Instance methods become available to any instance of a given class:
foo = Foo.new
foo.bar
Whereas class methods can be called directly on the class:
Foo.baz
Attempting to call instance methods on the class or vice versa results in an error:
Foo.bar #=> NoMethodError: undefined method `bar' for Foo:Class
foo.baz #=> NoMethodError: undefined method `baz' for #<Foo:0x00007ffe20055a20>
Another way to define class methods is by prefixing the method name with self.:
class Foo
def self.baz
end
end
You could also define them outside the class block, although this is rarely seen:
def Foo.baz
end
Or likewise:
class << Foo
def baz
end
end
Note that defining methods this way is not limited to classes. You can add methods to arbitrary objects, e.g.:
o = Object.new
def o.hello
"hello from o"
end
o.hello
#=> "hello from o"
Or via:
class << o
def hello
"hello from o"
end
end
Internally, these methods are added to the object's singleton class. It's a special purpose class to hold methods for just that instance:
o.singleton_class.instance_methods(false)
#=> [:hello]
For the Foo class above:
Foo.instance_methods(false) #=> [:bar]
Foo.singleton_class.instance_methods(false) #=> [:baz]
So technically, a class method is just an instance method defined on the class' singleton class.
You may need to read up on Ruby's instance and class methods.
But personally, I'd do
class Foo
class << self
def foobar
end
end
end
instead of
class Foo
def self.foobar
end
end
whenever I want to add some class level attributes, or make a method private etc as
class Foo
private
def self.foobar
end
end
wouldn't work the same as
class Foo
class << self
private
def foobar
end
end
end
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]
Here are the Ruby classes I have:
class MyBase
class << self
def static_method1
##method1_var ||= "I'm a base static method1"
end
def static_method1=(value)
##method1_var = value
end
def static_method2
##method2_var ||= "I'm a base static method2"
end
def static_method2=(value)
##method2_var = value
end
end
def method3
MyBase::static_method1
end
end
class MyChild1 < MyBase
end
class MyChild2 < MyBase
class << self
def static_method1
##method1_var ||= "I'm a child static method1"
end
end
end
c1 = MyChild1.new
puts c1.method3 #"I'm a base static method1" - correct
c2 = MyChild2.new
puts c2.method3 # "I'm a base static method1" - incorrect. I want to get "I'm a child static method1"
I'm aware of attr_accessor and modules, but I can't use use them here because I want them to give default values in MyBase class. I want to override MyBase.static_method1 in MyChild2.
The problem is that method3 is always explicitly calling the method on the base class. Change it to this:
def method3
self.class.static_method1
end
After that, consider not using ##.
## in ruby is extremely counterintuitive and rarely means what you think it means.
The problem with ## is that it is shared across the all of the inherited classes and the base class. See this blog post for an explanation.
In Ruby. How do I refer to a class from within the class << self definition?
module MyModule
class MyClass
puts self # returns MyModule::MyClass
class << self
puts self # returns #<Class:MyModule::MyClass>
puts ???
end
end
end
How do I get the result MyModule::MyClass from where the ??? is?
Thanks,
Arth
Until somebody comes up with a more orthodox solution, nesting seems to do the work:
module MyModule
class MyClass
class << self
puts nesting[1] # MyModule::MyClass
end
end
end