Accessing Module Methods with ::

Access module functions in Ruby

You demonstrated the complete misunderstanding of OOP concepts. And, BTW, the method names in Ruby are not to be started with capital letter.

One can not just call an arbitrary method somewhere in the class hierarchy. Whether this was possible, the whole OOP would make absolutely no sense.

One might call the super method from within this method:

module Base
def hello
puts "Hello"
end
end

class Top
include Base

def initialize p
@p = p
end
def hello
if @p == 1
puts "hello from top"
else
super
end
end
def hi
hello
end
end

Top.new(1).hi
#⇒ hello from top
Top.new(2).hi
#⇒ Hello

or, one might declare the module function, a.k.a. static function and call it from everywhere:

module Base
def self.hello
puts "Hello"
end
end

class Top
# NOT NEEDED include Base
def hello
puts "hello from top"
end

def hi
if p == 1
hello
else
Base.hello
end
end
end

How to access method defined in a module inside another module in Ruby?

Assuming you don't want class level methods, you can also include the module into a class, instantiate an object of that class and call whoa:

class C
include A::B
end

c = C.new
c.whoa
# Whoa!

How to access parent/sibling module methods

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.

Access module method directly without operator ('.' or '::')

Try running it like this

module Example
def do_something
puts 'foo!'
end
end

include Example
do_something #=> foo!

Modules and Accessing Variables from Modules (Ruby Language)

When writing a module the convention is to declare constants like this:

module Week
FIRST_DAY = 'Sunday'
end

Note that they're in ALL_CAPS. Anything that begins with a capital letter is treated as a constant. Lower-case names of that sort are treated as local variables.

Generally it's bad form to access the constants of another module, it limits your ability to refactor how those are stored. Instead define a public accessor method:

module Week
def first_day
FIRST_DAY
end
end

Now you can call that externally:

Week.first_day

Note you can also change how that's implemented:

module Week
DAYS = %w[
Sunday
Monday
Tuesday
...
Saturday
]

def first_day
DAYS.first
end

extend self # Makes methods callable like Week.first_day
end

The nice thing about that is the first_day method does exactly the same thing, no other code has to change. This makes refactoring significantly easier. Imagine if you had to track down and replace all those instances to Week::FIRST_DAY.

There's some other things to note here. The first is that any time you call include on a module then you get the methods and constants loaded in locally. The second thing is when you define a mix-in module, be careful with your names to avoid potential conflict with the target class.

Since you've mixed it in, you don't need the namespace prefix, just calling first_day should do it.

Access class variables in a modules class and instance methods

When inside MyModule::ClassMethods, you're not inside MyModule and don't have access to @@a_class_variable. Here's a related question.

With an accessor, your code works fine :

module MyModule
@@a_class_variable = "lorem ipsum"

def self.a_class_variable
@@a_class_variable
end

def self.included(base)
base.extend ClassMethods
end

module ClassMethods
def a_class_method
MyModule.a_class_variable << " abc1"
end
end

# Use it in constructor
def initialize
@@a_class_variable << " abc2"
end

def an_instance_method
@@a_class_variable << " abc3"
end
end

class MyObject
include MyModule
end

my_object = MyObject.new
MyObject.a_class_method
p my_object.an_instance_method
#=> "lorem ipsum abc2 abc1 abc3"

As you noted in the comments, it exposes @@a_class_variable to the public.
Setting the method as private or protected wouldn't work in the above example, since ClassMethods and MyModule aren't related.

It might not be the cleanest solution, but you could use send to access the private method :

module MyModule
@@a_class_variable = 'lorem ipsum'

module ClassMethods
def a_class_method
MyModule.send(:__a_class_variable) << ' abc1'
end
end

# Use it in constructor
def initialize
@@a_class_variable << ' abc2'
end

def an_instance_method
@@a_class_variable << ' abc3'
end

class << self
def included(base)
base.extend ClassMethods
end

private

def __a_class_variable
@@a_class_variable
end
end
end

How to access class method from the included hook of a Ruby module

There'a a method_added callback you could use:

module MyModule
def self.included(includer)
def includer.method_added(name)
puts "Method added #{name.inspect}"
end
end
end

class MyClass
include MyModule

def foo ; end
end

Output:

Method added :foo

If you want to track both, existing and future methods, you might need something like this:

module MyModule
def self.on_method(name)
puts "Method #{name.inspect}"
end

def self.included(includer)
includer.instance_methods(false).each do |name|
on_method(name)
end

def includer.method_added(name)
MyModule.on_method(name)
end
end
end

Example:

class MyClass
def foo ; end

include MyModule

def bar; end
end

# Method :foo
# Method :bar


Related Topics



Leave a reply



Submit