Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access parent/sibling module methods

Tags:

ruby

Is there any way to access baz_method inside class Qux without mentioning module namespace from first? When there are many nested modules the code doesn't look clean.

module Foo
  module Bar
    module Baz
      class Qux
        def self.qux_method
          Foo::Bar::Baz.baz_method  
        end
      end
      def self.baz_method
      end
    end 
  end
end
like image 439
Saman Mohamadi Avatar asked Jan 07 '16 20:01

Saman Mohamadi


3 Answers

Constants are looked up first in the lexically enclosing module(s) and then up the inheritance chain.

module Foo
  module Bar
    module Baz
      class Qux
        def self.qux_method
          Baz.baz_method    
        end
      end
      def self.baz_method
      end
    end
  end
end

This will work, because the constant Baz will be first looked up in the lexically enclosing module (class) Qux, where it isn't found. The lookup continues in the lexically enclosing module Baz, where it also isn't found. Therefore, it will next be looked up in the lexically enclosing module Bar, where it is found and the search stops.

Note: you write in your title:

Ruby, Access parent/sibling module methods

This is wrong. These modules are neither parents nor siblings. There is no inheritance here. There is, in fact, no relationship between the modules at all. There is only a relationship between the constants and the modules: constants belong to modules.

The module declarations are lexically nested, but the modules themselves aren't.

like image 82
Jörg W Mittag Avatar answered Nov 06 '22 19:11

Jörg W Mittag


You don't need to specify the entire namespace chain. You only need as much as is necessary to disambiguate the constant. Just use Baz.baz_method.

module Foo
  module Bar
    module Baz
      class Qux
        def self.qux_method
          Baz.baz_method
        end
      end

      def self.baz_method
      end
    end
  end
end
like image 27
drhining Avatar answered Nov 06 '22 20:11

drhining


Note: Unless you're explicitly looking for relative module access, this metaprogramming is unnecessary. Use @drhining's solution instead.

You can dynamically climb the module hierarchy using Module#nesting:

module Foo
  module Bar
    module Baz
      class Qux
        def self.qux_method
          Module.nesting[1].baz_method  
        end
      end

      def self.baz_method
        puts "foo!"
      end
    end
  end
end

In this situation, Module.nesting will give the following (when called in qux_method): [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar, Foo]

Note though that this is not an unambiguous reference to Baz, but rather to whatever happens to be one level up in the module chain.

like image 2
Linuxios Avatar answered Nov 06 '22 20:11

Linuxios