Ruby中的私有模块方法
我有两个部分的问题
最佳实践
- 我有一个algorithm,使用公共接口对数据结构执行一些操作
- 它目前是一个拥有众多静态方法的模块,除了一个公共接口方法外,都是私有的。
- 有一个实例variables需要在所有方法之间共享。
这些是我可以看到的选项,哪个最好?
- 模块与静态(ruby模块)的方法
- 类与静态方法
- Mixin模块包含在数据结构中
- 重构出修改该数据结构的algorithm部分(非常小),并调用一个调用algorithm模块静态方法的mixin
技术部分
有没有办法做一个私人的模块方法 ?
module Thing def self.pub; puts "Public method"; end private def self.priv; puts "Private method"; end end
那里的private
似乎没有任何影响 ,我仍然可以叫Thing.priv
没有问题。
我认为最好的方式(主要是如何编写现有的库)是通过在处理所有逻辑的模块中创build一个类来实现的,模块只是提供一个方便的方法,例如
module GTranslate class Translator def perform( text ); 'hola munda'; end end def self.translate( text ) t = Translator.new t.perform( text ) end end
还有Module.private_class_method
,可以expression更多的意图。
module Foo def self.included(base) base.instance_eval do def method_name # ... end private_class_method :method_name end end end
对于问题中的代码:
module Thing def self.pub; puts "Public method"; end def self.priv; puts "Private method"; end private_class_method :priv end
Ruby 2.1或更新版本:
module Thing def self.pub; puts "Public method"; end private_class_method def self.priv; puts "Private method"; end end
你可以使用“包含”的方法做一些混合模块时的花哨的东西。这就是你想要的东西,我想:
module Foo def self.included(base) class << base def public_method puts "public method" end def call_private private_method end private def private_method puts "private" end end end end class Bar include Foo end Bar.public_method begin Bar.private_method rescue puts "couldn't call private method" end Bar.call_private
module Writer class << self def output(s) puts upcase(s) end private def upcase(s) s.upcase end end end Writer.output "Hello World" # -> HELLO WORLD Writer.upcase "Hello World" # -> so.rb:16:in `<main>': private method `upcase' called for Writer:Module (NoMethodError)
不幸的是, private
只适用于实例方法。 在一个类中获得私有“静态”方法的一般方法是做如下的事情:
class << self private def foo() .... end end
诚然,我还没有玩过这个模块。
一个好方法就是这样
module MyModule class << self def public_method # you may call the private method here tmp = private_method :public end private def private_method :private end end end # calling from outside the module puts MyModule::public_method
我在Rails中发现的最好的模式就是放弃那些想要私有方法并使用Singleton类的模块。 它感觉不对,但它确实起作用,并且看起来比我在这个问题中看到的其他例子更清洁。
很想听到其他意见。
例:
ErrorService.notify("Something bad happened") class ErrorService include Singleton class << self delegate :notify, to: :instance end def notify(message, severity: :error) send_exception_notification(message) log_message(message, severity) end private def send_exception_notification(message) # ... end def log_message(message, severity) # ... end end
制作私人模块或课程
常量永远不是私有的。 但是,可以创build一个模块或类,而不必将其分配给常量。
因此, :private_class_method
的另一种方法是创build一个私有模块或类,并在其上定义公共方法。
module PublicModule def self.do_stuff(input) @private_implementation.do_stuff(input) end @private_implementation = Module.new do def self.do_stuff(input) input.upcase # or call other methods on module end end end
用法:
PublicModule.do_stuff("whatever") # => "WHATEVER"
查看Module.new和Class.new的文档。
在类variables/常量中将方法存储为lambdas是什么?
module MyModule @@my_secret_method = lambda { # ... } # ... end
testing:
module A @@C = lambda{ puts "C" } def self.B ; puts "B"; @@C[] ; end private # yeah, this has no sense, just for experiment def self.D ; puts "D"; @@C[] ; end end for expr in %w{ A::B AB A::C AC A::D AD } eval expr rescue puts expr end
这里我们看到C可以被B和D成功使用,但是不能从外部使用。