やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

組込ライブラリ(Method)

 オブジェクト化したメソッド。

成果物

情報源

Method

Object#method によりオブジェクト化されたメソッドオブジェクトのクラスです。

メソッドの実体(名前でなく)とレシーバの組を封入します。 Proc オブジェクトと違ってコンテキストを保持しません。

 ローカル変数の参照はできない、という意味かな?

Proc との差

Method は取り出しの対象であるメソッドがなければ作れませんが、Proc は準備なしに作れます。その点から Proc は使い捨てに向き、Method は何度も繰り返し生成する場合に向くと言えます。また内包するコードの大きさという点では Proc は小規模、Method は大規模コードに向くと言えます。

既存のメソッドを Method オブジェクト化する。

class Foo
  def foo(arg)
    "foo called with arg #{arg}"
  end
end

m = Foo.new.method(:foo)

p m             # => #<Method: Foo#foo>
p m.call(1)     # => "foo called with arg 1"

名前のないメソッド(の代わり)が必要なら Proc を使うと良い。

pr = Proc.new {|arg|
  "proc called with arg #{arg}"
}

p pr            # => #<Proc:0x401b1fcc>
p pr.call(1)    # => "proc called with arg 1"

Method オブジェクトが有用なのは以下のような場合。

class Foo
  def foo() "foo" end
  def bar() "bar" end
  def baz() "baz" end
end

obj = Foo.new

# 任意のキーとメソッドの関係をハッシュに保持しておく
methods = {1 => obj.method(:foo),
           2 => obj.method(:bar),
           3 => obj.method(:baz)}

# キーを使って関連するメソッドを呼び出す
p methods[1].call       # => "foo"
p methods[2].call       # => "bar"
p methods[3].call       # => "baz"

しかし、レシーバを固定させる(Method オブジェクトはレシーバを保持する)必要がないなら Object#public_sendを使う方法も有用。

class Foo
  def foo() "foo" end
  def bar() "bar" end
  def baz() "baz" end
end

# 任意のキーとメソッド(の名前)の関係をハッシュに保持しておく
# レシーバの情報がここにはないことに注意
methods = {1 => :foo,
           2 => :bar,
           3 => :baz}

# キーを使って関連するメソッドを呼び出す
# レシーバは任意(Foo クラスのインスタンスである必要もない)
p Foo.new.public_send(methods[1])      # => "foo"
p Foo.new.public_send(methods[2])      # => "bar"
p Foo.new.public_send(methods[3])      # => "baz"

メンバ抜粋

インスタンスメソッド

<< == === >> [] arity call clone curry eql? hash 
inspect name original_name owner parameters receiver 
source_location super_method to_proc to_s unbind

対象環境

$ uname -a
Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux