I have a simple module that defines a constant and makes it private:
module Foo
Bar = "Bar"
private_constant :Bar
end
I can include it in a class like this, and it works as expected:
class User
include Foo
def self.test
Bar
end
end
puts User.test
# => Bar
begin
User::Bar
rescue => exception
puts "#{exception} as expected"
# => private constant Foo::Bar referenced as expected
end
(let's call it "typical class" definition)
Then I tried the Class.new approach, but this failed miserably:
X = Class.new do
include Foo
def self.test
Bar # Line 28 pointed in the stack trace
end
end
begin
X::Bar
rescue => exception
puts "#{exception}"
# => private constant Foo::Bar
end
puts X.test
# test.rb:28:in `test': uninitialized constant Bar (NameError)
# from test.rb:28:in `<main>'
Why? I always though class Something and Something = Class.new are equivalent. What's the actual difference?
Then I had a strike of inspiration, and recalled there's alternative way to define class methods, which actually worked:
X = Class.new do
class << self
include Foo
def test
Bar
end
end
end
begin
X::Bar
rescue => exception
puts "#{exception}"
# => uninitialized constant X::Bar
end
puts X.test
# Bar
Again - why this one work, and why the exception is now different: private constant Foo::Bar vs uninitialized constant X::Bar?
It seems like those 3 ways of initializing classes differ in a nuanced way.
- does exactly what I want: Bar is accessible internally, and accessing it gives exception about referencing private constant.
- second gives "ok" exception, but has no access to Bar itself
- third has access, but now gives slightly different exception
What is exactly going on in here?