'Avoid calling private method from module

Is there any possibility to make private method in module ? I want to prevent to call method from other modules.

module A
    private
    
    def name # this method can be used in module B
        "name"
    end
end

module B
    def print_name
        puts name
    end
end

module C
    include A
    include B
end

class Z
    include C
end

Z.new.print_name # want to throw NoMethodError


Solution 1:[1]

You could write the following.

module A
  def name
    "name from A"
  end
end

module B
  def print_name
    "name from B"
  end
end

module C
  include A
  include B
  def self.included(klass)
    B.instance_methods(false).each { |m| klass.send(:private, m) }
  end
end

class Z
  include C
  def test
    print_name
  end
end

Then

Z.instance_methods.include?(:name)
  #=> true
Z.private_instance_methods.include?(:print_name)
  #=> true
z = Z.new
  #=> #<Z:0x00007fb0f810ad28>
z.name
  #=> "name from A"
z.print_name
  #=> NoMethodError: private method 'print_name' called for #<Z:0x00007fb0f810ad28>
z.test
  #=> "name from B"

See Module#included. This is one of several so-called "hook methods".


Suppose Z were as follows.

class Z
  def print_name
    "name from Z"
  end
  include C
  def test
    print_name
  end
end

Then

z.print_name
  #=> NoMethodError: private method 'print_name' called for #<Z:0x00007fb0f810ad28>
z.test
  #=> "name from Z"

This demonstrates that it is the original public method Z#print_name has been made private. Note:

C.ancestors
  #=> [Z, C, B, A, Object, Kernel, BasicObject]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1