9

メソッドの欠落を拡張するモジュールがいくつかあります。

module SaysHello
    def respond_to?(method)
        super.respond_to?(method) || !!(method.to_s =~ /^hello/)
    end
    def method_missing(method, *args, &block)
        if (method.to_s =~ /^hello/)
            puts "Hello, #{method}"
        else
            super.method_missing(method, *args, &block)
        end
    end
end

module SaysGoodbye
    def respond_to?(method)
        super.respond_to?(method) || !!(method.to_s =~ /^goodbye/)
    end
    def method_missing(method, *args, &block)
        if (method.to_s =~ /^goodbye/)
            puts "Goodbye, #{method}"
        else
            super.method_missing(method, *args, &block)
        end
    end
end

class ObjectA
    include SaysHello
end

class ObjectB
    include SaysGoodbye
end

これはすべてうまく機能しObjectA.new.hello_thereます"Hello, hello_there"。同様に、ObjectB.new.goodbye_xxx出力します"Goodbye, xxx"respond_to?も機能します。たとえば、ObjectA.new.respond_to? :hello_theretrue を返します。

SaysHelloただし、 と の両方を使用する場合、これはうまく機能しませんSaysGoodbye

class ObjectC
    include SaysHello
    include SaysGoodbye
end

ObjectC.new.goodbye_aaa正しく動作しますが、ObjectC.new.hello_a奇妙な動作をします:

> ObjectC.new.hello_aaa
Hello, hello_aaa
NoMethodError: private method `method_missing' called for nil:NilClass
    from test.rb:22:in `method_missing' (line 22 was the super.method_missing line in the SaysGoodbye module)

正しく出力され、エラーがスローされます。またrespond_to?、正しくない場合ObjectC.new.respond_to? :hello_aは false を返します。

最後に、このクラスを追加します。

class ObjectD
    include SaysHello
    include SaysGoodbye

    def respond_to?(method)
        super.respond_to?(method) || !!(method.to_s =~ /^lol/)
    end


    def method_missing(method, *args, &block)
        if (method.to_s =~ /^lol/)
            puts "Haha, #{method}"
        else
            super.method_missing(method, *args, &block)
        end
    end
end

怪しい行動も。ObjectD.new.lol_zzz動作しますが、ObjectD.new.hello_aand ObjectD.new.goodbye_tは両方とも、正しい文字列を出力した後に名前の例外をスローします。respond_to?hello および goodbye メソッドでも失敗します。

これをすべて正しく機能させる方法はありますか? method_missing、 モジュール 、がどのように相互作用しているかについての説明superも非常に役立ちます。

編集: coreyward が問題を解決しsuper.<method-name>(args...)ました。定義したすべてのメソッドの代わりに super を使用すると、プログラムは正しく動作します。これがなぜなのかわからないので、これについて別の質問をしましたsuper.<method-name> do in ruby​​?

4

2 に答える 2

5

メソッドを再定義すると、メソッドが再定義されます。限目。

メソッド defineで 2 番目のモジュールをインクルードするときに行っていることはmethod_missing、以前に定義された をオーバーライドすることmethod_missingです。再定義する前にエイリアスを付けることで保持できますが、注意が必要な場合があります。

また、なぜ電話をかけているのかわかりませんsuper.method_missing。定義がトリックから外れたらmethod_missing、呼び出しを処理する方法を探してチェーンを続けられることを Ruby に知らせるsuper必要があります (引数を渡したり、メソッド名を指定したりする必要はありません)。

スーパーについて(アップデート)

Rubyを呼び出すsuperと、呼び出されたメソッドの次の定義を探して継承チェーンを進み、見つかった場合はそれを呼び出して応答を返します。呼び出すときは、 への応答でメソッドを呼び出しsuper.method_missingます。method_missingsuper()

この(ややばかげた)例を見てみましょう:

class Sauce
  def flavor
    "Teriyaki"
  end
end

# yes, noodles inherit from sauce:
#   warmth, texture, flavor, and more! ;)
class Noodle < Sauce
  def flavor
    sauce_flavor = super
    "Noodles with #{sauce_flavor} sauce"
  end
end

dinner = Noodle.new
puts dinner.flavor     #=> "Noodles with Teriyaki sauce"

super は他のメソッドと同じようにメソッドであることがわかります。これは、舞台裏で何らかの魔法を実行するだけです。「てりやき」は文字列なので、super.classここで呼び出すとが表示されます。String

今、理にかなっていますか?

于 2011-06-16T02:33:49.757 に答える