これは .ごっ!のアドベントカレンダー の19日目の記事です。
RubyのHashのキー名をメソッド名として扱うときの備忘録です。
例えば、 h = {num: 42} があったときに h.num で42を取得したいといったときです。
Rubyの Hash#fetch と method_missing をいい具合に利用します。
class Hash
def method_missing(m)
fetch(m) { fetch(m.to_s) { super } }
end
end
h = {num: 42, str: "string", first_hash: { second_hash: "second_hash_str" }}
p h.num # => 42
p h.str # => "string"
p h.first_hash.second_hash # => "second_hash_str"
p h.string # => undefined method 'string' for {....}:Hash (NoMethodError)
この method_missing() は Hashにそのメソッドが定義されていなかった時に呼び出されるメソッドで、引数の m は呼び出そうとしたメソッド名のSymbolが渡ります。
fetch() はキーに関連付けられた値を返すメソッドです。キーがない場合はブロックの実行結果が返されます。
それぞれの詳しい内容はリファレンスマニュアルを読んでください。
https://docs.ruby-lang.org/ja/3.1/method/BasicObject/i/method_missing.html
https://docs.ruby-lang.org/ja/3.1/method/Hash/i/fetch.html
上記にあるコードを順番に読み解きます。
-
h.numの場合-
method_missingにm = :numが渡る。 -
fetch(:num)でhには:numのキーがあるのでその値を返す。-
h.stringの場合 -
method_missingにm = :stringが渡る。 -
fetch(:string)でhには:stringのキーが存在しないのでブロックの中身が実行される。 -
m.to_sした結果がfetchされるので、fetch("string")となるがhには"string"のキーが存在しないのでブロックの中身が実行される。 -
superで実際のmethod_missingが実行される。
-
-
良さげな使い方としては、 APIリクエストしてJSONを受け取った時にメソッドっぽく値を取り出すことができ、きれいなコードを書いているように見えることです。
以下サンプルコードです。
require 'faraday'
class Hash
def method_missing(m)
fetch(m) { fetch(m.to_s) { super } }
end
end
conn = Faraday::new({url: "https://api.nasa.gov"}) do |c|
c.request :json
c.response :json
c.adapter Faraday.default_adapter
end
res = conn.send(:get, "/planetary/apod", { api_key: "DEMO_KEY" }, nil)
p res.body.copyright # => "Craig Stocks"
p res.body.title # => "The Tadpole Nebula in Gas and Dust"
このコードでは faraday を使用していますが、httpリクエストの方法はなんでもよいです。
lostisland
/
faraday
Simple, but flexible HTTP client library, with support for multiple backends.
Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle Take a look at Awesome Faraday for a list of available adapters and middleware.
Why use Faraday?
Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses, making it easier to build sophisticated API clients or web service libraries that abstract away the details of how HTTP requests are made.
Faraday comes with a lot of features out of the box, such as:
- Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
- Persistent connections (keep-alive)
- Parallel requests
- Automatic response parsing (JSON, XML, YAML)
- Customization of the request/response cycle with middleware
- Support for streaming responses
- Support for uploading files
- And much more!
Getting Started
The best starting point is the Faraday Website, with…
レスポンスbodyの中身をまるでメソッドかのように値を取得しています。
上記のコードは万能ではありません。 Hash のインスタンスメソッドにあるメソッド名がキー名と同じだった場合、インスタンスメソッドが優先されます。({dig: "dig_string"} とあった場合は、method_missingではないので Hash#dig が優先されるということです。)
小さい個人ツールやgemとして使う分には便利ではありますが、大きいプロダクトに適用させる場合には注意しましょう。
Top comments (0)