避免从模块调用私有方法

Avoid calling private method from module

提问人:oczek.scala 提问时间:4/27/2022 更新时间:4/27/2022 访问量:137

问:

有没有可能在模块中制作私有方法? 我想防止从其他模块调用方法。

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
Ruby-on-Rails 方法 Ruby-on-Rails-5

评论


答:

1赞 Cary Swoveland 4/27/2022 #1

你可以写以下内容。

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

然后

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"

请参阅 Module#included。这是几种所谓的“钩子方法”之一。


假设如下。Z

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

然后

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

这表明原来的公共方法已设为私有。注意:Z#print_name

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