はじめに
hkob の雑記録の第158回目は、Faraday の取得時にハッシュのキーを Symbol にする作業を解説します。
symbolize_names: true
昨日の「おわりに」に記載したように Faraday の response 変換時に symbolize_names を true にすることで JSON の parse した後のハッシュキーをシンボルにすることができるようです。早速、この部分を下の parser_options に変更しました。
conn.response :json # conn.response :json, parser_options: {symbolize_names: true}
この変更により、さまざまなテストが失敗するようになりました。当然ですね。これを一つずつ修正していきます。
WebMock のエラー表示
NotionRubyMapping のテストでは、実際に Notion API をアクセスすることはなく、WebMock を利用しています。一度、API アクセスした時の response の JSON を fixtures として取得しておき、WebMock でアクセスを偽装しています。この時、API の payload が異なると WebMock に登録されたものと一致しないため、エラーとなります。この際、テストログに登録済の stubs が registered request stubs: として出力され、ログが肥大化する問題がありました。テストのために大量の無駄なログが表示されるのは厳しいので、NetConnectNotAllowedError をオーバライドすることにしました。
具体的には spec/spec_helper.rb に以下の記述を追加しました。
module WebMock class NetConnectNotAllowedError < Exception def initialize(request_signature) super("Real HTTP connections are disabled. Please stub: #{request_signature}") end end end
この結果、失敗した時のエラーは以下のような形で出力されました。失敗した URL と body だけが表示されるので、だいぶスッキリしました。
WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Please stub: PATCH https://api.notion.com/v1/pages/206ffaa277744a99baf593e28730240c with body '{"properties":{"CheckboxTitle":{"checkbox":true,"type":"checkbox"},"DateTitle":{"type":"date","date":{"start":"2022-03-14","end":null,"time_zone":null}},... (以下省略)
テストの修正
テストはこんな感じの修正になりました。 set_icon のテストだとこんな感じになります。シンボルになることでだいぶスッキリ書けるようになります。
describe "set_icon" do before { payload.set_icon(**params) } + context "for emoji icon" do let(:params) { {emoji: "😀"} } + it "update icon (emoji)" do - is_expected.to eq({"icon" => {"type" => "emoji", "emoji" => "😀"}}) + expect(subject).to eq({icon: {type: :emoji, emoji: "😀"}}) end end
実装の修正
実装も同様に修正していきます。payload は symbol のままでも、JSON にする際には文字列になるので、問題ありません。また、各種ハッシュキーも全て symbol で設定するようにします。
def set_icon(emoji: nil, url: nil) payload = if emoji - {"type" => "emoji", "emoji" => emoji} + {type: :emoji, emoji: emoji} elsif url - {"type" => "external", "external" => {"url" => url}} + {type: :external, external: {url: url}} else {} end - @json["icon"] = payload + @json[:icon] = payload self end
おわりに
記述は簡単になったのですが、流石にページの修正量が多いので、まだ全て完了しているわけではありません。まずは現状のテストが全て通過するところまで持っていきます。ただ、明日までに終わるか不明です。もし、終わらなかった場合は現在考えている FileObject の構想をまとめてみたいと思います。