Rubyのプライベートモジュールメソッド
-
11-07-2019 - |
質問
2部構成の質問があります
ベストプラクティス
- パブリックインターフェイスを使用してデータ構造に何らかの操作を実行するアルゴリズムがあります
- 現在、多数の静的メソッドを備えたモジュールであり、1つのパブリックインターフェイスメソッドを除き、すべてプライベートです。
- すべてのメソッドで共有する必要があるインスタンス変数が1つあります。
これらは私が見ることができるオプションで、どれが最良ですか?
- モジュール静的(Rubyでは「モジュール」)メソッド
- クラスと静的メソッド データ構造に含めるための
- Mixin モジュール
- リファクタリングそのデータ構造を変更するアルゴリズムの部分(非常に小さい)を取り除き、アルゴリズムモジュールの静的メソッドを呼び出すmixinを作成します
技術部分
プライベートモジュールメソッドを作成する方法はありますか?
module Thing
def self.pub; puts "Public method"; end
private
def self.priv; puts "Private method"; end
end
そこにあるprivate
は効果がないようです、Thing.priv
を問題なく呼び出すことができます。
解決
すべてのロジックを処理するモジュール内にクラスを作成することにより、これを行う最善の方法(および既存のライブラリの作成方法)を考えると、モジュールは便利なメソッドを提供するだけです。例えば、
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
もあり、これはおそらくより多くの意図を表します。
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 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)
<!> quot; included <!> quot;を使用できます。モジュールが混在しているときに派手なことをする方法
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
残念ながら、private
はインスタンスメソッドにのみ適用されます。プライベート<!> quot; static <!> quot;を取得する一般的な方法。クラス内のメソッドは次のようなことを行います:
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でこれを行うことで見つけた最良のパターンは、プライベートメソッドを持ち、代わりにシングルトンクラスを使用するモジュールを放棄することです。正しくないように感じますが、動作し、この質問で私が見た他の例よりもきれいに見えます。
これに関する他の意見を聞きたいです。
例:
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
クラス変数/定数内にラムダとしてメソッドを保存することはどうですか?
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
は、self.
を使用して外部および内部からメソッドprivate ; self.
に正常にアクセスできるようにしますが、それなしではできません-これは奇妙な
3)private ; class << self
および<=>はメソッドをプライベートにしません-<=>
プライベートモジュールまたはクラスを作成する
定数は決してプライベートではありません。ただし、モジュールまたはクラスを定数に割り当てずに作成することは可能です。
したがって、: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"