I assume you're trying this out in Rails development mode. In this mode all constants (classes, modules and constants) are loaded by demand.
When ruby meets undefined constant, it throws an error, which autoloader intercepts and tries to load the constant by converting its name to a path.
In your case, autoloader tries to find
MyNamespace::MY_SET in app/presenters/my_namespace.rb (which fails) and has no idea that you actually defined it in app/presenters/my_namespace/base_presenter.rb. But after you have loaded your MyNamespace::BasePresenter (which, btw, lies on the correct path), MyNamespace, MyNamespace::MY_SET, and MyNamespace.my_method got initialized and become available.
What you need to do is to
a) define MyNamespace correctly and move methods and constants to its definition:
app/presenters/my_namespace.rb
module MyNamespace
MY_SET = Set.new(['a', 'b', 'c'])
def self.my_method
true
end
end
app/presenters/my_namespace/base_presenter.rb
# note that I don't open module here,
# but use a constant to enable autoloading of MyNamespace module
class MyNamespace::BasePresenter
end
or
b) just move all methods/constants to your BasePresenter class. Since it lies on a correct path, constant MyNamespace::BasePresenter::MY_SET will just work.
module MyNamespace
class BasePresenter
MY_SET = Set.new(['a', 'b', 'c'])
def self.my_method
true
end
end
end
Bonus part
The difference between
module MyNamespace
class BasePresenter
end
end
and
class MyNamespace::BasePresenter
end
is when MyNamespace is undefined in first case it will be defined (module MyNamespace either opens existing module or defines new one), but in second case the mechanism described above will try to load MyNamespace somewhere, and if it fails - you'll get uninitialized constant error MyNamespace.
What it also means to you is if you define all your namespaced classes as a first case (inside module MyNamespace)
app/presenters/my_namespace/base_presenter.rb
module MyNamespace
class BasePresenter
end
end
and also have MyNamespace in its proper place with some code inside
app/presenters/my_namespace.rb
module MyNamespace
MY_SET = Set.new(['a', 'b', 'c'])
end
And if your MyNamespace::BasePresenter will gets loaded first, it'll actually define MyNamespace and your app/presenters/my_namespace.rb will not be loaded (since autoloading loads only missing constants), and you'll have to require it yourself.
presenter = MyNamespace::BasePresenter.new
MyNamespace::MY_SET # boom, uninitialized constant error
The solution here is to define modules in 1 proper place (that autoloading knows how to find) and use class MyNamespace::BasePresenter format for defining namespaced classes in their proper locations.
MyNamespace::MY_SETandMyNamespace::my_methodshould work. What error do you have?MyNamespace::MY_SETwork after you doMyNamespace::BasePresenter.new?