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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7837ec79aa7e71a84da9f8fda957c0217bd2691b
4
- data.tar.gz: 26ad97f8e6d9b9dcd3dad8c0155eab31a80c8d6b
3
+ metadata.gz: b5e0cbbf0655194ed77a8e96424d290e700cc6a6
4
+ data.tar.gz: c26576875dc473fd201e7f8ccd21940a642da05f
5
5
  SHA512:
6
- metadata.gz: e7535b1ce03cb5c6cb877aaf91fa0676f93eda13bc706db8ddeb5169bc443853f0112893dcd2cc20d5a60264d2226231a9b83dca599e86815cb75f37c5e64208
7
- data.tar.gz: 7b7cff2ba3ece3d3a5be9a9eb002ce8ebdc9c534537120cbc74736be1079b999621a9b90893c5c231fe5b0c999c33eb435196fa2a849bf8b9f604651059ca268
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 natural language for building JSON in Ruby**
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
- @meta_pagination = ->(t) {
12
- t.meta!(inherit: true) { |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 <= @users
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.(&@meta_pagination)
32
- }
33
- #=> {
34
- # "users": [
35
- # {
36
- # "id": 1,
37
- # "age": 21,
38
- # "full_name": "John Smith",
39
- # "avatar": {
40
- # "image_url": "http://example.com/john.png"
41
- # }
42
- # },
43
- # {
44
- # "id": 2,
45
- # "age": 37,
46
- # "full_name": "William Northington",
47
- # "avatar": {
48
- # "image_url": "http://example.com/william.png"
49
- # }
50
- # },
51
- # {
52
- # "id": 3,
53
- # "age": 29,
54
- # "full_name": "Samuel Miller",
55
- # "avatar": {
56
- # "image_url": "http://example.com/samuel.png"
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
- Make sure to add the gem to your Gemfile.
72
-
73
- ```ruby
74
- gem 'neo_json'
75
- ```
84
+ ### Object assignment
76
85
 
77
- Start writing object:
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
- ### Object assignment
86
-
87
- To declare the data object for use:
95
+ Or pass as an argument:
88
96
 
89
97
  ```ruby
90
- t <= @user
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
- t.id # @user.id
99
- t.age # @user.age
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
- t.full_name { |u| [u.first_name, u.last_name].join ' ' } # u = @user
106
- t.russian_roulette { rand(1..10) } # block parameter isn't required
107
- t.with_object(Time) { |t| t.now } # now, t = Time
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
- Aliased attributes works well as you expected:
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
- ### Automatic attributes inclusion
131
+ # or with specified object
132
+ user.feature_time(Time.now) { |now| now + 1.years }
119
133
 
120
- If you set `attr_json` in any class, the specified attributes will automatically be included:
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
- class Sample < Struct.new(:id, :foo)
124
- attr_json :id, :foo
125
- end
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
- # "sample": {
136
- # "id": 123,
137
- # "foo": "foo!"
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
- t.user! { |user|
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
- "user": {
163
- "name": "John Smith",
164
- "avatar": {
165
- "image_url": null,
166
- "width": null,
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
- t.user! { |user|
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
- and the output will be:
234
+ Or a block can inherit the parent object:
188
235
 
189
- ```javascipt
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
- "name": "John Smith",
193
- "avatar": null
247
+ "profile": {
248
+ "name": "John Smith"
249
+ }
194
250
  }
195
251
  }
252
+ =end
196
253
  ```
197
254
 
198
- Explicitly set an object to use inside a block:
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
- t.home?(@user.hometown_address) { |home|
202
- home.street # @user.hometown_address.street
203
- home.zip
204
- home.city
205
- home.state
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
- Or blocks can inherit the parent object:
267
+ and then,
210
268
 
211
269
  ```ruby
212
- t.user! { |user|
213
- t.my!(inherit: true) { |my|
214
- my.name # @user.name
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
- ### Array nodes
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
- t[].friends! { |friend|
225
- friend.name
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
- ```javascipt
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
- name: "John Smith"
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` to fullfill functonality of mixin.
331
+ Since Jsonity aim to be simple and light, **use plain `Proc`** to fullfill functonality of mixin.
250
332
 
251
333
  ```ruby
252
- timestamp_mixin = ->(t) {
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
- t.user! { |user|
262
- user.(&timestamp_mixin)
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 use different object in mixin, you can pass the object in the first argument:
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
- t.(@other_user, &timestamps)
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
- t.(@other_user) { |other_user|
276
- other_user.name
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
- t[].people!(@people) { |person|
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
- meta.total_count @people.count
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
- ### Conditions
422
+ ### Using object
323
423
 
324
- Simply you can use `if` or `unless` statement inside the block:
424
+ You can get the current object as a second block parameter.
325
425
 
326
- ```
327
- t[].people! { |person|
328
- unless person.private_member?
329
- person.name
330
- person.age
331
- end
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
- person.cv if person.looking_for_job?
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 natural language for building JSON in Ruby'
12
- spec.description = 'The most natural language for building JSON in Ruby'
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
 
@@ -1,3 +1,3 @@
1
1
  module Jsonity
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
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.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-12 00:00:00.000000000 Z
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 natural language for building JSON in Ruby
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 natural language for building JSON in Ruby
83
+ summary: The most sexy language for building JSON in Ruby
84
84
  test_files: []