【Ruby】ネストしたStructをスマートに書きたい
2021/06/11
response.data.solution.status #=> 'ACTIVE'
テストでこんな感じのモックが欲しくて、ネストしたStructをスマートに書く方法がないか調べた
response = Struct.new(:data).new(Struct.new(:solution).new(Struct.new(:status).new('ACTIVE')))
#=> #<struct data=#<struct solution=#<struct status="ACTIVE">>>
response.data.solution.status
#=> "ACTIVE"
普通に書いたら、なにこれひどいなって感じになった
solution = Struct.new(:status).new('ACTIVE')
data = Struct.new(:solution).new(solution)
response = Struct.new(:data).new(data)
変数に入れたら一応読みやすくはなるけど、スマートではない
調査結果
3種類の書き方が見つかった
1. 標準ライブラリ(ostruct)を使う
require 'ostruct'
response = OpenStruct.new({ data: { solution: { status: 'ACTIVE' } } })
#=> #<OpenStruct data={:solution=>{:status=>"ACTIVE"}}>
response.data[:solution][:status]
#=> "ACTIVE"
スマートに書けるけど、2階層以降はHashになってる
2. Gem(recursive-open-struct)を追加する
require 'recursive-open-struct'
response = RecursiveOpenStruct.new({ data: { solution: { status: 'ACTIVE' } } })
#=> #<RecursiveOpenStruct data={:solution=>{:status=>"ACTIVE"}}>
response.data.solution.status
#=> "ACTIVE"
求めてたスマートさで書けた
ただ、Gemを追加しないといけないのが難点
3. JSON.parseとostructを使う
require 'json'
require 'ostruct'
response = JSON.parse({ data: { solution: { status: 'ACTIVE' } } }.to_json, object_class: OpenStruct)
#=> #<OpenStruct data=#<OpenStruct solution=#<OpenStruct status="ACTIVE">>>
response.data.solution.status
#=> "ACTIVE"
Gemを追加しないで書けるけど、果たしてこれはスマートなのか?ってなった
結論
実用的なのはこの2つ
-
- Gem(recursive-open-struct)を追加する
-
- JSON.parseとostructを使う
Gemを追加しても問題ないのならrecursive-open-structを使うのがいいのかな
Hashクラスにモンキーパッチを当ててやるのもありかもしれない
require 'json'
require 'ostruct'
class Hash
def to_o
JSON.parse to_json, object_class: OpenStruct
end
end
response = { data: { solution: { status: 'ACTIVE' } } }.to_o
#=> #<OpenStruct data=#<OpenStruct solution=#<OpenStruct status="ACTIVE">>>
response.data.solution.status
#=> "ACTIVE"