son_jay 0.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +42 -0
- data/Rakefile +23 -0
- data/cucumber.yml +2 -0
- data/features/json_parsing.feature +227 -0
- data/features/json_serialization.feature +260 -0
- data/features/step_definitions/json_parsing_steps.rb +26 -0
- data/features/step_definitions/json_serialization_steps.rb +23 -0
- data/features/step_definitions/model_steps.rb +3 -0
- data/features/support/env.rb +13 -0
- data/lib/son_jay/model_array.rb +55 -0
- data/lib/son_jay/object_model/properties.rb +70 -0
- data/lib/son_jay/object_model/property_definition.rb +38 -0
- data/lib/son_jay/object_model.rb +71 -0
- data/lib/son_jay/value_array.rb +17 -0
- data/lib/son_jay/version.rb +3 -0
- data/lib/son_jay.rb +8 -0
- data/son_jay.gemspec +25 -0
- data/spec/model_array_spec.rb +70 -0
- data/spec/object_model/properties_spec.rb +125 -0
- data/spec/object_model/property_definition_spec.rb +31 -0
- data/spec/object_model_spec.rb +136 -0
- data/spec/son_jay_spec.rb +7 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/value_array_spec.rb +21 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjdiYTdiZjkxOWE3ZDg0ZjkxNzY0ZjNkYzEwYzg1ZWM1ZWQ3NTM5Yg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjA4ZmQ1NDRkZDgwN2JmZDU1YmU4ZmFmMDM0NzhkZjAyZjczMzBiOQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDkzNGQ4ZTk1ZjZhNjYyYTg0MDU0NzMwNTM2ZTM0MzJhNWQwNmY1OGIyMDY0
|
10
|
+
YjY2NThhMDJhNmMwODc2NjYyNGM4NDg5NzM3OTllZmJhMjVlMzdhMmMzY2Qw
|
11
|
+
ZjU5YzcwNTY3MTdhMWY1NTI0NDU2NGJiMGZkODZiMmVkOWVkYzk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjI0N2FiMTE0MWNiYjVjM2IwZDQ2MGZkN2Y5MWUzNjg2NmVjYWRkZDQzMjU5
|
14
|
+
M2FlMzdjMzM3NmVmZWQxZWVlNzJkM2M1N2VmZGE5OTlhOTBmNzg2ZDI5MmJl
|
15
|
+
MjZmMjdmNTBmNGRiZDNjYTMwZWQ2YjRlZDUxZDFkMDkyNWQ0YzM=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Steve Jorgensen
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# SonJay
|
2
|
+
|
3
|
+
Symmetrical transformation between structured data and JSON
|
4
|
+
|
5
|
+
Allows concrete object/array data model classes to be defined,
|
6
|
+
and then allows JSON serialization/parsing from/to an instance
|
7
|
+
of one of those classes.
|
8
|
+
|
9
|
+
This allows a single body of code to be used to define a JSON
|
10
|
+
API structure for a provider and its clients.
|
11
|
+
|
12
|
+
Instances of these models can also be used to help keep
|
13
|
+
automated tests simple and reliable. Attempts by test setup
|
14
|
+
code or code under test to produce incorrectly structured
|
15
|
+
data will generally fail in a fast, informative way.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
gem 'son_jay'
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install son_jay
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
- [Serialization](features/json_serialization.feature)
|
34
|
+
- [Parsing](features/json_parsing.feature)
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
1. Fork it ( http://github.com/<my-github-username>/son_jay/fork )
|
39
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
41
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
42
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
|
5
|
+
desc "Run all specs and features"
|
6
|
+
task all_tests: %w[spec cucumber cucumber:wip]
|
7
|
+
|
8
|
+
task :default => :all_tests
|
9
|
+
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
|
13
|
+
|
14
|
+
require "cucumber"
|
15
|
+
require "cucumber/rake/task"
|
16
|
+
|
17
|
+
Cucumber::Rake::Task.new
|
18
|
+
|
19
|
+
namespace :cucumber do
|
20
|
+
Cucumber::Rake::Task.new :wip do |t|
|
21
|
+
t.profile = 'wip'
|
22
|
+
end
|
23
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
Feature: Parsing data from JSON
|
2
|
+
|
3
|
+
Scenario: Simple object data
|
4
|
+
Given an object model defined as:
|
5
|
+
"""
|
6
|
+
class SimpleObjectModel < SonJay::ObjectModel
|
7
|
+
properties do
|
8
|
+
property :id
|
9
|
+
property :name
|
10
|
+
property :published
|
11
|
+
property :featured
|
12
|
+
property :owner
|
13
|
+
end
|
14
|
+
end
|
15
|
+
"""
|
16
|
+
And JSON data defined as:
|
17
|
+
"""
|
18
|
+
json = <<-JSON
|
19
|
+
{
|
20
|
+
"id" : 55 ,
|
21
|
+
"name" : "Polygon" ,
|
22
|
+
"published" : true ,
|
23
|
+
"featured" : false ,
|
24
|
+
"owner" : null
|
25
|
+
}
|
26
|
+
JSON
|
27
|
+
"""
|
28
|
+
When the JSON is parsed to a model instance as:
|
29
|
+
"""
|
30
|
+
instance = SimpleObjectModel.json_create( json )
|
31
|
+
"""
|
32
|
+
Then the instance attributes are as follows:
|
33
|
+
| id | name | published | featured | owner |
|
34
|
+
| 55 | "Polygon" | true | false | nil |
|
35
|
+
|
36
|
+
Scenario: Composite object data
|
37
|
+
Given an object model defined as:
|
38
|
+
"""
|
39
|
+
class ThingModel < SonJay::ObjectModel
|
40
|
+
properties do
|
41
|
+
property :name
|
42
|
+
property :details, :model => DetailModel
|
43
|
+
end
|
44
|
+
end
|
45
|
+
"""
|
46
|
+
And an object model defined as:
|
47
|
+
"""
|
48
|
+
class DetailModel < SonJay::ObjectModel
|
49
|
+
properties do
|
50
|
+
property :color
|
51
|
+
property :size
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"""
|
55
|
+
And JSON data defined as:
|
56
|
+
"""
|
57
|
+
json = <<-JSON
|
58
|
+
{
|
59
|
+
"name" : "Cherry" ,
|
60
|
+
"details" :
|
61
|
+
{
|
62
|
+
"color" : "red" ,
|
63
|
+
"size" : "small"
|
64
|
+
}
|
65
|
+
}
|
66
|
+
JSON
|
67
|
+
"""
|
68
|
+
When the JSON is parsed to a model instance as:
|
69
|
+
"""
|
70
|
+
instance = ThingModel.json_create( json )
|
71
|
+
"""
|
72
|
+
Then the instance attributes are as follows:
|
73
|
+
| name | details.color | details.size |
|
74
|
+
| "Cherry" | "red" | "small" |
|
75
|
+
|
76
|
+
Scenario: Object data with a value-array property
|
77
|
+
Given an object model defined as:
|
78
|
+
"""
|
79
|
+
class ContestantModel < SonJay::ObjectModel
|
80
|
+
properties do
|
81
|
+
property :name
|
82
|
+
property :scores, model: []
|
83
|
+
end
|
84
|
+
end
|
85
|
+
"""
|
86
|
+
And JSON data defined as:
|
87
|
+
"""
|
88
|
+
json = <<-JSON
|
89
|
+
{
|
90
|
+
"name" : "Pat" ,
|
91
|
+
"scores" : [ 9, 5, 7 ]
|
92
|
+
}
|
93
|
+
JSON
|
94
|
+
"""
|
95
|
+
When the JSON is parsed to a model instance as:
|
96
|
+
"""
|
97
|
+
instance = ContestantModel.json_create( json )
|
98
|
+
"""
|
99
|
+
Then the instance attributes are as follows:
|
100
|
+
| name | scores[0] | scores[1] | scores[2] |
|
101
|
+
| "Pat" | 9 | 5 | 7 |
|
102
|
+
|
103
|
+
Scenario: Object data with a nested value-array property
|
104
|
+
Given an object model defined as:
|
105
|
+
"""
|
106
|
+
class TicTacToeModel < SonJay::ObjectModel
|
107
|
+
properties do
|
108
|
+
property :rows, model: [[]]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
"""
|
112
|
+
And a model instance defined as:
|
113
|
+
"""
|
114
|
+
instance = TicTacToeModel.new
|
115
|
+
"""
|
116
|
+
And JSON data defined as:
|
117
|
+
"""
|
118
|
+
json = <<-JSON
|
119
|
+
{
|
120
|
+
"rows" : [
|
121
|
+
[ "X", "O", "X" ] ,
|
122
|
+
[ "O", "X", "X" ] ,
|
123
|
+
[ "X", "O", "O" ]
|
124
|
+
]
|
125
|
+
}
|
126
|
+
JSON
|
127
|
+
"""
|
128
|
+
When the JSON is parsed to a model instance as:
|
129
|
+
"""
|
130
|
+
instance = TicTacToeModel.json_create( json )
|
131
|
+
"""
|
132
|
+
Then the instance attributes are as follows:
|
133
|
+
| rows[0][0] | rows[0][1] | rows[0][2] |
|
134
|
+
| 'X' | 'O' | 'X' |
|
135
|
+
| rows[1][0] | rows[1][1] | rows[1][2] |
|
136
|
+
| 'O' | 'X' | 'X' |
|
137
|
+
| rows[2][0] | rows[2][1] | rows[2][2] |
|
138
|
+
| 'X' | 'O' | 'O' |
|
139
|
+
|
140
|
+
Scenario: Object data with an object-array property
|
141
|
+
Given an object model defined as:
|
142
|
+
"""
|
143
|
+
class ListModel < SonJay::ObjectModel
|
144
|
+
properties do
|
145
|
+
property :name
|
146
|
+
property :items, :model => [ ItemModel ]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
"""
|
150
|
+
And an object model defined as:
|
151
|
+
"""
|
152
|
+
class ItemModel < SonJay::ObjectModel
|
153
|
+
properties do
|
154
|
+
property :description
|
155
|
+
property :priority
|
156
|
+
end
|
157
|
+
end
|
158
|
+
"""
|
159
|
+
And JSON data defined as:
|
160
|
+
"""
|
161
|
+
json = <<-JSON
|
162
|
+
{
|
163
|
+
"name" : "Shopping" ,
|
164
|
+
"items" :
|
165
|
+
[
|
166
|
+
{
|
167
|
+
"description" : "Potato Chips" ,
|
168
|
+
"priority" : "Low"
|
169
|
+
} ,
|
170
|
+
{
|
171
|
+
"description" : "Ice Cream" ,
|
172
|
+
"priority" : "High"
|
173
|
+
}
|
174
|
+
]
|
175
|
+
}
|
176
|
+
JSON
|
177
|
+
"""
|
178
|
+
When the JSON is parsed to a model instance as:
|
179
|
+
"""
|
180
|
+
instance = ListModel.json_create( json )
|
181
|
+
"""
|
182
|
+
Then the instance attributes are as follows:
|
183
|
+
| name | items[0].description | items[0].priority | items[1].description | items[1].priority |
|
184
|
+
| "Shopping" | "Potato Chips" | "Low" | "Ice Cream" | "High" |
|
185
|
+
|
186
|
+
Scenario: Object data with a nested object-array property
|
187
|
+
Given an object model defined as:
|
188
|
+
"""
|
189
|
+
class TableModel < SonJay::ObjectModel
|
190
|
+
properties do
|
191
|
+
property :rows, :model => [[ CellModel ]]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
"""
|
195
|
+
And an object model defined as:
|
196
|
+
"""
|
197
|
+
class CellModel < SonJay::ObjectModel
|
198
|
+
properties do
|
199
|
+
property :is_head
|
200
|
+
property :value
|
201
|
+
end
|
202
|
+
end
|
203
|
+
"""
|
204
|
+
And JSON data defined as:
|
205
|
+
"""
|
206
|
+
json = <<-JSON
|
207
|
+
{
|
208
|
+
"rows" :
|
209
|
+
[
|
210
|
+
[ {"is_head": 1, "value": "Date"} , {"is_head": 1, "value": "Sightings"} ] ,
|
211
|
+
[ {"is_head": 1, "value": "Jan 1"} , {"is_head": 0, "value": 3} ] ,
|
212
|
+
[ {"is_head": 1, "value": "Jan 3"} , {"is_head": 0, "value": 2} ]
|
213
|
+
]
|
214
|
+
}
|
215
|
+
JSON
|
216
|
+
"""
|
217
|
+
When the JSON is parsed to a model instance as:
|
218
|
+
"""
|
219
|
+
instance = TableModel.json_create( json )
|
220
|
+
"""
|
221
|
+
Then the instance attributes are as follows:
|
222
|
+
| rows[0][0].is_head | rows[0][0].value | rows[0][1].is_head | rows[0][1].value |
|
223
|
+
| 1 | "Date" | 1 | "Sightings" |
|
224
|
+
| rows[1][0].is_head | rows[1][0].value | rows[1][1].is_head | rows[1][1].value |
|
225
|
+
| 1 | "Jan 1" | 0 | 3 |
|
226
|
+
| rows[2][0].is_head | rows[2][0].value | rows[2][1].is_head | rows[2][1].value |
|
227
|
+
| 1 | "Jan 3" | 0 | 2 |
|
@@ -0,0 +1,260 @@
|
|
1
|
+
Feature: Serializing data to JSON
|
2
|
+
|
3
|
+
Scenario: Simple object data
|
4
|
+
Given an object model defined as:
|
5
|
+
"""
|
6
|
+
class SimpleObjectModel < SonJay::ObjectModel
|
7
|
+
properties do
|
8
|
+
property :id
|
9
|
+
property :name
|
10
|
+
property :published
|
11
|
+
property :featured
|
12
|
+
property :owner
|
13
|
+
end
|
14
|
+
end
|
15
|
+
"""
|
16
|
+
And a model instance defined as:
|
17
|
+
"""
|
18
|
+
instance = SimpleObjectModel.new
|
19
|
+
"""
|
20
|
+
When the instance's property values are assigned as:
|
21
|
+
"""
|
22
|
+
instance.id = 55
|
23
|
+
instance.name = "Polygon"
|
24
|
+
instance.published = true
|
25
|
+
instance.featured = false
|
26
|
+
instance.owner = nil
|
27
|
+
"""
|
28
|
+
And the model is serialized to JSON as:
|
29
|
+
"""
|
30
|
+
json = instance.to_json
|
31
|
+
"""
|
32
|
+
Then the resulting JSON is equivalent to:
|
33
|
+
"""
|
34
|
+
{
|
35
|
+
"id" : 55 ,
|
36
|
+
"name" : "Polygon" ,
|
37
|
+
"published" : true ,
|
38
|
+
"featured" : false ,
|
39
|
+
"owner" : null
|
40
|
+
}
|
41
|
+
"""
|
42
|
+
|
43
|
+
Scenario: Composite object data
|
44
|
+
Given an object model defined as:
|
45
|
+
"""
|
46
|
+
class ThingModel < SonJay::ObjectModel
|
47
|
+
properties do
|
48
|
+
property :name
|
49
|
+
property :details, :model => DetailModel
|
50
|
+
end
|
51
|
+
end
|
52
|
+
"""
|
53
|
+
And an object model defined as:
|
54
|
+
"""
|
55
|
+
class DetailModel < SonJay::ObjectModel
|
56
|
+
properties do
|
57
|
+
property :color
|
58
|
+
property :size
|
59
|
+
end
|
60
|
+
end
|
61
|
+
"""
|
62
|
+
And a model instance defined as:
|
63
|
+
"""
|
64
|
+
instance = ThingModel.new
|
65
|
+
"""
|
66
|
+
When the instance's property values are assigned as:
|
67
|
+
"""
|
68
|
+
instance.name = "Cherry"
|
69
|
+
instance.details.color = "red"
|
70
|
+
instance.details.size = "small"
|
71
|
+
"""
|
72
|
+
And the model is serialized to JSON as:
|
73
|
+
"""
|
74
|
+
json = instance.to_json
|
75
|
+
"""
|
76
|
+
Then the resulting JSON is equivalent to:
|
77
|
+
"""
|
78
|
+
{
|
79
|
+
"name" : "Cherry" ,
|
80
|
+
"details" :
|
81
|
+
{
|
82
|
+
"color" : "red" ,
|
83
|
+
"size" : "small"
|
84
|
+
}
|
85
|
+
}
|
86
|
+
"""
|
87
|
+
|
88
|
+
Scenario: Object data with a value-array property
|
89
|
+
Given an object model defined as:
|
90
|
+
"""
|
91
|
+
class ContestantModel < SonJay::ObjectModel
|
92
|
+
properties do
|
93
|
+
property :name
|
94
|
+
property :scores, model: []
|
95
|
+
end
|
96
|
+
end
|
97
|
+
"""
|
98
|
+
And a model instance defined as:
|
99
|
+
"""
|
100
|
+
instance = ContestantModel.new
|
101
|
+
"""
|
102
|
+
When the instance's property values are assigned as:
|
103
|
+
"""
|
104
|
+
instance.name = "Pat"
|
105
|
+
instance.scores = [ 9, 5, 7 ]
|
106
|
+
"""
|
107
|
+
And the model is serialized to JSON as:
|
108
|
+
"""
|
109
|
+
json = instance.to_json
|
110
|
+
"""
|
111
|
+
Then the resulting JSON is equivalent to:
|
112
|
+
"""
|
113
|
+
{
|
114
|
+
"name" : "Pat" ,
|
115
|
+
"scores" : [ 9, 5, 7 ]
|
116
|
+
}
|
117
|
+
"""
|
118
|
+
|
119
|
+
Scenario: Object data with a nested value-array property
|
120
|
+
Given an object model defined as:
|
121
|
+
"""
|
122
|
+
class TicTacToeModel < SonJay::ObjectModel
|
123
|
+
properties do
|
124
|
+
property :rows, model: [[]]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
"""
|
128
|
+
And a model instance defined as:
|
129
|
+
"""
|
130
|
+
instance = TicTacToeModel.new
|
131
|
+
"""
|
132
|
+
When the instance's property values are assigned as:
|
133
|
+
"""
|
134
|
+
instance.rows.additional.concat %w[ X O X ]
|
135
|
+
instance.rows.additional.concat %w[ O X X ]
|
136
|
+
instance.rows.additional.concat %w[ X O O ]
|
137
|
+
"""
|
138
|
+
And the model is serialized to JSON as:
|
139
|
+
"""
|
140
|
+
json = instance.to_json
|
141
|
+
"""
|
142
|
+
Then the resulting JSON is equivalent to:
|
143
|
+
"""
|
144
|
+
{
|
145
|
+
"rows" : [
|
146
|
+
[ "X", "O", "X" ] ,
|
147
|
+
[ "O", "X", "X" ] ,
|
148
|
+
[ "X", "O", "O" ]
|
149
|
+
]
|
150
|
+
}
|
151
|
+
"""
|
152
|
+
|
153
|
+
Scenario: Object data with an object-array property
|
154
|
+
Given an object model defined as:
|
155
|
+
"""
|
156
|
+
class ListModel < SonJay::ObjectModel
|
157
|
+
properties do
|
158
|
+
property :name
|
159
|
+
property :items, :model => [ ItemModel ]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
"""
|
163
|
+
And an object model defined as:
|
164
|
+
"""
|
165
|
+
class ItemModel < SonJay::ObjectModel
|
166
|
+
properties do
|
167
|
+
property :description
|
168
|
+
property :priority
|
169
|
+
end
|
170
|
+
end
|
171
|
+
"""
|
172
|
+
And a model instance defined as:
|
173
|
+
"""
|
174
|
+
instance = ListModel.new
|
175
|
+
"""
|
176
|
+
When the instance's property values are assigned as:
|
177
|
+
"""
|
178
|
+
instance.name = "Shopping"
|
179
|
+
|
180
|
+
item = instance.items.additional
|
181
|
+
item.description = 'Potato Chips'
|
182
|
+
item.priority = 'Low'
|
183
|
+
|
184
|
+
item = instance.items.additional
|
185
|
+
item.description = 'Ice Cream'
|
186
|
+
item.priority = 'High'
|
187
|
+
"""
|
188
|
+
And the model is serialized to JSON as:
|
189
|
+
"""
|
190
|
+
json = instance.to_json
|
191
|
+
"""
|
192
|
+
Then the resulting JSON is equivalent to:
|
193
|
+
"""
|
194
|
+
{
|
195
|
+
"name" : "Shopping" ,
|
196
|
+
"items" :
|
197
|
+
[
|
198
|
+
{
|
199
|
+
"description" : "Potato Chips" ,
|
200
|
+
"priority" : "Low"
|
201
|
+
} ,
|
202
|
+
{
|
203
|
+
"description" : "Ice Cream" ,
|
204
|
+
"priority" : "High"
|
205
|
+
}
|
206
|
+
]
|
207
|
+
}
|
208
|
+
"""
|
209
|
+
|
210
|
+
Scenario: Object data with a nested object-array property
|
211
|
+
Given an object model defined as:
|
212
|
+
"""
|
213
|
+
class TableModel < SonJay::ObjectModel
|
214
|
+
properties do
|
215
|
+
property :rows, :model => [[ CellModel ]]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
"""
|
219
|
+
And an object model defined as:
|
220
|
+
"""
|
221
|
+
class CellModel < SonJay::ObjectModel
|
222
|
+
properties do
|
223
|
+
property :is_head
|
224
|
+
property :value
|
225
|
+
end
|
226
|
+
end
|
227
|
+
"""
|
228
|
+
And a model instance defined as:
|
229
|
+
"""
|
230
|
+
instance = TableModel.new
|
231
|
+
"""
|
232
|
+
When the instance's property values are assigned as:
|
233
|
+
"""
|
234
|
+
row_cells = instance.rows.additional
|
235
|
+
row_cells.additional.tap{ |c| c.is_head=1 ; c.value='Date' }
|
236
|
+
row_cells.additional.tap{ |c| c.is_head=1 ; c.value='Sightings' }
|
237
|
+
|
238
|
+
row_cells = instance.rows.additional
|
239
|
+
row_cells.additional.tap{ |c| c.is_head=1 ; c.value='Jan 1' }
|
240
|
+
row_cells.additional.tap{ |c| c.is_head=0 ; c.value=3 }
|
241
|
+
|
242
|
+
row_cells = instance.rows.additional
|
243
|
+
row_cells.additional.tap{ |c| c.is_head=1 ; c.value='Jan 3' }
|
244
|
+
row_cells.additional.tap{ |c| c.is_head=0 ; c.value=2 }
|
245
|
+
"""
|
246
|
+
And the model is serialized to JSON as:
|
247
|
+
"""
|
248
|
+
json = instance.to_json
|
249
|
+
"""
|
250
|
+
Then the resulting JSON is equivalent to:
|
251
|
+
"""
|
252
|
+
{
|
253
|
+
"rows" :
|
254
|
+
[
|
255
|
+
[ {"is_head": 1, "value": "Date"} , {"is_head": 1, "value": "Sightings"} ] ,
|
256
|
+
[ {"is_head": 1, "value": "Jan 1"} , {"is_head": 0, "value": 3} ] ,
|
257
|
+
[ {"is_head": 1, "value": "Jan 3"} , {"is_head": 0, "value": 2} ]
|
258
|
+
]
|
259
|
+
}
|
260
|
+
"""
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Given(/^JSON data defined as:$/) do |code|
|
2
|
+
json = nil
|
3
|
+
context_module.module_eval code
|
4
|
+
context_data[:json] = json
|
5
|
+
end
|
6
|
+
|
7
|
+
When(/^the JSON is parsed to a model instance as:$/) do |code|
|
8
|
+
json = context_data[:json]
|
9
|
+
instance = nil
|
10
|
+
context_module.module_eval code
|
11
|
+
context_data[:instance] = instance
|
12
|
+
end
|
13
|
+
|
14
|
+
Then(/^the instance attributes are as follows:$/) do |table|
|
15
|
+
row_pairs = table.raw.each_slice(2)
|
16
|
+
attribute_exprs = row_pairs.map( &:first ).reduce( :+ )
|
17
|
+
expected_exprs = row_pairs.map( &:last ).reduce( :+ )
|
18
|
+
|
19
|
+
instance = context_data[:instance]
|
20
|
+
actuals = attribute_exprs .map{ |expr| eval( "instance.#{expr}" ) }
|
21
|
+
expecteds = expected_exprs .map{ |expr| eval( expr ) }
|
22
|
+
|
23
|
+
actual_hash = Hash[ attribute_exprs.zip( actuals ) ]
|
24
|
+
expected_hash = Hash[ attribute_exprs.zip( expecteds ) ]
|
25
|
+
expect( actual_hash ).to eq( expected_hash )
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Given(/^a model instance defined as:$/) do |code|
|
2
|
+
instance = nil
|
3
|
+
context_module.module_eval code
|
4
|
+
context_data[:instance] = instance
|
5
|
+
end
|
6
|
+
|
7
|
+
When(/^the instance's property values are assigned as:$/) do |code|
|
8
|
+
instance = context_data[:instance]
|
9
|
+
context_module.module_eval code
|
10
|
+
end
|
11
|
+
|
12
|
+
When(/^the model is serialized to JSON as:$/) do |code|
|
13
|
+
instance = context_data[:instance]
|
14
|
+
json = nil
|
15
|
+
context_module.module_eval code
|
16
|
+
context_data[:json] = json
|
17
|
+
end
|
18
|
+
|
19
|
+
Then(/^the resulting JSON is equivalent to:$/) do |expected_json_equivalent|
|
20
|
+
expected_data = JSON.parse( expected_json_equivalent )
|
21
|
+
actual_data = JSON.parse( context_data[:json] )
|
22
|
+
expect( actual_data ).to eq( expected_data )
|
23
|
+
end
|