jsonity 1.0.0 → 1.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 +4 -4
- data/README.md +257 -155
- data/jsonity.gemspec +2 -2
- data/lib/jsonity/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5e0cbbf0655194ed77a8e96424d290e700cc6a6
|
4
|
+
data.tar.gz: c26576875dc473fd201e7f8ccd21940a642da05f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 305a32a835c2695991915d9e35899c5080ec3c624dffd63eb54c4760d9107b0390c8c6fd43b10cf86e5135cf0ceca19b1996ac763dfc11d250c34c77af3a6c0b
|
7
|
+
data.tar.gz: 4ef7f0f1a7c647255cff9f469ef35f0a7027510f5bdb1e9764fe8e6964ab6b20d142d4d7bd0db4fb792ea4c8c7b7dabe56ed87058c1e7d57c0b16d088765b712
|
data/README.md
CHANGED
@@ -1,24 +1,45 @@
|
|
1
1
|
Jsonity
|
2
2
|
=======
|
3
3
|
|
4
|
-
**The most
|
4
|
+
**The most sexy language for building JSON in Ruby**
|
5
|
+
|
6
|
+
I'd been writing JSON API with [Jbuilder](https://github.com/rails/jbuilder), [RABL](https://github.com/nesquena/rabl) and [ActiveModel::Serializer](https://github.com/rails-api/active_model_serializers), but nothing of them meet my requirement and use case.
|
7
|
+
|
8
|
+
- Jbuilder is very verbose in syntax, and its functonalities of partial and mixin are actually weak
|
9
|
+
- RABL has simple syntax, but writing complex data structure with it is not very readable
|
10
|
+
- ActiveModel::Serializer is persuasive role in Rails architecture, but can get very useless when you need to fully control from controller what attributes of nested (associated) object to be included
|
11
|
+
|
12
|
+
So I chose to create new one -- Jsonity, which is simple and powerful JSON builder especially for JSON API representations.
|
13
|
+
|
14
|
+
- Simple and readable syntax even if it gets complex
|
15
|
+
- Flexible and arbitrary nodes
|
16
|
+
- Includable mixin
|
17
|
+
- Declarative attributes inclusion
|
18
|
+
|
19
|
+
|
20
|
+
Installation
|
21
|
+
------------
|
22
|
+
|
23
|
+
Make sure to add the gem to your Gemfile.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'jsonity'
|
27
|
+
```
|
5
28
|
|
6
29
|
|
7
30
|
Overview
|
8
31
|
--------
|
9
32
|
|
10
33
|
```ruby
|
11
|
-
@
|
12
|
-
t.meta!
|
34
|
+
@meta_pagination_mixin = ->(t) {
|
35
|
+
t.meta! { |meta|
|
13
36
|
meta.total_pages
|
14
37
|
meta.current_page
|
15
38
|
}
|
16
39
|
}
|
17
40
|
|
18
41
|
Jsonity.build { |t|
|
19
|
-
t
|
20
|
-
|
21
|
-
t[].users!(inherit: true) { |user|
|
42
|
+
t[].users!(@users) { |user|
|
22
43
|
user.id
|
23
44
|
user.age
|
24
45
|
user.full_name { |u| [u.first_name, u.last_name].join ' ' }
|
@@ -28,115 +49,113 @@ Jsonity.build { |t|
|
|
28
49
|
}
|
29
50
|
}
|
30
51
|
|
31
|
-
t.(&@
|
32
|
-
}
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# }
|
58
|
-
# }
|
59
|
-
# ],
|
60
|
-
# "meta": {
|
61
|
-
# "total_pages": 1,
|
62
|
-
# "current_page": 1
|
63
|
-
# }
|
64
|
-
# }
|
52
|
+
t.(@users, &@meta_pagination_mixin)
|
53
|
+
}
|
54
|
+
=begin
|
55
|
+
{
|
56
|
+
"users": [
|
57
|
+
{
|
58
|
+
"id": 1,
|
59
|
+
"age": 21,
|
60
|
+
"full_name": "John Smith",
|
61
|
+
"avatar": {
|
62
|
+
"image_url": "http://example.com/john.png"
|
63
|
+
}
|
64
|
+
},
|
65
|
+
{
|
66
|
+
"id": 2,
|
67
|
+
"age": 37,
|
68
|
+
"full_name": "William Northington",
|
69
|
+
"avatar": null
|
70
|
+
}
|
71
|
+
],
|
72
|
+
"meta": {
|
73
|
+
"total_pages": 1,
|
74
|
+
"current_page": 1
|
75
|
+
}
|
76
|
+
}
|
77
|
+
=end
|
65
78
|
```
|
66
79
|
|
67
80
|
|
68
81
|
Usage
|
69
82
|
-----
|
70
83
|
|
71
|
-
|
72
|
-
|
73
|
-
```ruby
|
74
|
-
gem 'neo_json'
|
75
|
-
```
|
84
|
+
### Object assignment
|
76
85
|
|
77
|
-
|
86
|
+
To declare the data object for use:
|
78
87
|
|
79
88
|
```ruby
|
80
89
|
Jsonity.build { |t|
|
90
|
+
t <= @user
|
81
91
|
# ...
|
82
92
|
}
|
83
93
|
```
|
84
94
|
|
85
|
-
|
86
|
-
|
87
|
-
To declare the data object for use:
|
95
|
+
Or pass as an argument:
|
88
96
|
|
89
97
|
```ruby
|
90
|
-
|
98
|
+
Jsonity.build(@user) { |user|
|
99
|
+
# ...
|
100
|
+
}
|
91
101
|
```
|
92
102
|
|
103
|
+
|
93
104
|
### Attribute nodes
|
94
105
|
|
95
106
|
Basic usage of defining simple attributes:
|
96
107
|
|
97
108
|
```ruby
|
98
|
-
|
99
|
-
|
109
|
+
Jsonity.build(@user) { |user|
|
110
|
+
user.id # @user.id
|
111
|
+
user.age # @user.age
|
112
|
+
}
|
113
|
+
=begin
|
114
|
+
{
|
115
|
+
"id": 123,
|
116
|
+
"age": 27
|
117
|
+
}
|
118
|
+
=end
|
100
119
|
```
|
101
120
|
|
102
121
|
Or you can use custom attributes in flexible ways:
|
103
122
|
|
104
123
|
```ruby
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
t.seventeen 17 # block can be omitted
|
109
|
-
```
|
124
|
+
Jsonity.build(@user) { |user|
|
125
|
+
# create full_name from @user.first_name and @user.last_name
|
126
|
+
user.full_name { |u| [u.first_name, u.last_name].join ' ' }
|
110
127
|
|
111
|
-
|
112
|
-
|
113
|
-
```ruby
|
114
|
-
# show `id` as `my_id`
|
115
|
-
t.my_id &:id
|
116
|
-
```
|
128
|
+
# block parameter isn't required
|
129
|
+
user.russian_roulette { rand(1..10) }
|
117
130
|
|
118
|
-
|
131
|
+
# or with specified object
|
132
|
+
user.feature_time(Time.now) { |now| now + 1.years }
|
119
133
|
|
120
|
-
|
134
|
+
# block can be omitted if the value is constant
|
135
|
+
user.seventeen 17
|
136
|
+
}
|
137
|
+
=begin
|
138
|
+
{
|
139
|
+
"full_name": "John Smith",
|
140
|
+
"russian_roulette": 4,
|
141
|
+
"feature_time": "2015-09-13 12:32:39 +0900",
|
142
|
+
"seventeen": 17
|
143
|
+
}
|
144
|
+
=end
|
145
|
+
```
|
121
146
|
|
147
|
+
Aliased attributes works well as you expected:
|
148
|
+
|
122
149
|
```ruby
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
@sample = Sample.new 123, 'foo!'
|
128
|
-
|
129
|
-
Jsonity.build { |t|
|
130
|
-
t.sample!(@sample) { |t|
|
131
|
-
# leave empty inside
|
132
|
-
}
|
150
|
+
Jsonity.build(@user) { |user|
|
151
|
+
# show `id` as `my_id`
|
152
|
+
user.my_id &:id
|
133
153
|
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
# }
|
154
|
+
=begin
|
155
|
+
{
|
156
|
+
"my_id": 123
|
157
|
+
}
|
158
|
+
=end
|
140
159
|
```
|
141
160
|
|
142
161
|
### Hash nodes
|
@@ -144,7 +163,7 @@ Jsonity.build { |t|
|
|
144
163
|
With name suffixed with `!`, nested object can be included:
|
145
164
|
|
146
165
|
```ruby
|
147
|
-
|
166
|
+
Jsonity.build(@user) { |user|
|
148
167
|
user.name # @user.name
|
149
168
|
|
150
169
|
user.avatar! { |avatar|
|
@@ -153,89 +172,152 @@ t.user! { |user|
|
|
153
172
|
avatar.height # @user.avatar.height
|
154
173
|
}
|
155
174
|
}
|
156
|
-
|
157
|
-
|
158
|
-
If `@user.avatar = nil`, the output will be like this:
|
175
|
+
=begin
|
176
|
+
Assume that `@user.avatar` is `nil`,
|
159
177
|
|
160
|
-
```javascipt
|
161
178
|
{
|
162
|
-
"
|
163
|
-
|
164
|
-
"
|
165
|
-
|
166
|
-
|
167
|
-
"height": null
|
168
|
-
}
|
179
|
+
"name": "John Smith",
|
180
|
+
"avatar": {
|
181
|
+
"image_url": null,
|
182
|
+
"width": null,
|
183
|
+
"height": null
|
169
184
|
}
|
170
185
|
}
|
186
|
+
=end
|
171
187
|
```
|
172
188
|
|
173
189
|
On the other hand, use `?` as suffix, the whole object become `null`:
|
174
190
|
|
175
191
|
```ruby
|
176
|
-
|
192
|
+
Jsonity.build(@user) { |user|
|
177
193
|
user.name
|
178
194
|
|
179
|
-
user.avatar? { |avatar|
|
195
|
+
user.avatar? { |avatar| # <-- look, prefix is `?`
|
180
196
|
avatar.image_url
|
181
197
|
avatar.width
|
182
198
|
avatar.height
|
183
199
|
}
|
184
200
|
}
|
201
|
+
=begin
|
202
|
+
Assume that `@user.avatar` is `nil`,
|
203
|
+
|
204
|
+
{
|
205
|
+
"name": "John Smith",
|
206
|
+
"avatar": null
|
207
|
+
}
|
208
|
+
=end
|
209
|
+
```
|
210
|
+
|
211
|
+
Explicitly specify an object to use inside a block:
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
Jsonity.build { |t|
|
215
|
+
t.home!(@user.hometown_address) { |home|
|
216
|
+
home.street # @user.hometown_address.street
|
217
|
+
home.zip
|
218
|
+
home.city
|
219
|
+
home.state
|
220
|
+
}
|
221
|
+
}
|
222
|
+
=begin
|
223
|
+
{
|
224
|
+
"home": {
|
225
|
+
"street": "4611 Armbrester Drive",
|
226
|
+
"zip": "90017",
|
227
|
+
"city": "Los Angeles",
|
228
|
+
"state": "CA"
|
229
|
+
}
|
230
|
+
}
|
231
|
+
=end
|
185
232
|
```
|
186
233
|
|
187
|
-
|
234
|
+
Or a block can inherit the parent object:
|
188
235
|
|
189
|
-
```
|
236
|
+
```ruby
|
237
|
+
Jsonity.build { |t|
|
238
|
+
t.user!(@user) { |user|
|
239
|
+
t.profile!(inherit: true) { |profile|
|
240
|
+
profile.name # @user.name
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
=begin
|
190
245
|
{
|
191
246
|
"user": {
|
192
|
-
"
|
193
|
-
|
247
|
+
"profile": {
|
248
|
+
"name": "John Smith"
|
249
|
+
}
|
194
250
|
}
|
195
251
|
}
|
252
|
+
=end
|
196
253
|
```
|
197
254
|
|
198
|
-
|
255
|
+
### Automatic attributes inclusion
|
256
|
+
|
257
|
+
If you set `attr_json` in any class, **the specified attributes will automatically be included**:
|
199
258
|
|
200
259
|
```ruby
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
}
|
260
|
+
class Sample < Struct.new(:id, :foo, :bar)
|
261
|
+
attr_json :id, :foo
|
262
|
+
end
|
263
|
+
|
264
|
+
@sample = Sample.new 123, 'foo!', 'bar!!'
|
207
265
|
```
|
208
266
|
|
209
|
-
|
267
|
+
and then,
|
210
268
|
|
211
269
|
```ruby
|
212
|
-
|
213
|
-
t.
|
214
|
-
|
270
|
+
Jsonity.build { |t|
|
271
|
+
t.sample! @sample
|
272
|
+
}
|
273
|
+
=begin
|
274
|
+
{
|
275
|
+
"sample": {
|
276
|
+
"id": 123,
|
277
|
+
"foo": "foo!"
|
215
278
|
}
|
216
279
|
}
|
280
|
+
=end
|
217
281
|
```
|
218
282
|
|
219
|
-
|
220
|
-
|
221
|
-
Including a collection of objects, just use `t[]` and write the same syntax of hash node:
|
283
|
+
Still you can create any kinds of nodes with a block:
|
222
284
|
|
223
285
|
```ruby
|
224
|
-
|
225
|
-
|
286
|
+
Jsonity.build { |t|
|
287
|
+
t.sample!(@sample) { |sample|
|
288
|
+
sample.bar { |bar| "this is #{bar}" }
|
289
|
+
}
|
290
|
+
}
|
291
|
+
=begin
|
292
|
+
{
|
293
|
+
"sample": {
|
294
|
+
"id": 123,
|
295
|
+
"foo": "foo!",
|
296
|
+
"bar": "this is bar!!"
|
297
|
+
}
|
226
298
|
}
|
299
|
+
=end
|
227
300
|
```
|
228
301
|
|
229
|
-
and the output JSON will be:
|
230
302
|
|
231
|
-
|
303
|
+
### Array nodes
|
304
|
+
|
305
|
+
Including a collection of objects, just use `[]` and write the same syntax of hash node:
|
306
|
+
|
307
|
+
```ruby
|
308
|
+
Jsonity.build(@user) { |user|
|
309
|
+
user[].friends! { |friend|
|
310
|
+
friend.name # @user.friends[i].name
|
311
|
+
}
|
312
|
+
}
|
313
|
+
=begin
|
232
314
|
{
|
233
315
|
"friends": [
|
234
|
-
{
|
235
|
-
|
236
|
-
}
|
316
|
+
{ "name": "John Smith" },
|
317
|
+
{ "name": "William Northington" }
|
237
318
|
]
|
238
319
|
}
|
320
|
+
=end
|
239
321
|
```
|
240
322
|
|
241
323
|
Similar to hash nodes in naming convention,
|
@@ -246,10 +328,10 @@ Also passing the object or inheritance can be done in the same way as hash nodes
|
|
246
328
|
|
247
329
|
### Mixin / Scope
|
248
330
|
|
249
|
-
Since Jsonity aim to be simple and light, use plain `Proc
|
331
|
+
Since Jsonity aim to be simple and light, **use plain `Proc`** to fullfill functonality of mixin.
|
250
332
|
|
251
333
|
```ruby
|
252
|
-
|
334
|
+
@timestamps_mixin = ->(t) {
|
253
335
|
t.created_at
|
254
336
|
t.updated_at
|
255
337
|
}
|
@@ -258,29 +340,54 @@ timestamp_mixin = ->(t) {
|
|
258
340
|
and then,
|
259
341
|
|
260
342
|
```ruby
|
261
|
-
|
262
|
-
user
|
343
|
+
Jsonity.build { |t|
|
344
|
+
t.user!(@user) { |user|
|
345
|
+
user.(&@timestamps_mixin)
|
346
|
+
}
|
263
347
|
}
|
348
|
+
=begin
|
349
|
+
{
|
350
|
+
"user": {
|
351
|
+
"created_at": "2014-09-10 10:41:07 +0900",
|
352
|
+
"updated_at": "2014-09-13 12:55:56 +0900"
|
353
|
+
}
|
354
|
+
}
|
355
|
+
=end
|
264
356
|
```
|
265
357
|
|
266
|
-
In case you might
|
358
|
+
In case you might explicitly **specify an object to use** in mixin, you can do by passing it in the first argument:
|
267
359
|
|
268
360
|
```ruby
|
269
|
-
|
361
|
+
Jsonity.build { |t|
|
362
|
+
t.(@user, &@timestamps_mixin)
|
363
|
+
}
|
364
|
+
=begin
|
365
|
+
{
|
366
|
+
"created_at": "2014-09-10 10:41:07 +0900",
|
367
|
+
"updated_at": "2014-09-13 12:55:56 +0900"
|
368
|
+
}
|
369
|
+
=end
|
270
370
|
```
|
271
371
|
|
272
|
-
So you take this functonality for scope
|
372
|
+
So you take this functonality for **scope**:
|
273
373
|
|
274
374
|
```ruby
|
275
|
-
|
276
|
-
|
375
|
+
Jsonity.build { |t|
|
376
|
+
t.(@user) { |user|
|
377
|
+
user.name
|
378
|
+
}
|
277
379
|
}
|
380
|
+
=begin
|
381
|
+
{
|
382
|
+
"name": "John Smith"
|
383
|
+
}
|
384
|
+
=end
|
278
385
|
```
|
279
386
|
|
280
387
|
#### Mixining nested object and merging
|
281
388
|
|
282
389
|
```ruby
|
283
|
-
meta_pagination_mixin = ->(t) {
|
390
|
+
@meta_pagination_mixin = ->(t) {
|
284
391
|
t.meta! { |meta|
|
285
392
|
meta.total_pages
|
286
393
|
meta.current_page
|
@@ -291,46 +398,41 @@ meta_pagination_mixin = ->(t) {
|
|
291
398
|
and use this mixin like:
|
292
399
|
|
293
400
|
```ruby
|
294
|
-
|
295
|
-
|
296
|
-
}
|
297
|
-
|
298
|
-
t.(@people, &meta_pagination_mixin)
|
401
|
+
Jsonity.build { |t|
|
402
|
+
t.(@people, &@meta_pagination_mixin)
|
299
403
|
|
300
|
-
t.meta! { |meta|
|
301
|
-
|
404
|
+
t.meta! { |meta|
|
405
|
+
meta.total_count @people.count
|
406
|
+
}
|
302
407
|
}
|
303
|
-
|
304
|
-
|
305
|
-
the output become:
|
408
|
+
=begin
|
409
|
+
Notice that two objects `meta!` got merged.
|
306
410
|
|
307
|
-
```javascript
|
308
411
|
{
|
309
|
-
"people": [
|
310
|
-
// ...
|
311
|
-
],
|
312
412
|
"meta": {
|
313
413
|
"total_pages": 5,
|
314
414
|
"current_page": 1,
|
315
415
|
"total_count": 123
|
316
416
|
}
|
317
417
|
}
|
418
|
+
=end
|
318
419
|
```
|
319
420
|
|
320
|
-
Notice that two objects `meta!` got merged.
|
321
421
|
|
322
|
-
###
|
422
|
+
### Using object
|
323
423
|
|
324
|
-
|
424
|
+
You can get the current object as a second block parameter.
|
325
425
|
|
326
|
-
```
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
426
|
+
```ruby
|
427
|
+
Jsonity.build { |t|
|
428
|
+
t[].people!(@people) { |person, person_obj|
|
429
|
+
unless person_obj.private_member?
|
430
|
+
person.name
|
431
|
+
person.age
|
432
|
+
end
|
332
433
|
|
333
|
-
|
434
|
+
person.cv if person_obj.looking_for_job?
|
435
|
+
}
|
334
436
|
}
|
335
437
|
```
|
336
438
|
|
@@ -338,7 +440,7 @@ t[].people! { |person|
|
|
338
440
|
With Rails
|
339
441
|
----------
|
340
442
|
|
341
|
-
Helper method is available for rendering with Jsonity:
|
443
|
+
Helper method is available in controller for rendering with Jsonity:
|
342
444
|
|
343
445
|
```ruby
|
344
446
|
render_json(status: :ok) { |t|
|
data/jsonity.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Jsonity::VERSION
|
9
9
|
spec.authors = ['Yuki Iwanaga']
|
10
10
|
spec.email = ['yuki@creasty.com']
|
11
|
-
spec.summary = 'The most
|
12
|
-
spec.description = 'The most
|
11
|
+
spec.summary = 'The most sexy language for building JSON in Ruby'
|
12
|
+
spec.description = 'The most sexy language for building JSON in Ruby'
|
13
13
|
spec.homepage = 'https://github.com/creasty/jsonity'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
data/lib/jsonity/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuki Iwanaga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.3'
|
41
|
-
description: The most
|
41
|
+
description: The most sexy language for building JSON in Ruby
|
42
42
|
email:
|
43
43
|
- yuki@creasty.com
|
44
44
|
executables: []
|
@@ -80,5 +80,5 @@ rubyforge_project:
|
|
80
80
|
rubygems_version: 2.2.2
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
|
-
summary: The most
|
83
|
+
summary: The most sexy language for building JSON in Ruby
|
84
84
|
test_files: []
|