Skip to content

allow user to specify container and / or superclass #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
9 changes: 3 additions & 6 deletions lib/json-api-vanilla/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions spec/json-api-vanilla/diff_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down