From adf03bca9aeb62899654ef92ac42ec46fe3bdf6e Mon Sep 17 00:00:00 2001 From: Paul Kmiec Date: Fri, 30 Oct 2020 15:33:24 -0700 Subject: [PATCH] allow user to specify container and / or superclass Co-authored-by: Mischa Lewis-Norelle --- README.md | 18 ++++++++++++++++++ lib/json-api-vanilla/parser.rb | 9 +++------ spec/json-api-vanilla/diff_spec.rb | 11 +++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3183ef9..7ac217e 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,24 @@ fields: - `keys` is a Hash from objects to a Hash from their original field names (non-snake\_case'd) to the corresponding object. +## User Defined Data Objects + +Deserializing will automatically create the necessary Ruby objects based on the json api structure. These Ruby objects inherit from an autogenerated superclass and will be placed in an autogenerated container Module. + +However, it is possible for the user to specify the container and / or the superclass like so, +```ruby +module Api + module Resources + class Base + end + end +end + +JSON::Api::Vanilla.parse(json_string, container: Api::Resources, superclass: Api::Resources::Base) +``` + +There are 2 reasons why this is useful. The first reason is that it allows the Ruby object to define some additional methods that make it more convenient to interact with the object. For example, say the api returns an object of type persons with first name and last name as attributes. We could define a Persons class which defines `def name; [first, last].join(' '); end`. The second reason is that dynamically creating classes / methods in Ruby kills internal caching, so by reusing existing classes we gain a bit of performance and memory. + # License Copyright © Trainline.com Limited. All rights reserved. See LICENSE.txt in the project root for license information. diff --git a/lib/json-api-vanilla/parser.rb b/lib/json-api-vanilla/parser.rb index 0140b85..8a353a0 100644 --- a/lib/json-api-vanilla/parser.rb +++ b/lib/json-api-vanilla/parser.rb @@ -15,9 +15,9 @@ class InvalidRootStructure < StandardError; end # # @param json [String] the JSON API payload. # @return [JSON::Api::Vanilla::Document] a wrapper for the objects. - def self.parse(json) + def self.parse(json, container: Module.new, superclass: Class.new) hash = JSON.parse(json) - build(hash) + build(hash, container: container, superclass: superclass) end # Convert a ruby hash JSON API representation to vanilla Ruby objects. @@ -31,11 +31,8 @@ def self.parse(json) # # @param hash [Hash] parsed JSON API payload. # @return [JSON::Api::Vanilla::Document] a wrapper for the objects. - def self.build(hash) + def self.build(hash, container: Module.new, superclass: Class.new) naive_validate(hash) - # Object storage. - container = Module.new - superclass = Class.new data_hash = hash['data'] data_hash_array = if data_hash.is_a?(Array) diff --git a/spec/json-api-vanilla/diff_spec.rb b/spec/json-api-vanilla/diff_spec.rb index 62e948c..188289d 100644 --- a/spec/json-api-vanilla/diff_spec.rb +++ b/spec/json-api-vanilla/diff_spec.rb @@ -135,6 +135,17 @@ end.to_not raise_error end + it "should use user specified container and superclass" do + my_container = Module.new + my_superclass = Class.new + my_commentsclass = Class.new(my_superclass) + my_container.const_set("Comments", my_commentsclass) + + doc = JSON::Api::Vanilla.parse(IO.read("#{__dir__}/example.json"), container: my_container, superclass: my_superclass) + expect(doc.data[0].class.superclass).to eql(my_superclass) + expect(doc.data[0].comments[0].class).to eql(my_commentsclass) + end + describe '.prepare_class' do let(:container) {Module.new} let(:superclass) {Class.new}