Module class << self constants - ruby

Is there my L constants?
module M
class Z
class << self
L = "foo"
end
end
end
=> M::Z::L
=> NameError: uninitialized constant M::Z::L
=> M::Z.constants
=> []
module B
class N
X = "bar"
end
end
=> B::N::X
=> "bar"
=> B::N.constants
=> [:X]
I read this but I do not understand.

You need to do as :
module M
class Z
class << self
L = "foo"
end
end
end
M::Z.singleton_class::L # => "foo"
L is defined inside the singleton class of Z.
"L" is stored in the set of constants of the singleton class of M::Z, You may call it S for now. M::Z::L it actually is searching this constant L, in the constant table of M::Z and its ancestors. since none of them is S, the look-up fails.

Related

Ruby: Get the class on which currently executing code is defined

How can I programmatically get the class on which the currently executing code is defined? I need to find the class when control flow runs through multiple method definitions due to super():
class A
def foo
puts(get_current_class)
end
end
class B < A
def foo
puts(get_current_class)
super
end
end
class C < B
def foo
puts(get_current_class)
super
end
end
C.new.foo
# => C
# => B
# => A
I know how to get the method name (using __callee__, caller_locations or __method__); but what about the class?
Since classes in ruby are also modules, this could be achieved with Module#nesting:
class A
def foo
puts(Module.nesting.first)
end
end
class B < A
def foo
puts(Module.nesting.first)
super
end
end
class C < B
def foo
puts(Module.nesting.first)
super
end
end
C.new.foo
# => C
# => B
# => A
Alternatively, if the goal is to construct a list of which methods may be called by the object's ancestor chain, then you could use Method#owner and Method#super_method (available since ruby version 2.2.0):
c = C.new
c.method(:foo).owner # => C
c.method(:foo).super_method.owner # => B
c.method(:foo).super_method.super_method.owner # => A
c.method(:foo).super_method.super_method.super_method # => nil
As a quick off-the-cuff implementation to programatically print all classes then, how about:
c = C.new
method = c.method(:foo)
while(method)
puts m.owner
method = method.super_method
end
# => C
# => B
# => A
(However, there is no guarantee that all of these methods will actually be invoked - as this is determined at runtime via super!)

Can anonymous modules and class be nested in Ruby?

I can define an anonymous class within an anonymous module:
c = nil
m = Module.new do
c = Class.new
end
m #=> #<Module:0x007fad3a055660>
c #=> #<Class:0x007fad3a0555e8>
Is the above equivalent to:
m = Module.new
c = Class.new
In other words: does the concept of "nesting" actually apply to anonymous modules?
It is not about being anonymous. Assigning a dynamically created class to a constant makes it named:
Foo = Class.new # => Foo
foo = Class.new # => #<Class:0x007fe5dd45d650>
Yet it still doesn't nest further:
module Bar
Baz = Module.new do
p Module.nesting # => [Bar]
end
end
Or even about being dynamic for that matter:
module Quz
eval 'module Qux; p Module.nesting; end' # => [Quz::Qux, Quz]
end
It's about scope gates.
As far as constants are concerned, there are only two scope gates - the keywords class and module.
Nesting is done purely syntactically. That is why you get the weird:
module Do
X = 42
end
module Do
module Re
p Module.nesting # => [Do::Re, Do]
p X # => 42
end
end
module Do::Mi
p Module.nesting # => [Do::Mi]
p X # => uninitialized constant
end
Do.module_eval { p X } # => uninitialized constant
Do.instance_eval { p X } # => uninitialized constant
So if Ruby sees the keywords class or module, it nests the "current node" further. When the closing end is found, it goes up the tree. When a new constant is being defined, it places it in the current node.

Getting the owner of a constant

With a(n inherited) method, the receiver/class where it is defined can be achieved by doing:
class A
def foo; end
end
class B < A
end
B.instance_method(:foo).owner # => A
With a(n inherited) constant, there is no counterpart to instance_method or method method, so it is not straightforward. Is it possible to achieve the class where it is defined?
class A
Foo = true
end
class B < A
end
B.some_way_to_extract_the_owner_of_constant(:Foo) # => A
Like, the below code:
class A
Foo = true
end
class B < A
end
B.ancestors.find { |klass| klass.const_defined? :Foo, false }
# => A
Similar to #Arup's answer, but I've used Module#constants.
class Base
end
class A < Base
Foo = true
end
class B < A
Foo = false
end
class C < B
end
C.ancestors.find { |o| o.constants(false).include?(:Foo) }
#=> B

What's the difference between object's superclass and class's superclass?

I get the result:
String.class # => Class
String.superclass # => Object
Class.class # => Class
Class.superclass # => Module
Both String and Class are objects of Class. Why is String's superclass Object while Class's superclass is Module?
You formulate question in a strange way. I have nothing to say besides "they are defined in this way".
class A
end
class B
end
class C < A
end
class D < B
end
p C.class # => Class
p C.superclass # => A
p D.class # => Class
p D.superclass # => B

Why is the behavior of nested class different between different ways of class declaration?

Why doesn't c.f() below work as b.f()? I'd like to use the class A::C-way to declare a nested class for avoiding too many indentations.
class A
CONSTANT = 1
end
class A
class B
p self # => A::B
def f
print CONSTANT, "\n"
end
end
end
class A::C
p self # => A::C
def f
print CONSTANT, "\n"
end
end
b = A::B.new
b.f() # => 1
c = A::C.new
c.f() # => `f': uninitialized constant A::C::CONSTANT (NameError)
You can put it in one line using semicolon:
class A; class C
...
end end
You can work around this by prefixing the constant with A::
class A
CONSTANT = 1
end
class A
class B
def f
puts A::CONSTANT
end
end
end
class A::C
def f
puts A::CONSTANT
end
end
b = A::B.new
b.f() #=> 1
c = A::C.new
c.f() #=> 1

Resources