json_objects 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +11 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +7 -0
- data/json_object.gemspec +23 -0
- data/lib/json_object.rb +203 -0
- data/lib/json_object/version.rb +3 -0
- data/spec/json_object_spec.rb +324 -0
- data/spec/spec_helper.rb +6 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a9dc2ff554538a1a27dfdef5d8b79c0c7dafb314
|
4
|
+
data.tar.gz: a818bb78f50fe251ba711fefaa084293d2fb73ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 08bc57e8de4bb9ef1c17cd31d6377ae33a1ec694ff1a66234058f4a650133d794f5b2e5b7ff0f87fa229bbb2f9d39efd2a7d22facc0fc9b32d6b14e65098cd79
|
7
|
+
data.tar.gz: e68f57a8c8b6d57d3babf2d70c5bb494465d15c1fa745f904d93a6cc512a79d7db8a745d367f9722718409a6d24d526807857fb9105a99aee5c433511558045f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Dave Vallance
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# JsonObject
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
See http://www.wisethinker.info/json-object/index for a quick description and more detailed information.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
## Ruby 2.0 dependent
|
12
|
+
|
13
|
+
I've used Ruby 2.0 keyword arguments. If theres a big demand for pre Ruby 2 support let me know ;)
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'json_object'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install json_object
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it ( https://github.com/[my-github-username]/json_object/fork )
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/json_object.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'json_object/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "json_objects"
|
8
|
+
spec.version = JsonObject::VERSION
|
9
|
+
spec.authors = ["Dave Vallance"]
|
10
|
+
spec.email = ["davevallance@gmail.com"]
|
11
|
+
spec.summary = %q{Instead of accessing JSON Hashs the usual way, this allows creating custom classes to represent and access the JSON values.}
|
12
|
+
spec.description = %q{Quickly build objects to represent, store and access JSON Hash values. You can control the accessor method names, default values and provide procs to do more complex computation.}
|
13
|
+
spec.homepage = "https://github.com/dvallance/json_object"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
data/lib/json_object.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
require "json_object/version"
|
2
|
+
require 'json'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
# The intended use of this module is for inclusion in a class, there by giving
|
6
|
+
# the class the necessary methods to store a JSON Hash and define custom accessors
|
7
|
+
# to retrieve its values.
|
8
|
+
#
|
9
|
+
# @example when including class has a no argument initializer
|
10
|
+
# class SomeClass
|
11
|
+
# include JsonObject
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example when the including class has an initializer with arguments
|
15
|
+
# class AnotherClass
|
16
|
+
# include JsonObject
|
17
|
+
#
|
18
|
+
# def initialize string
|
19
|
+
# # does something with string
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # we must override the default {#create} method as it will call
|
23
|
+
# # new() with no arguments on the class by default
|
24
|
+
#
|
25
|
+
# #this is the form it must take
|
26
|
+
# def self.create hash, parent=nil
|
27
|
+
# # here we imagine getting the initializer string param from the hash
|
28
|
+
# obj = new(hash["..."])
|
29
|
+
#
|
30
|
+
# # we must set the json_hash instance variable for proper functionality
|
31
|
+
# obj.json_hash = hash
|
32
|
+
#
|
33
|
+
# # optionally we can set the hash_parent variable
|
34
|
+
# obj.parent = parent
|
35
|
+
#
|
36
|
+
# #finnally we return our new object
|
37
|
+
# obj
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # same as above but using Object#tap for a cleaner implementation
|
41
|
+
# def self.create hash, parent=nil
|
42
|
+
# new(hash["..."]).tap do |obj|
|
43
|
+
# obj.json_hash = hash
|
44
|
+
# obj.parent = parent
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# end
|
49
|
+
module JsonObject
|
50
|
+
|
51
|
+
# A sane default class for use by {ClassMethods#object_accessor} when a custom
|
52
|
+
# class is not provided.
|
53
|
+
#
|
54
|
+
# Simply an OpenStruct object with our JsonObject module included.
|
55
|
+
#
|
56
|
+
# @see ClassMethods#object_accessor
|
57
|
+
class JsonOpenStruct < OpenStruct
|
58
|
+
include JsonObject
|
59
|
+
|
60
|
+
# Making sure we set our json_* attributes otherwise
|
61
|
+
def self.create hash, parent=nil
|
62
|
+
new(hash).tap do |obj|
|
63
|
+
obj.parent = parent
|
64
|
+
obj.json_hash = hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# JsonObject class methods
|
70
|
+
class << self
|
71
|
+
|
72
|
+
# Allows setting a custom class to replace the default JsonOpenStruct.
|
73
|
+
def default_json_object_class= klass
|
74
|
+
@default_json_object_class = klass
|
75
|
+
end
|
76
|
+
|
77
|
+
# Retrieve a set default class or use our JsonOpenStruct default.
|
78
|
+
def default_json_object_class
|
79
|
+
@default_json_object_class || JsonObject::JsonOpenStruct
|
80
|
+
end
|
81
|
+
|
82
|
+
def create
|
83
|
+
Class.new.include(JsonObject)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Callback runs when module is included in another module/class.
|
88
|
+
#
|
89
|
+
# We use this to automatically extend our ClassMethods module in a
|
90
|
+
# class that includes JsonObject.
|
91
|
+
def self.included klass
|
92
|
+
klass.extend ClassMethods
|
93
|
+
end
|
94
|
+
|
95
|
+
# Used to aid in nested JsonObject's traversing back through their parents.
|
96
|
+
attr_accessor :parent
|
97
|
+
|
98
|
+
# Stores the underlying JSON Hash that we wish to then declare accessors for.
|
99
|
+
attr_accessor :json_hash
|
100
|
+
|
101
|
+
# Nested JsonObjects might be initalized with new so we account for that by
|
102
|
+
# supplying a empty hash default.
|
103
|
+
def json_hash= hash
|
104
|
+
@json_hash = hash || {}
|
105
|
+
end
|
106
|
+
|
107
|
+
# This will be extended when JsonObject is included in a class.
|
108
|
+
module ClassMethods
|
109
|
+
|
110
|
+
# Provides a default implementation of this method, which is a required
|
111
|
+
# call, used by {#object_accessor}
|
112
|
+
#
|
113
|
+
# Usable with a class that can be initialized with no arguments e.g. new()
|
114
|
+
def create hash, parent=nil
|
115
|
+
new().tap do |obj|
|
116
|
+
obj.parent = parent
|
117
|
+
obj.json_hash = hash
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def create_value_accessor_method attribute, opts={}, &block
|
122
|
+
method_name = opts[:name] || attribute
|
123
|
+
cached_method_results_name = "@#{method_name}_cached"
|
124
|
+
define_method method_name.to_sym do
|
125
|
+
return instance_variable_get(cached_method_results_name) if instance_variable_defined?(cached_method_results_name)
|
126
|
+
instance_variable_set("@#{method_name}_cached", begin
|
127
|
+
block.yield self
|
128
|
+
end)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private :create_value_accessor_method
|
133
|
+
|
134
|
+
# Creates an accessor method to retrieve values from the stored {#json_hash}
|
135
|
+
#
|
136
|
+
# @param [#to_s] attribute will be used to retrieve a value from {#json_hash} and will be the name of the new accessor method by default
|
137
|
+
# @param [Hash] opts
|
138
|
+
# @option opts [#to_s] :name Will explicitly set the new accessor method name
|
139
|
+
# @option opts [Object] :default If {#json_hash} has no value for the given attribute the default provided will be returned.
|
140
|
+
# @option opts [Proc] :proc Allows a supplied proc to return the value from the created accessor method. The proc has access to self and the current value; may be from the :default option if provided.
|
141
|
+
def value_accessor attribute, opts={}
|
142
|
+
default_value = opts[:default]
|
143
|
+
proc_provided = opts[:proc]
|
144
|
+
create_value_accessor_method attribute, opts do |obj|
|
145
|
+
value = obj.json_hash[attribute.to_s]
|
146
|
+
value = default_value if value.nil?
|
147
|
+
proc_provided ? proc_provided.call(obj, value) : value
|
148
|
+
end
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Convienience method for defining muiltiple accessors with one call.
|
154
|
+
# @example Muiltiple accessors with no options
|
155
|
+
# value_accessors :first_name, :last_name, :age
|
156
|
+
#
|
157
|
+
# @example Muiltiple accessors with some options
|
158
|
+
# value_accessors [:selected, default: false], [:category, name: :main_category], :age
|
159
|
+
#
|
160
|
+
# @param args [#to_s, Array<#to_s, [Hash]>]
|
161
|
+
def value_accessors *args
|
162
|
+
args.each do |values|
|
163
|
+
value_accessor *Array(values)
|
164
|
+
end
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
# Similar to value_accessor.
|
169
|
+
#
|
170
|
+
# @example Accepting the default object class
|
171
|
+
# object_accessor :address_information
|
172
|
+
#
|
173
|
+
# @example Assigning a JsonObject class
|
174
|
+
# object_accessor :address_information, class: AddressInformation
|
175
|
+
#
|
176
|
+
# @param [#to_s] attribute will be used to retrieve the expected hash value from {#json_hash} and will be the name of the new accessor method by default.
|
177
|
+
# @param [Hash] opts
|
178
|
+
# @option opts [#to_s] :name Will explicitly set the new accessor method name
|
179
|
+
def object_accessor attribute, opts={}
|
180
|
+
klass = opts.fetch(:class, JsonObject.default_json_object_class)
|
181
|
+
set_parent = opts.fetch(:set_parent, true)
|
182
|
+
create_value_accessor_method attribute, opts do |obj|
|
183
|
+
value_for_attribute = obj.json_hash[attribute.to_s]
|
184
|
+
methods_value = if value_for_attribute.is_a? Array
|
185
|
+
value_for_attribute.inject([]) do |classes, hash|
|
186
|
+
classes << klass.create(hash, set_parent ? obj : nil)
|
187
|
+
end
|
188
|
+
else
|
189
|
+
value_for_attribute.nil? ? nil : klass.create(value_for_attribute, set_parent ? obj : nil)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
self
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Alternative for include JsonObject is to inherit this class
|
197
|
+
# @example
|
198
|
+
# class MyClass < JsonObject::Base
|
199
|
+
# end
|
200
|
+
class Base
|
201
|
+
include JsonObject
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
include JsonObject
|
4
|
+
|
5
|
+
describe JsonObject do
|
6
|
+
|
7
|
+
it "the default json_object_class is correct" do
|
8
|
+
JsonObject.default_json_object_class.must_equal JsonOpenStruct
|
9
|
+
end
|
10
|
+
|
11
|
+
it "we can change the default json_object_class" do
|
12
|
+
klass = Class.new()
|
13
|
+
JsonObject.default_json_object_class = klass
|
14
|
+
JsonObject.default_json_object_class.must_equal klass
|
15
|
+
#reset to correct default
|
16
|
+
JsonObject.default_json_object_class = JsonOpenStruct
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { Class.new(Base) }
|
20
|
+
|
21
|
+
describe Base do
|
22
|
+
|
23
|
+
it "creating an instance with a nil hash will create an empty hash" do
|
24
|
+
subject.create(nil).json_hash.must_be_instance_of Hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "value_accessors" do
|
29
|
+
|
30
|
+
let(:json) do
|
31
|
+
JSON.parse(<<-EOS
|
32
|
+
{"an_integer":1,"a_string":"my string","a_boolean":true,"an_array":[1,2,3],"false_boolean":false}
|
33
|
+
EOS
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "caching is working" do
|
38
|
+
subject.value_accessor :an_integer
|
39
|
+
check = subject.create(json)
|
40
|
+
check.instance_variable_defined?("@an_integer_cached").must_equal false
|
41
|
+
check.instance_variable_get("@an_integer_cached").must_equal nil
|
42
|
+
check.an_integer
|
43
|
+
check.instance_variable_defined?("@an_integer_cached").must_equal true
|
44
|
+
check.instance_variable_get("@an_integer_cached").must_equal 1
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#value_accessor works for data types Integer, String, Boolean and Array" do
|
48
|
+
|
49
|
+
it "integer" do
|
50
|
+
subject.value_accessor :an_integer
|
51
|
+
subject.create(json).an_integer.must_equal 1
|
52
|
+
end
|
53
|
+
|
54
|
+
it "string" do
|
55
|
+
subject.value_accessor :a_string
|
56
|
+
subject.create(json).a_string.must_equal "my string"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "boolean" do
|
60
|
+
subject.value_accessor :a_boolean
|
61
|
+
subject.create(json).a_boolean.must_equal true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "array" do
|
65
|
+
subject.value_accessor :an_array
|
66
|
+
subject.create(json).an_array.must_equal [1,2,3]
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "assigning a specific accessor name" do
|
70
|
+
it "to one attribute" do
|
71
|
+
subject.value_accessor :an_integer, name: "new_integer_accessor"
|
72
|
+
subject.create(json).methods.must_include :new_integer_accessor
|
73
|
+
subject.create(json).new_integer_accessor.must_equal 1
|
74
|
+
end
|
75
|
+
|
76
|
+
it "with an existing accessor of the same name and a proc" do
|
77
|
+
subject.value_accessor :an_integer
|
78
|
+
subject.value_accessor :an_integer, name: "new_integer_accessor", proc: Proc.new {|obj, value| value * 2 }
|
79
|
+
subject.create(json).methods.must_include :new_integer_accessor
|
80
|
+
subject.create(json).an_integer.must_equal 1
|
81
|
+
subject.create(json).new_integer_accessor.must_equal 2
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "when a value doesn't exist nil will be found" do
|
86
|
+
subject.value_accessor :not_there
|
87
|
+
subject.create(json).not_there.must_equal nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "we can provide a default value so a nil return can be avoided" do
|
91
|
+
subject.value_accessor :not_there, default: "my default value"
|
92
|
+
subject.create(json).not_there.must_equal "my default value"
|
93
|
+
end
|
94
|
+
|
95
|
+
it "we can provide a default value that would evaluate to false" do
|
96
|
+
subject.value_accessor :not_there, default: false
|
97
|
+
subject.create(json).not_there.must_equal false
|
98
|
+
end
|
99
|
+
|
100
|
+
it "a default value will not overwrite an existing value that evaluates to false" do
|
101
|
+
subject.value_accessor :false_boolean, default: true
|
102
|
+
subject.create(json).false_boolean.must_equal false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "we can provide a modifier proc" do
|
106
|
+
subject.value_accessor :an_integer, proc: Proc.new {|json_object,value| value*2}
|
107
|
+
subject.create(json).an_integer.must_equal 2
|
108
|
+
end
|
109
|
+
|
110
|
+
it "another modifying proc example showing it works after :default" do
|
111
|
+
subject.value_accessor :not_there, default: "small", proc: Proc.new {|json_object, value| value.sub('small', 'big')}
|
112
|
+
subject.create(json).not_there.must_equal "big"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "#value_accessors can be used to define muiltible accessors at a time" do
|
117
|
+
|
118
|
+
it "integer, string, boolean in one line assignment" do
|
119
|
+
subject.value_accessors :an_integer, :a_string, :a_boolean
|
120
|
+
subject.create(json).an_integer.must_equal 1
|
121
|
+
subject.create(json).a_string.must_equal "my string"
|
122
|
+
subject.create(json).a_boolean.must_equal true
|
123
|
+
end
|
124
|
+
|
125
|
+
it "correctly uses options like :name" do
|
126
|
+
subject.value_accessors :an_integer, [:a_string, name: "custom_name"]
|
127
|
+
subject.create(json).methods.must_include :custom_name
|
128
|
+
subject.create(json).custom_name.must_equal "my string"
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#object_accessor" do
|
135
|
+
|
136
|
+
let(:json) do
|
137
|
+
JSON.parse(<<-EOS
|
138
|
+
{"an_object":{"id":1, "name":"object one", "enabled":true}, "name":"record one"}
|
139
|
+
EOS
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
let :object_handler_class do
|
144
|
+
Class.new(Base).tap do |obj|
|
145
|
+
obj.value_accessors :id, :name, :object
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it "caching is working" do
|
150
|
+
subject.object_accessor :an_object
|
151
|
+
check = subject.create(json)
|
152
|
+
check.instance_variable_defined?("@an_object_cached").must_equal false
|
153
|
+
check.instance_variable_get("@an_object_cached").must_equal nil
|
154
|
+
check.an_object
|
155
|
+
check.instance_variable_defined?("@an_object_cached").must_equal true
|
156
|
+
check.instance_variable_get("@an_object_cached").must_be_instance_of JsonOpenStruct
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "providing a class to handle a json object" do
|
160
|
+
|
161
|
+
it "we correctly have an instace of our object handler" do
|
162
|
+
subject.object_accessor :an_object, class: object_handler_class
|
163
|
+
subject.create(json).an_object.must_be_instance_of object_handler_class
|
164
|
+
end
|
165
|
+
|
166
|
+
it "the object handler contains the correct values " do
|
167
|
+
subject.object_accessor :an_object, class: object_handler_class
|
168
|
+
object_handler_class.value_accessor :an_integer
|
169
|
+
subject.create(json).an_object.id.must_equal 1
|
170
|
+
end
|
171
|
+
|
172
|
+
it "the object handler sets the parent by default" do
|
173
|
+
TempClass = JsonObject.create
|
174
|
+
TempClass.object_accessor :an_object, class: object_handler_class
|
175
|
+
TempClass.create(json).an_object.parent.must_be_instance_of TempClass
|
176
|
+
end
|
177
|
+
|
178
|
+
it "the object handler handles set_parent(false)" do
|
179
|
+
Temp2Class = JsonObject.create
|
180
|
+
Temp2Class.object_accessor :an_object, class: object_handler_class, set_parent: false
|
181
|
+
Temp2Class.create(json).an_object.parent.must_be_instance_of NilClass
|
182
|
+
end
|
183
|
+
|
184
|
+
it "the object handler has a value_accessor set that has access to the object and its parent via proc" do
|
185
|
+
subject.value_accessor :name
|
186
|
+
object_handler_class.value_accessor :parents_name, proc: Proc.new {|json_object, value| json_object.parent.name}
|
187
|
+
subject.object_accessor :an_object, class: object_handler_class
|
188
|
+
subject.create(json).an_object.parents_name.must_equal "record one"
|
189
|
+
|
190
|
+
#also confirm the parent is correct
|
191
|
+
result = subject.create(json)
|
192
|
+
result.an_object.parent.must_equal result
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "not supplying a specific object handler" do
|
198
|
+
|
199
|
+
it "assigns the values to an OpenStruct object by default" do
|
200
|
+
subject.object_accessor :an_object
|
201
|
+
subject.create(json).an_object.must_be_instance_of JsonOpenStruct
|
202
|
+
end
|
203
|
+
|
204
|
+
it "also has access to the parent" do
|
205
|
+
subject.object_accessor :an_object
|
206
|
+
result = subject.create(json)
|
207
|
+
result.an_object.parent.must_equal result
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe "an object handler given a nil (non-existing json object)" do
|
212
|
+
|
213
|
+
it "simply returns nil" do
|
214
|
+
subject.object_accessor :dosent_exist, class: object_handler_class
|
215
|
+
subject.create(json).dosent_exist.must_be_nil
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "with arrays" do
|
221
|
+
let(:json) do
|
222
|
+
JSON.parse(<<-EOS
|
223
|
+
{"objects":[
|
224
|
+
{"id":1, "name":"object one"},
|
225
|
+
{"id":2, "name":"object two"},
|
226
|
+
{"id":3, "name":"object three"}
|
227
|
+
]
|
228
|
+
}
|
229
|
+
EOS
|
230
|
+
)
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "not supplying object class handlers" do
|
234
|
+
|
235
|
+
it "when theres an array of objects we will get back an array" do
|
236
|
+
|
237
|
+
subject.object_accessor :objects
|
238
|
+
subject.create(json).objects.must_be_instance_of Array
|
239
|
+
end
|
240
|
+
|
241
|
+
it "the array will contain OpenStruct objects" do
|
242
|
+
|
243
|
+
subject.object_accessor :objects
|
244
|
+
subject.create(json).objects[0].must_be_instance_of JsonOpenStruct
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
it "when the json array is empty the return value will be as well" do
|
249
|
+
subject.object_accessor :objects
|
250
|
+
subject.create(JSON.parse('{"objects":[]}')).objects.must_be_empty
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "when using object handler classes" do
|
255
|
+
|
256
|
+
it "providing a custom class for our objects works" do
|
257
|
+
subject.object_accessor :objects, class: object_handler_class
|
258
|
+
subject.create(json).objects.must_be_instance_of Array
|
259
|
+
end
|
260
|
+
|
261
|
+
it "the array will contain our supplied object handlers" do
|
262
|
+
subject.object_accessor :objects, class: object_handler_class
|
263
|
+
subject.create(json).objects[0].must_be_instance_of object_handler_class
|
264
|
+
end
|
265
|
+
|
266
|
+
it "when the json array is empty the return value will be as well" do
|
267
|
+
subject.object_accessor :objects, class: object_handler_class
|
268
|
+
subject.create(JSON.parse('{"objects":[]}')).objects.must_be_empty object_handler_class
|
269
|
+
end
|
270
|
+
|
271
|
+
it "if we rename the accessor name it will be used instead of the attribute name" do
|
272
|
+
subject.object_accessor :objects, name: 'cool_objects', class: object_handler_class
|
273
|
+
subject.create(json).methods.must_include :cool_objects
|
274
|
+
subject.create(json).cool_objects.first.id.must_equal 1
|
275
|
+
end
|
276
|
+
|
277
|
+
it "the object handler sets the parent by default" do
|
278
|
+
Temp3Class = JsonObject.create
|
279
|
+
Temp3Class.object_accessor :objects, class: object_handler_class
|
280
|
+
Temp3Class.create(json).objects.first.parent.must_be_instance_of Temp3Class
|
281
|
+
end
|
282
|
+
|
283
|
+
it "the object handler handles set_parent(false)" do
|
284
|
+
Temp4Class = JsonObject.create
|
285
|
+
Temp4Class.object_accessor :objects, class: object_handler_class, set_parent: false
|
286
|
+
Temp4Class.create(json).objects.first.parent.must_be_instance_of NilClass
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe "with arrays that have null entries" do
|
293
|
+
let(:json) do
|
294
|
+
JSON.parse(<<-EOS
|
295
|
+
{"objects":[
|
296
|
+
null,
|
297
|
+
{"id":2, "name":"object three"},
|
298
|
+
{"id":3, "name":"object three"}
|
299
|
+
]
|
300
|
+
}
|
301
|
+
EOS
|
302
|
+
)
|
303
|
+
end
|
304
|
+
|
305
|
+
describe "not supplying object class handlers" do
|
306
|
+
|
307
|
+
it "OpenStruct handles a nil initializer" do
|
308
|
+
subject.object_accessor :objects
|
309
|
+
subject.create(json).objects.must_be_instance_of Array
|
310
|
+
subject.create(json).objects.first.must_be_instance_of JsonOpenStruct
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe "supplying an object handler class" do
|
315
|
+
it "OpenStruct handles a nil initializer" do
|
316
|
+
subject.object_accessor :objects, class: object_handler_class
|
317
|
+
subject.create(json).objects.must_be_instance_of Array
|
318
|
+
subject.create(json).objects.first.must_be_instance_of object_handler_class
|
319
|
+
subject.create(json).objects.first.id.must_equal nil
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json_objects
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dave Vallance
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Quickly build objects to represent, store and access JSON Hash values.
|
42
|
+
You can control the accessor method names, default values and provide procs to do
|
43
|
+
more complex computation.
|
44
|
+
email:
|
45
|
+
- davevallance@gmail.com
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- ".gitignore"
|
51
|
+
- Gemfile
|
52
|
+
- Guardfile
|
53
|
+
- LICENSE.txt
|
54
|
+
- README.md
|
55
|
+
- Rakefile
|
56
|
+
- json_object.gemspec
|
57
|
+
- lib/json_object.rb
|
58
|
+
- lib/json_object/version.rb
|
59
|
+
- spec/json_object_spec.rb
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
homepage: https://github.com/dvallance/json_object
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.2.2
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: Instead of accessing JSON Hashs the usual way, this allows creating custom
|
85
|
+
classes to represent and access the JSON values.
|
86
|
+
test_files:
|
87
|
+
- spec/json_object_spec.rb
|
88
|
+
- spec/spec_helper.rb
|