我有两个问题
最佳实践
这些是我能看到的选项,哪个最好?:
技术部分
有没有办法制作私有模块方法?
module Thing
def self.pub; puts "Public method"; end
private
def self.priv; puts "Private method"; end
end
private
似乎没有任何影响,我仍然可以毫无问题地致电Thing.priv
。
答案 0 :(得分:84)
我认为最好的方式(以及主要是如何编写现有的lib)通过在模块中创建一个处理所有逻辑的类来实现这一点,并且模块只是提供了一种方便的方法,例如
module GTranslate
class Translator
def perform( text ); 'hola munda'; end
end
def self.translate( text )
t = Translator.new
t.perform( text )
end
end
答案 1 :(得分:72)
还有Module.private_class_method
,可以说表达了更多的意图。
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
答案 2 :(得分:35)
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)
答案 3 :(得分:28)
当混合使用模块时,你可以使用“included”方法做一些奇特的事情。这就是你想要的想法:
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
答案 4 :(得分:12)
不幸的是,private
仅适用于实例方法。在类中获取私有“静态”方法的一般方法是执行以下操作:
class << self
private
def foo()
....
end
end
不可否认,我没有在模块中这样做过。
答案 5 :(得分:2)
一个好方法就是这样
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
答案 6 :(得分:2)
The best pattern that I've found by doing this in Rails is to give up on modules that want to have private methods and use a Singleton class instead. It doesn't feel right but it does work and seems cleaner that then other examples I've seen in this question.
Would love to hear other opinions on this.
Example:
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
答案 7 :(得分:1)
在类变量/常量中将方法存储为lambda是什么意思?
module MyModule
@@my_secret_method = lambda {
# ...
}
# ...
end
进行测试:
UPD:6年后对此代码的大量更新显示了声明私有方法的更简洁方法d
module A
@@L = lambda{ "@@L" }
def self.a ; @@L[] ; end
def self.b ; a ; end
class << self
def c ; @@L[] ; end
private
def d ; @@L[] ; end
end
def self.e ; c ; end
def self.f ; self.c ; end
def self.g ; d ; end
def self.h ; self.d ; end
private
def self.i ; @@L[] ; end
class << self
def j ; @@L[] ; end
end
public
def self.k ; i ; end
def self.l ; self.i ; end
def self.m ; j ; end
def self.n ; self.j ; end
end
for expr in %w{ A.a A.b A.c A.d A.e A.f A.g A.h A.i A.j A.k A.l A.m A.n }
puts "#{expr} => #{begin ; eval expr ; rescue => e ; e ; end}"
end
我们在这里看到:
A.a => @@L
A.b => @@L
A.c => @@L
A.d => private method `d' called for A:Module
A.e => @@L
A.f => @@L
A.g => @@L
A.h => private method `d' called for A:Module
A.i => @@L
A.j => @@L
A.k => @@L
A.l => @@L
A.m => @@L
A.n => @@L
1)@@L
不能从外部访问,但几乎可以从任何地方访问
2)class << self ; private ; def
成功地使方法d
无法从外部和内部使用self.
,但不是没有它 - 这很奇怪
3)private ; self.
和private ; class << self
不会将方法设为私有 - 无论是否有self.
答案 8 :(得分:0)
常量永远不会私有。但是,可以创建模块或类而不将其分配给常量。
因此:private_class_method
的替代方法是创建私有模块或类并在其上定义公共方法。
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的文档。
答案 9 :(得分:0)
除非您通过方法参数显式传递数据,否则该方法将不允许与私有方法共享数据。
module Thing
extend self
def pub
puts priv(123)
end
private
def priv(value)
puts "Private method with value #{value}"
end
end
Thing.pub
# "Private method with value 123"
Thing.priv
# NoMethodError (private method `priv' called for Thing:Module)
答案 10 :(得分:0)
这里有一个解决方案,说明如何将多个类嵌套在单个模块中,并能够通过使用 extend
调用模块上的私有方法,该方法可从任何嵌套类访问:< /p>
module SomeModule
class ClassThatDoesNotExtendTheModule
class << self
def random_class_method
private_class_on_module
end
end
end
class ClassThatDoesExtendTheModule
extend SomeModule
class << self
def random_class_method
private_class_on_module
end
end
end
class AnotherClassThatDoesExtendTheModule
extend SomeModule
class << self
def random_class_method
private_class_on_module
end
end
end
private
def private_class_on_module
puts 'some private class was called'
end
end
显示解决方案的一些输出:
> SomeModule::ClassThatDoesNotExtendTheModule.random_class_method
NameError: undefined local variable or method `private_class_on_module' for SomeModule::ClassThatDoesNotExtendTheModule:Class
> SomeModule::ClassThatDoesExtendTheModule.random_class_method
some private class was called
> SomeModule::ClassThatDoesExtendTheModule.private_class_on_module
NoMethodError: private method `private_class_on_module' called for SomeModule::ClassThatDoesExtendTheModule:Class
> SomeModule::AnotherClassThatDoesExtendTheModule.random_class_method
some private class was called
> SomeModule::AnotherClassThatDoesExtendTheModule.random_class_method
NoMethodError: private method `private_class_on_module' called for SomeModule::AnotherClassThatDoesExtendTheModule:Class