Ruby Namespacing

Ruby namespacing

When you use

#The code in question
module Api
module V1
class UserController < ApplicationController
end
end
end

ApplicationControllerdefinition will be searched in Api::V1 then if not found in Api then if not found in the root namespace.

I agree it could be confusing, that's why I tend to use absolute paths like so: ::ApplicationController

If ever I'd need Api::ApplicationController, I'd write ::Api::ApplicationController

Basically the :: tells ruby to start from the root namespace and not from where the code lives.


Sidenote

Be aware that there are vicious cases in Rails development mode. In order to gain speed, the strict minimum is loaded. Then Rails looks for classes definitions when needed.

But this sometimes fails big time example, when you have say ::User already loaded, and then look for ::Admin::User. Rails would not look for it, it will think ::User does the trick.

This can be solved using require_dependency statements in your code. Speed has a cost :)

Ruby Class namespacing with modules: Why do I get NameError with double colons but not module blocks?

It may seem counter-intuitive, but constant lookup in Ruby is done using current lexical scope, i.e. the current lexical nesting level (location in the source code), not the semantic nesting level.

This can be tested by inspecting Module.nesting, which prints the current lexical scope:

class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end

module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end

Since Ruby uses this nesting level for symbol lookup, it means in the situation where you try to look up FirstClass within nesting [Foo::SecondClass], Ruby will not find it.

However when you try to look it up within nesting [Foo::SecondClass, Foo], it will find FirstClass under Foo, just like you expect.

To get around this, you could do:

class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end

Which will now work as you expect, since you provided the necessary lookup hint for FirstClass, and told Ruby it is inside Foo.

How to add module namespace to a ruby class/module?

It seems like what you're asking is kinda multi-faceted, but if you just want to use the class in another file without having to type out the namespace each time then a simple solution would just be to redefine it in the file you want to use it in

ClassName = A::B::C::D::ClassName

Then you can just do ClassName.method just fine

Ruby namespacing with a class vs. module?

The most immediate benefit to using modules for namespacing is that you can use include to import the namespace, and use the constants declared within it unqualified:

module Foo; class Bar; end; end

module Elsewhere
include Foo
Bar.new
end

What are implications of namespacing classes under same namespace/under the same name as a module

As mentioned in the comment, namespacing as described in the question is just namespacing, and so the above are completely separate modules/classes.

Proper rails model namespacing

Indeed, if you do that, Ruby will complain because Party can't be a module and a class at the same time. So at least, Party would need to remain a class.

Now as the "Rails way" is concerned, we don't usually subclass our associations (ie. your Chat will probably belong_to a Party), we just put all our models in the root namespace (unless one has a good reason to). So you'd have Party at app/models/party.rb and Chat at app/models/chat.rb.

I'm guessing one would make a namespaced subclass Party::Chat only if there's a different ::Chat already present, and even that could lead to trouble with Ruby's constant lookup which is sometimes counter-intuitive.

Namespacing in Ruby require

You will want to wrap your code in an actual module or class

something like

class Foo
def self.bar
"quxx"
end
end

This way, you will be able to call Foo.bar to access your method.

How do I un-namespace a ruby constant?

At first you can add the constant you need and assign the Class/Module to it (remember both are just objects). You should duplicate it to reset the name:

Posts = TableEngine::Posts.dup

Afterwards remove the source constant name:

Object.send :remove_const, :TableEngine

Then:

Posts
# => Posts
TableEngine
# => NameError: uninitialized constant TableEngine
TableEngine::Posts
# => NameError: uninitialized constant TableEngine

UPDATE. Why dup is needed:

Notice, the class SomeClass is a shortcut for creating an object of type Class and assigning it to some constant:

SomeClass = Class.new

When you create a class, its name value isn't set:

klass = Class.new
# => #<Class:0x00000001545a28>
klass.name
# => nil

When you assign it to the constant for the first time, the name is assigned and memoized:

Klass = klass
# => Klass
klass.name
# => "Klass"

When you later assign the object of type Class to another constant, it remains just the same object, referred by both constants:

NewKlass = Klass
# => Klass
Klass.name
# => "Klass"
NewKlass.name
# => "Klass"

That's why even if the initial constant will be removed, the object will keep carrying the old name.

Object.send :remove_const, :Klass
# => Klass
NewKlass
# => Klass
NewKlass.name
# => "Klass"

Klass
# => NameError: uninitialized constant Klass

The object by itself hasn't been changed. What has been changed is the list of constants, carried by the Object object.

When you duplicate the object of type Class it is created without any name (it is the new object):

new_klass = NewKlass.dup
# => #<Class:0x000000016ced90>
new_klass.name
# => nil

And when you assing it to the new constant, the name is set. That is how in the very first example above it receives the new name:

Posts = TableEngine::Posts.dup
# => Post

What's the difference between these Ruby namespace conventions?

The difference lies in nesting.

In the example below, you can see that the former method using class Foo, can get the outer scope's constant variables BAR_A without errors.

Meanwhile, class Baz will bomb with an error of uninitialized constant A::B::Baz::BAR_A. As it doesn't bring in A::* implicitly, only A::B::*explicitly.

module A
BAR_A = 'Bar A!'
module B
BAR_B = 'Bar B!'
class Foo
p BAR_A
p BAR_B
end
end
end

class A::B::Baz
p BAR_A
p BAR_B
end

Both behaviors have their place. There's no real consensus in the community in my opinion as to which is the One True Ruby Way (tm). I personally use the former, most of the time.



Related Topics



Leave a reply



Submit