Chiperific
Chiperific

Reputation: 4716

Rails json with keys that respond to method calls

I'm writing an RSpec test for some code that uses the Google API Client for Gmail.

When I query an email, I get back a Google::Apis::GmailV1::Message object.

For testing, I created a fixture file called 'gmail_message_spec.json' that replicates the important methods of the object, but as JSON:

{"id": "17d38b2e48f6fake",
 "payload":
  {"headers":
    [{"name": "MIME-Version", "value": "1.0"},
     {"name": "Date", "value": "Fri, 19 Nov 2021 09:56:27 -0500"},
     {"name": "Message-ID", "value": "<CAG4LXW=jEzKkfOLnE5jOSo7ertC=gAj-6GKE1qO=P8KB19fake@mail.gmail.com>"},
     {"name": "Subject", "value": "Make a simple message for testing"},
     {"name": "From", "value": "Test Person <[email protected]>"},
     {"name": "To", "value": "Test Person <[email protected]>"},
     {"name": "Content-Type", "value": "multipart/alternative; boundary=\"000000000000cc6f1d05d1257a61\""}],
   "mime_type": "multipart/alternative",
   "parts":
    [{"mime_type": "text/plain", "body": {"data": "This is a very simple message.\r\n"}},
     {"mime_type": "text/html", "body": {"data": "<div dir=\"ltr\">This is a very simple message.</div>\r\n"}}]},
 "snippet": "This is a very simple message."}

So, in my spec, I can load in this fixture as a demo response:

response = JSON.parse(File.read("#{Rails.root}/spec/fixtures/files/gmail_message_spec.json"), symbolize_names: true)

However, my code expects the response to be an object and tries to perform method calls:

response.payload.headers

Since the testing object is JSON, I'd need to access it like a hash:

response[:payload][:headers]

It seems my options are:

  1. Manually re-create the Google::Apis::GmailV1::Message object

  2. Write a bunch of stubs: allow(response).to receive(:payload).and return(response[:payload])

  3. Get the JSON to respond to methods as an object does.

I'm aiming for option #3 first. The other two options seem a bit tedious, especially #2.

Is there a way to get a Hash with deeply symbolized keys to allow for method calls that retrieve keys?

Instead of having to write this: response[:payload][:headers]

I want to write this: response.payload.headers

Upvotes: 0

Views: 270

Answers (1)

Chiperific
Chiperific

Reputation: 4716

Of course I just rubber ducked myself.

I can use OpenStruct: JSON.parse(File.read(), object_class: OpenStruct)

response = JSON.parse(File.read("#{Rails.root}/spec/fixtures/files/gmail_message_spec.json"), object_class: OpenStruct)

Thanks to Someth Victory and their very good Medium article from 2018.

Upvotes: 1

Related Questions