gensym

プログラミングと読書、勉強に関するメモ

メタプログラミングRuby その5 [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

3.3 method_missing
ruby オブジェクトがメソッドを呼び出すと、継承チェーンに沿ってメソッドを探索し、見つからなければもとのオブジェクトの method_missing メソッドが呼び出される。
この辺りが他の言語でどうなっているのかは知らないが、ruby ではあくまで method_missing メソッドが呼び出されてからそのメソッドがエラーを返している。
そしてメソッドはオーバーライドが可能なので、method_missing も上書きが出来ると言うことになる。

class Dog
  def method_missing(method, *args)
    puts "called : #{method}(#{args.join(', ')})"
    puts "block" if block_given?
  end
end

hachi = Dog.new
hachi.meow(2) do
  # block
end

# -> called : meow(2)
#    block

method_missing をオーバーライドすることで、メソッドの呼び出しをここに集めることが可能になる。
ビットコインAPIruby から呼び出す際の手本としてこのやり方が使われていた。

# https://en.bitcoin.it/wiki/API_reference_%28JSON-RPC%29#Ruby
require 'net/http'
require 'uri'
require 'json'

class BitcoinRPC
  def initialize(service_url)
    @uri = URI.parse(service_url)
  end

  def method_missing(name, *args)
    post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
    resp = JSON.parse( http_post_request(post_body) )
    raise JSONRPCError, resp['error'] if resp['error']
    resp['result']
  end

# ...

以前見たときは何をしているのかがよく分からなかったが、ようやく理解できた。
ここでは BitcoinRPC オブジェクトが api に存在するメソッドを呼び出したとき、method_missing において捕捉され、外部のサーバにリクエストを投げ、結果かエラーを返している。
これにより個々の api に対応するメソッドを書く必要がなくなっている。

かなり過激なやり方だ。
method_missing のようなメソッドを書き換えるのはなにか聖人の墓を暴くような感じがするし、直感的に非効率なように思える。
その反面実行時にしか分からないような事にも対応できる柔軟性は見過ごせない。
api が数百有ってしょっちゅう変更されるような場合でも楽に対応できるだろう。
まさしく黒魔術だ。