Jignesh Gohel
Jignesh Gohel

Reputation: 6552

Ruby module_function, invoking module's private method, invoked in class method style on module shows error

test_module.rb

  module MyModule
    def module_func_a
      puts "module_func_a invoked"
      private_b
    end

    module_function :module_func_a

    private
    def private_b
      puts "private_b invoked"
    end
  end

  class MyClass
    include MyModule
    def test_module
      module_func_a
    end
  end

Invoking module function from class

  c = MyClass.new
  c.test_module

Output 1:

$ ruby test_module.rb 
 module_func_a invoked
 private_b invoked

Invoking module function on module in class method style

ma = MyModule.module_func_a

Output 2:

 module_func_a invoked
 test_module.rb:5:in `module_func_a': undefined local variable or method `private_b' for MyModule:Module (NameError)
 from test_module.rb:31

As can be seen from the Output 1 and Output 2 when including the module in a class, no issue occurs when a module's private method gets invoked from a module function while in case when directly invoking the module function on the module in class method style the module's private method, invoked from module function, is not found.

Can anybody make me understand the reason behind above behavior and whether invoking module function (which in turn invokes module's private method) on module in class method style is possible or not? If possible, then what rectifications are required in my code to do the same?

Upvotes: 9

Views: 6770

Answers (2)

psyho
psyho

Reputation: 7212

It works when you include the module in a class, because then all of the module's methods get included in that class (the self in module_func_a points to MyClass, which has also the private_b method).

In the other situation self points to MyModule, which does not have private_b method. If you wanted it to work both ways, you'd have to either declare private_b as a module method as well, or simply add the line extend self to MyModule, so that all it's methods would become module methods.

Upvotes: 8

Vincent Robert
Vincent Robert

Reputation: 36120

module_function does copy your module_func_a into the metaclass but not its dependencies.

So when calling module_func_a from an object, you get the other method private_b. But calling it on the module itself fails because private_b is not a module function.

You should use module_function for private_b too and it should work.

Upvotes: 3

Related Questions