これは .ごっ!のアドベントカレンダー の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)