Rubyでは、ここに示すようにmodule_function
を使用することで、モジュールを混合せずにモジュール関数を使用できることを理解しています。これがどのように役立つかがわかるので、モジュール内で混合することなく関数を使用できます。
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
私の質問は、なぜこれらの両方の方法で関数を定義したいのかということです。
なぜ持っていないのですか
def MyModule.do_something
OR
def do_something
どのような場合に、関数を混合したり、静的メソッドとして使用したりできるのが便利でしょうか?
Enumerable と考えてください。
これは、モジュールに含める必要がある場合の完璧な例です。クラスで#each
を定義している場合、モジュール(#map
、#select
など)を含めるだけで多くの利点が得られます。これは、モジュールをミックスインとして使用する場合の唯一のケースです。モジュールが、そのモジュールをインクルードするクラスで定義されたいくつかのメソッドに関して機能を提供する場合です。これが一般的な唯一のケースであるべきだと主張できます。
「静的」メソッドの定義に関して、より良いアプローチは次のとおりです。
module MyModule
def self.do_something
end
end
#module_function
を呼び出す必要はありません。私はそれがただ奇妙な遺産のものだと思う。
これを行うこともできます:
module MyModule
extend self
def do_something
end
end
...しかし、モジュールをどこかに含めたい場合はうまくいきません。 Ruby metaprogramming。の微妙さを学ぶまで、それを避けることをお勧めします。
最後に、あなたがそうするだけなら:
def do_something
end
...最終的にはグローバル関数としてではなく、Object
のプライベートメソッドとして機能します(Rubyには関数はなく、メソッドのみです)。 2つの欠点があります。まず、名前空間がありません。同じ名前の別の関数を定義すると、後で評価される関数になります。第二に、#method_missing
に関して機能を実装している場合、Object
にプライベートメソッドがあると、それがシャドウされます。そして最後に、モンキーパッチObject
は単なる悪いビジネスです:)
編集:
module_function
は、private
と同様の方法で使用できます。
module Something
def foo
puts 'foo'
end
module_function
def bar
puts 'bar'
end
end
そうすれば、Something.bar
を呼び出すことができますが、Something.foo
を呼び出すことはできません。このmodule_function
の呼び出し後に他のメソッドを定義すると、それらは混ざることなく使用できます。
ただし、2つの理由で好きではありません。第一に、両方が混在し、「静的」メソッドを備えたモジュールは少し危険です。有効なケースがあるかもしれませんが、それほど頻繁ではありません。先ほど言ったように、私はモジュールを名前空間として使用するか、または混在させることを好みますが、両方は使いません。
第二に、この例では、bar
は、Something
が混在するクラス/モジュールでも使用できます。メソッドがself
を使用しており、混合する必要があるか、そうでない場合は混合する必要がないため、これがいつ望ましいかはわかりません。
メソッドの名前を渡さずにmodule_function
を使用することは、使用するよりもかなり頻繁に使用されると思います。 private
とprotected
についても同様です。
これは、Rubyライブラリが(多くの)内部状態を使用しない機能を提供するための良い方法です。したがって、sin
関数を提供し、汚染を望まない場合「グローバル」(Object
)名前空間、定数(Math
)の下でクラスメソッドとして定義できます。
ただし、数学アプリケーションを作成するアプリ開発者は、2行ごとにsin
を必要とする場合があります。メソッドがインスタンスメソッドでもある場合、彼女はMath
(またはMy::Awesome::Nested::Library
)モジュールを含めるだけで、sin
(stdlibの例)を直接呼び出すことができます。
それは本当にユーザーにとってライブラリをより快適にすることです。最上位のライブラリの機能が必要な場合は、自分で選択できます。
ところで、module_function
(モジュールの最初の行)を使用して、extend self
などの同様の機能を実現できます。私の考えでは、見た目が良くなり、理解しやすくなりました。
更新:このブログ記事 の詳細な背景情報。
実際の例をご覧になりたい場合は、慢性的な宝石をご覧ください。
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
ハンドラーは、ここのParserクラスに含まれています。
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
彼はmodule_functionを使用して、そのインスタンスのinvokeメソッドを使用して、ハンドラーからハンドラーの特定のインスタンスにメソッドを送信します。