2012-07-18 7 views
39

ルビーでは、ここに示すように、モジュール内で混合することなくモジュールの機能をmodule_functionで利用できるようになったことを理解しています。これがどのように役立つのか分かりますので、モジュールでミキシングせずにこの機能を使用することができます。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 

を持っていないのはなぜ?

答えて

35

考えてみてくださいEnumerable

これはモジュールに組み込む必要がある場合の完全な例です。あなたのクラスが#eachを定義している場合は、モジュール(#map#selectなど)を含めるだけで、多くの利点が得られます。これは、モジュールをmixinとして使用する唯一のケースです。モジュールがいくつかのメソッドの面で機能を提供するとき、それをモジュールに含めます。私はこれが一般的な唯一のケースであるべきだと主張することができます。 「静的」メソッドを定義するよう

、より良いアプローチは次のようになります。あなたは本当に#module_functionを呼び出す必要はありません

module MyModule 
    def self.do_something 
    end 
end 

。私はそれが単なる奇妙な遺産だと思う。

module MyModule 
    extend self 

    def do_something 
    end 
end 

を...しかし、あなたはまた、どこかのモジュールを含める場合、それはうまく動作しません。

あなたも、これを行うことができます。あなたがRubyメタプログラミングの微妙なことを学ぶまでは避けることをお勧めします。

最後に、あなただけ行う場合:

def do_something 
end 

は...それはグローバル関数として終わることはありませんが、 Objectのプライベートメソッドとして(何の機能は、Rubyでちょうど方法はありません)。 2つの欠点があります。まず、名前空間がありません。同じ名前の別の関数を定義すると、それは後で評価されます。第二に、 #method_missingの機能を実装している場合は、 Objectにプライベートメソッドを設定すると、それがシャドーされます。そして最後に、 Objectにパッチを適用猿はただ悪ビジネスです:)

EDIT:

module_functionprivateと同様の方法で使用することができます。

module Something 
    def foo 
    puts 'foo' 
    end 

    module_function 

    def bar 
    puts 'bar' 
    end 
end 

そのように、あなたはSomething.barを呼び出すことはできませんが、ないSomething.foo。この呼び出しの後に他のメソッドを定義した場合、それらは混在することなく利用できます。

私は2つの理由でそれを好きではありません。第一に、混在していて、静的な方法を持っているモジュールは少しばかげて聞こえます。妥当なケースがあるかもしれませんが、それほど頻繁ではありません。私が言ったように、私はモジュールを名前空間として使うか、それを混在させる方が好きですが、両方ではありません。

第2に、barは、Somethingに混在するクラス/モジュールでも使用できます。この方法が望ましいかどうかわからないのは、メソッドがselfを使用していて、混在する必要があるか、または混在する必要がないからです。メソッドの名前は、より頻繁に使用されます。 privateprotectedについても同じです。

+0

説明のためにありがとう。私はなぜあなたがモジュールで混在したいと思うのか理解しています。私の質問は実際にmodule_functionを実際に使用するかもしれないときです。あなたが実際にそれを使うかもしれませんか? –

+2

最後の例では、 'module_function'を使ってもう1つのキャッチがあります:' foo'はインスタンスメソッドです( 'self'はありません)ので、' private'関数 'foo'は' bar'の内部からアクセスできません。このモジュールがいくつかのクラスで混在している場合にのみ呼び出すことができます。ネームスペースの目的のためだけにスタンドアロンのモジュールである場合は不可能です。それで、どうやって両方持っているの?モジュールを名前空間に使用する方法と、外部から実装ヘルパー関数を隠す方法はありますが、それらをインターフェイスメソッドで呼び出すことはできますか? – SasQ

12

これはRubyライブラリが(多くの)内部状態を使用しない機能を提供するための良い方法です。たとえば、sin関数を提供したいが、 "グローバル"(Object)名前空間を汚染したくない場合は、定数(Math)の下でクラスメソッドとして定義することができます。

ただし、数学アプリケーションを作成するアプリのデベロッパーは、2行に1度にsinが必要になることがあります。メソッドがインスタンスメソッドでもある場合は、Math(またはMy::Awesome::Nested::Library)モジュールを含めるだけで、sin(stdlibの例)を直接呼び出すことができます。

実際には、ユーザーにとってより快適なライブラリを作成することです。彼らはトップレベルであなたのライブラリの機能を望むなら、彼ら自身を選択することができます。

ちなみにmodule_functionのような機能を実現するには、extend self(モジュールの最初の行)を使用します。私の心には、見た目が良くなり、理解するのが少しだけ明確になります。

更新:this blog articleの詳細情報。

+3

[ruby styleguide](https://github.com/bbatsov/ruby-style-guide#classes--modules)は、 '' extend self'よりも '' module_function''を好む – zhon

+3

ポインタをありがとう。私はそれに同意しない。 'module_function'は初心者には面白いかもしれませんが、Rubyを深刻に扱っている人は' extend self'を読んで理解できるはずです。 「拡張自己」はあまり抽象ではない。これはRubyの基本ツールセットを使用しますが、重要な機能を失うことなく 'module_function'をRubyから削除することができます。 –

+0

理由をお知らせいただきありがとうございます。このQ/Aを読む前に、私は '' self.method''と '' class << self''を使っていました。 – zhon

2

あなたが作業例を見たい場合は、慢性宝石チェックアウト:

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を使用して、そのインスタンスの呼び出しメソッドを使用してハンドラからハンドラの特定のインスタンスにメソッドを送信します。

関連する問題