Effective Rubyを読んでいます(6)

tl;dr

「Effective Ruby」の項目30を読みました。

:arrow_down: 目次です。

  • 項目30 method_missingではなくdefine_methodを使うようにしよう

新しく知ったこと

method_missingを使用するとrespond_to?が正しい答えを出せなくなる(項目30)

method_missingを使用した場合、respond_to?が正しい答えを出せなくなります。

:arrow_down: にサンプルコードを示します。ArrayProxy.new.respond_to?(:length)trueをリターンすることを期待していますが、実際にはfalseがリターンされます。 これは、respond_to?はオブジェクトに定義されているかを判定するメソッドからです。ArrayProxyのオブジェクトは、lengthメソッドが定義されているように振る舞いますが、実際は@arrayへ処理を移譲しています。

class ArrayProxy
  def initialize
    @array = []
  end

  def method_missing(name, *args, &block)
    if @array.respond_to?(name)
      @array.send(name, *args, &block)
    else
      super
    end
  end
end

p ArrayProxy.new.respond_to?(:length) # => false

method_missingの替わりにdefine_methodを使用する解決作があります。

:arrow_down: に上記のコードとの差分を示します。

@@ -3,11 +3,9 @@ class ArrayProxy
     @array = []
   end

-  def method_missing(name, *args, &block)
-    if @array.respond_to?(name)
-      @array.send(name, *args, &block)
-    else
-      super
+  Array.public_instance_methods(false).each do |name|
+    define_method(name) do |*args, &block|
+      @array.send(name, *args, &blockru)
     end
   end
 end
 ```

以上です :end: