'Ruby constants in singleton methods
I have a Ruby C extension; I call that class FooC defined in ext/foo/foo.c
, in that file I have
void Init_foo(void)
{
VALUE cFoo = rb_const_get(rb_cObject, rb_intern("FooC"));
:
rb_define_const(cFoo, "BAR", 7);
:
That is included in the "Ruby part" of the extension in lib/foo.rb
like
class FooC ; end
require 'foo/foo'
class Foo < FooC
class << self
def puts_bar
puts BAR
end
:
end
:
end
Unexpectedly, I get an error
NameError: uninitialized constant #<Class:Foo>::BAR
I was expecting that Ruby would not find BAR
in the Foo
namespace, but would then search FooC
where it would find it. Strangely, if I use Foo::BAR
or self::BAR
, the error goes away, and a similar usage in a Foo
instance method gives me no errors at all.
Anyone have an idea as to why I need this seemingly redundant qualification of constants in singleton methods?
[edit]
Following the interesting answer below, I confirm that this qualification is not needed in a proper class method:
class Foo < FooC
def self.puts_bar
# no NameError here
puts BAR
end
:
end
rather than a instance method of the eigenclass.
Solution 1:[1]
You are looking the constant up in the eigenclass of Foo
, not in the Foo
itself. Start with figuring out what’s what without any c bindings.
class FooC; end
class Foo < FooC
BAR = 42
puts "Foo: #{self}, DEF: #{const_defined?(:BAR)}"
class << self
def puts_bar
puts "Foo.class: #{self} DEF: #{self.class.const_defined?(:BAR)}"
puts self.class.const_get(:BAR)
end
end
def puts_bar
puts "Foo.class: #{self} DEF: #{self.class.const_defined?(:BAR)}"
puts self.class.const_get(:BAR)
end
end
And see how it works:
# Foo: Foo, DEF: true
[2] pry(main)> Foo.puts_bar
#? Foo.class: Foo DEF: false
# NameError: uninitialized constant Class::BAR
# from (pry):8:in `const_get'
[3] pry(main)> Foo.new.puts_bar
#? Foo.class: #<Foo:0x0000556e174b91c0> DEF: true
# 42
Constants are made visible within instance functions by looking up the class’ constants. #<Class:Foo>
in the error message you’ve got is explicitly pointing out to that.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nakilon |