jsonapi-serializable 0.1.1.beta2 → 0.1.1.beta3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d7beafa6258df4dd44fa02cc22d7a62b8f0e2d0
4
- data.tar.gz: fa7223c5647bd81486ec1066e13345a96311081a
3
+ metadata.gz: 1a382b6d5802f167908d0d6ee82605a7a52d43a0
4
+ data.tar.gz: 9c9211218919e4a05e74b010cbc9a5ad51c6533e
5
5
  SHA512:
6
- metadata.gz: e041bc9ebe1a08d945eb721baf612d70166de3cda15a310de8ba860d3f9bb7cd0dc72c2b40a6bf682c7568a0635bf796ed9ebf3676edd47d93ce4c01fcd96e3c
7
- data.tar.gz: fd83b712198356d829a7db4b10e2a831d8843a151cfaab7c3a573985a9f8005b2a78f113e0dfbf0b520ca443b18f4194f9635616a8229edf28da847bbbe737a6
6
+ metadata.gz: bf14811ff7b926f43b45c9cf49032d3fc0c0fe507d4c446d2108fd948de2c5c782cba5b3e90bfe5e6893ee0ef18dcddaf6c91de9e7052445fae25f1b747f65e0
7
+ data.tar.gz: 14e585466ae7124d51c0d7562e52fbff0982f91025ed71ad9f6a01e1100379b241e1ccea9248d2ebe84a273bdf50d020671b41a80c672f819226c4cfdc0c9a69
data/README.md CHANGED
@@ -1,11 +1,25 @@
1
1
  # jsonapi-serializable
2
2
  Ruby gem for building [JSON API](http://jsonapi.org) resources to be rendered by
3
- the [jsonapi-renderer](https://github.com/beauby/jsonapi) gem.
3
+ the [jsonapi-renderer](https://github.com/jsonapi-rb/renderer) gem.
4
4
 
5
5
  ## Status
6
6
 
7
7
  [![Gem Version](https://badge.fury.io/rb/jsonapi-serializable.svg)](https://badge.fury.io/rb/jsonapi-serializable)
8
- [![Build Status](https://secure.travis-ci.org/beauby/jsonapi-serializable.svg?branch=master)](http://travis-ci.org/beauby/jsonapi-serializable?branch=master)
8
+ [![Build Status](https://secure.travis-ci.org/jsonapi-rb/serializable.svg?branch=master)](http://travis-ci.org/jsonapi-rb/serializable?branch=master)
9
+
10
+ ## Table of Contents
11
+
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [Example for Model-based Resources](#example-for-model-based-resources)
15
+ - [Example for General Resources](#example-for-general-resources)
16
+ - [Documentation](#documentation)
17
+ - [`JSONAPI::Serializable::Resource` DSL](#jsonapiserializableresource-dsl)
18
+ - [`JSONAPI::Serializable::Model` DSL](#jsonapiserializablemodel-dsl)
19
+ - [`JSONAPI::Serializable::Relationship` DSL](#jsonapiserializablerelationship-dsl)
20
+ - [`JSONAPI::Serializable::Link` DSL](#jsonapiserializablelink-dsl)
21
+ - [`JSONAPI::Serializable::Error` DSL](#jsonapiserializableerror-dsl)
22
+ - [License](#license)
9
23
 
10
24
  ## Installation
11
25
  ```ruby
@@ -30,23 +44,21 @@ require 'jsonapi/serializable'
30
44
 
31
45
  Then, define some resource classes:
32
46
 
33
- ### For model-based resources
47
+ ### Example for Model-based Resources
34
48
 
35
49
  For resources that are simple representations of models, the DSL is simplified:
36
50
 
37
51
  ```ruby
38
- class PostResource < JSONAPI::Serializable::Resource
52
+ class PostResource < JSONAPI::Serializable::Model
39
53
  type 'posts'
40
54
 
41
- id
42
-
43
55
  attribute :title
44
56
 
45
57
  attribute :date do
46
58
  @model.created_at
47
59
  end
48
60
 
49
- relationship :author, UserResource do
61
+ has_one :author, UserResource do
50
62
  link(:self) do
51
63
  href @url_helper.link_for_rel('posts', @model.id, 'author')
52
64
  meta link_meta: 'some meta'
@@ -68,15 +80,16 @@ class PostResource < JSONAPI::Serializable::Resource
68
80
  end
69
81
  end
70
82
  ```
83
+
71
84
  Then, build your resources from your models and render them:
72
85
  ```ruby
73
86
  # post = some post model
74
87
  # UrlHelper is some helper class
75
88
  resource = PostResource.new(model: post, url_helper: UrlHelper)
76
- document = JSONAPI.render(resource)
89
+ document = JSONAPI.render(data: resource)
77
90
  ```
78
91
 
79
- ### For general resources
92
+ ### Example for General Resources
80
93
 
81
94
  In case your resource is not a simple representation of one of your models,
82
95
  the more general `JSONAPI::Serializable::Resource` class can be used.
@@ -129,9 +142,232 @@ Finally, build your resources from your models and render them:
129
142
  # post = some post model
130
143
  # UrlHelper is some helper class
131
144
  resource = PostResource.new(post: post, url_helper: UrlHelper)
132
- document = JSONAPI.render(resource)
145
+ document = JSONAPI.render(data: resource)
133
146
  ```
134
147
 
148
+ ## Documentation
149
+
150
+ ### `JSONAPI::Serializable::Resource` DSL
151
+
152
+ + `#initialize(hash)`
153
+
154
+ All the values of the hash are made available during serialization as instance
155
+ variables within all DSLs.
156
+
157
+ Example:
158
+ ```ruby
159
+ SerializablePost.new(post: post, url_helper: url_helper)
160
+ # => You can then use @post and @url_helper from within the DSL.
161
+ ```
162
+
163
+ + `::type(value = nil, &block)`
164
+
165
+ Define the type of the resource, either statically, or dynamically as the
166
+ return value of the block.
167
+
168
+ + `::id(&block)`
169
+
170
+ Define the id of the resource.
171
+
172
+ Example:
173
+ ```ruby
174
+ id { @post.id }
175
+ ```
176
+
177
+ + `::attribute(key, &block)`
178
+
179
+ Define an attribute of the resource.
180
+
181
+ Example:
182
+ ```ruby
183
+ attribute(:title) { @post.title }
184
+ ```
185
+
186
+ + `::relationship(key, &block)`
187
+
188
+ Define a relationship of the resource. The block can contain any instruction of
189
+ the [`JSONAPI::Serializable::Relationship` DSL](#jsonapiserializablerelationship-dsl).
190
+
191
+ Example:
192
+ ```ruby
193
+ relationship :comments do
194
+ data do
195
+ @post.comments.map do |c|
196
+ SerializableComment.new(comment: c, url_helper: @url_helper)
197
+ end
198
+ end
199
+ link :self do
200
+ @url_helper.link_for_post_comments(post_id: @post.id)
201
+ end
202
+ meta do
203
+ { count: @post.comments.count }
204
+ end
205
+ end
206
+ ```
207
+
208
+ + `::link(key, &block)`
209
+
210
+ Define a resource-level link. The block can either return a string or contain
211
+ any instruction of the [`JSONAPI::Serializable::Link` DSL](#jsonapiserializablelink-dsl).
212
+
213
+ Example:
214
+ ```ruby
215
+ link :self do
216
+ "http://api.example.com/posts/#{@post.id}"
217
+ end
218
+ ```
219
+
220
+ + `::meta(value = nil, &block)`
221
+
222
+ Define a resource-level meta member. The value can either be provided
223
+ statically, or dynamically as the return value of a block.
224
+
225
+ Examples:
226
+ ```ruby
227
+ meta(experimental: true)
228
+ ```
229
+ ```ruby
230
+ meta do
231
+ { remaining_time: @post.remaining_time }
232
+ end
233
+ ```
234
+
235
+ ### `JSONAPI::Serializable::Model` DSL
236
+
237
+ This class is a subclass of `JSONAPI::Serializable::Resource` with a more
238
+ convenient DSL tailored for resources that are direct representation of some
239
+ business models.
240
+
241
+ + `#initialize(hash)`
242
+
243
+ See `JSONAPI::Serializable::Resource` DSL.
244
+
245
+ The model is expected to be provided in the hash with the key `:model`.
246
+
247
+ + `::type(value = nil, &block)`
248
+
249
+ See `JSONAPI::Serializable::Resource` DSL.
250
+
251
+ + `::id(&block)`
252
+
253
+ See `JSONAPI::Serializable::Resource` DSL.
254
+
255
+ Defaults to:
256
+ ```ruby
257
+ id { @model.id }
258
+ ```
259
+
260
+ + `::attribute(key, &block)`
261
+
262
+ See `JSONAPI::Serializable::Resource` DSL.
263
+
264
+ Defaults to the following when no block is provided:
265
+ ```ruby
266
+ attribute key do
267
+ @model.public_send(key)
268
+ end
269
+ ```
270
+
271
+ + `::has_one(key, resource_klass = nil, &block)`
272
+
273
+ Define a `has_one` relationship on the resource.
274
+
275
+ The serializable class for the related resource can be explicitly stated as the
276
+ second parameter, but when omitted it will be infered from the related
277
+ resource's class name.
278
+
279
+ When no block is provided, the value of the relationship defaults to
280
+ `resource_klass.new(model: @model.public_send(key))`.
281
+
282
+ + `::has_many(key, resource_klass = nil, &block)`
283
+
284
+ Define a `has_many` relationship on the resource.
285
+
286
+ The serializable class for the related resources can be explicitly stated as the
287
+ second parameter, but when omitted it will be infered from the related
288
+ resources' class names.
289
+
290
+ When no block is provided, the value of the relationship defaults to:
291
+ ```ruby
292
+ @model.public_send(key).map do |r|
293
+ resource_klass.new(model: r)
294
+ end
295
+ ```
296
+
297
+ + `::relationship(key, &block)`
298
+
299
+ See `JSONAPI::Serializable::Resource` DSL.
300
+
301
+ + `::link(key, &block)`
302
+
303
+ See `JSONAPI::Serializable::Resource` DSL.
304
+
305
+ + `::meta(value = nil, &block)`
306
+
307
+ See `JSONAPI::Serializable::Resource` DSL.
308
+
309
+ ### `JSONAPI::Serializable::Relationship` DSL
310
+
311
+ + `::data(resource_class = nil, &block)`
312
+
313
+ NOTE: This section is outdated. It is still valid, but the data method is now
314
+ much more flexible.
315
+
316
+ Defines the related serializable resources for the relationship.
317
+
318
+ Example:
319
+ ```ruby
320
+ data do
321
+ if @post.author.nil?
322
+ nil
323
+ else
324
+ SerializableUser.new(user: @post.author)
325
+ end
326
+ end
327
+ ```
328
+
329
+ + `::link(key, &block)`
330
+
331
+ Define a relationship-level link.
332
+
333
+ See `JSONAPI::Serializable::Resource` DSL.
334
+
335
+ + `::meta(value = nil, &block)`
336
+
337
+ Define some relationship-level meta member.
338
+
339
+ See `JSONAPI::Serializable::Resource` DSL.
340
+
341
+ ### `JSONAPI::Serializable::Link` DSL
342
+
343
+ + `::href(value = nil, &block)`
344
+
345
+ Define the href member for the link, either directly, or dynamically as the
346
+ return value of a block.
347
+
348
+ + `::meta(value = nil, &block)`
349
+
350
+ Define the meta member for the link, either directly, or dynamically as the
351
+ return value of a block.
352
+
353
+ ### `JSONAPI::Serializable::Error` DSL
354
+
355
+ + `::id(value = nil, &block)`
356
+
357
+ + `::status(value = nil, &block)`
358
+
359
+ + `::code(value = nil, &block)`
360
+
361
+ + `::title(value = nil, &block)`
362
+
363
+ + `::detail(value = nil, &block)`
364
+
365
+ + `::meta(value = nil, &block)`
366
+
367
+ + `::link(key, &block)`
368
+
369
+ + `::source(&block)`
370
+
135
371
  ## License
136
372
 
137
373
  jsonapi-serializable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -1,3 +1,4 @@
1
1
  require 'jsonapi/serializable/error'
2
2
  require 'jsonapi/serializable/model'
3
3
  require 'jsonapi/serializable/resource'
4
+ require 'jsonapi/serializable/renderer'
@@ -6,39 +6,7 @@ module JSONAPI
6
6
  class Model < Resource
7
7
  include ModelDSL
8
8
 
9
- class << self
10
- attr_accessor :api_version_val
11
- end
12
-
13
- def self.inherited(klass)
14
- super
15
- klass.api_version_val = api_version_val
16
- end
17
-
18
9
  id { @model.public_send(:id).to_s }
19
-
20
- def resource_klass_for(model_klass)
21
- names = model_klass.name.split('::'.freeze)
22
- model_klass_name = names.pop
23
- namespace = names.join('::'.freeze)
24
- version = self.class.api_version_val
25
-
26
- klass_name = [namespace, version, "Serializable#{model_klass_name}"]
27
- .reject(&:nil?)
28
- .reject(&:empty?)
29
- .join('::'.freeze)
30
-
31
- Object.const_get(klass_name)
32
- end
33
-
34
- def nil?
35
- @model.nil?
36
- end
37
-
38
- def as_jsonapi(params = {})
39
- return nil if nil?
40
- super(params)
41
- end
42
10
  end
43
11
  end
44
12
  end
@@ -6,48 +6,21 @@ module JSONAPI
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- def api_version(value)
10
- self.api_version_val = value
11
- end
12
-
13
- def type(value = nil)
14
- value ||= name
15
- super(value)
16
- end
17
-
18
9
  def attribute(attr, &block)
19
10
  block ||= proc { @model.public_send(attr) }
20
11
  super(attr, &block)
21
12
  end
22
13
 
23
- def has_many(rel, resource_klass = nil, &block)
24
- rel_block = proc do
25
- if resource_klass
26
- data do
27
- @model.public_send(rel).map do |related|
28
- resource_klass ||= resource_klass_for(related.class)
29
- resource_klass.new(model: related)
30
- end
31
- end
32
- end
33
- instance_eval(&block) unless block.nil?
34
- end
35
- relationship(rel, &rel_block)
36
- end
37
-
38
- def has_one(rel, resource_klass = nil, &block)
14
+ def relationship(rel, resource_class = nil, &block)
39
15
  rel_block = proc do
40
- if resource_klass
41
- data do
42
- related = @model.public_send(rel)
43
- resource_klass ||= resource_klass_for(related.class)
44
- resource_klass.new(model: related)
45
- end
46
- end
16
+ data(resource_class) { @model.public_send(rel) }
47
17
  instance_eval(&block) unless block.nil?
48
18
  end
49
- relationship(rel, &rel_block)
19
+ super(rel, &rel_block)
50
20
  end
21
+ alias has_many relationship
22
+ alias has_one relationship
23
+ alias belongs_to relationship
51
24
  end
52
25
  end
53
26
  end
@@ -18,24 +18,19 @@ module JSONAPI
18
18
  hash[:links] = @_links if @_links.any?
19
19
  hash[:meta] = @_meta unless @_meta.nil?
20
20
  return hash unless included || (!@_links.any? && @_meta.nil?)
21
- hash[:data] = eval_linkage_data
21
+ hash[:data] = linkage_data
22
22
 
23
23
  hash
24
24
  end
25
25
 
26
26
  private
27
27
 
28
- def eval_linkage_data
29
- @_linkage_data ||=
30
- if @_linkage_data_block
31
- @_linkage_data_block.call
32
- elsif data.respond_to?(:each)
33
- data.map { |res| { type: res.jsonapi_type, id: res.jsonapi_id } }
34
- elsif data.nil?
35
- nil
36
- else
37
- { type: data.jsonapi_type, id: data.jsonapi_id }
38
- end
28
+ def linkage_data
29
+ linkage_data = Array(data).map do |res|
30
+ { type: res.jsonapi_type, id: res.jsonapi_id }
31
+ end
32
+
33
+ data.respond_to?(:each) ? linkage_data : linkage_data.first
39
34
  end
40
35
  end
41
36
  end
@@ -1,40 +1,55 @@
1
+ require 'jsonapi/serializable/resource_builder'
2
+
1
3
  module JSONAPI
2
4
  module Serializable
3
5
  module RelationshipDSL
4
- # Declare/access the data for this relationship.
5
- #
6
- # @yieldreturn [JSONAPI::Serializable::Resource,
7
- # Array<JSONAPI::Serializable::Resource>,
8
- # nil] The data for this relationship.
6
+ # Declare the data for this relationship.
7
+ # @param [String,Constant,Hash{Symbol=>String,Constant}] resource_class
8
+ # @yieldreturn The data for this relationship.
9
+ # If it is nil, an object implementing the Serializable::Resource
10
+ # interface, an empty array, or an array of objects implementing the
11
+ # Serializable::Resource interface, then it is used as is.
12
+ # Otherwise an appropriate Serializable::Model subclass is inferred
13
+ # from the object(s)' namespace/class, the resource_class parameter if
14
+ # provided, and the @_resource_inferer.
9
15
  #
10
16
  # @example
11
- # data :posts do
17
+ # data do
12
18
  # @user.posts.map { |p| PostResource.new(post: p) }
13
19
  # end
14
20
  #
15
21
  # @example
16
- # data :author do
17
- # @user.author && UserResource.new(user: @user.author)
22
+ # data do
23
+ # @post.author && UserResource.new(user: @user.author)
18
24
  # end
19
- def data(&block)
20
- if block.nil?
21
- @_data ||= (@_data_block && @_data_block.call)
22
- else
23
- @_data_block = block
24
- end
25
- end
26
-
27
- # Declare the linkage data for this relationship. Useful when linkage
28
- # can be computed in a more efficient way than the data itself.
29
25
  #
30
- # @yieldreturn [Hash] The block to compute linkage data.
26
+ # @example
27
+ # data do
28
+ # @user.posts
29
+ # end
30
+ # end
31
31
  #
32
32
  # @example
33
- # linkage_data do
34
- # { id: @post.author_id.to_s, type: 'users' }
33
+ # data SerializablePost do
34
+ # @user.posts
35
35
  # end
36
- def linkage_data(&block)
37
- @_linkage_data_block = block
36
+ #
37
+ # @example
38
+ # data "SerializableUser" do
39
+ # @post.author
40
+ # end
41
+ def data(resource_class = nil)
42
+ if block_given?
43
+ # NOTE(beauby): Lazify computation since it is only needed when
44
+ # the corresponding relationship is included.
45
+ @_data_block = proc do
46
+ _resources_for(yield, resource_class)
47
+ end
48
+ else
49
+ # NOTE(beauby): In the case of a computation heavy relationship with
50
+ # nil value, this block might be executed multiple times.
51
+ @_data ||= @_data_block.call
52
+ end
38
53
  end
39
54
 
40
55
  # @overload meta(value)
@@ -77,6 +92,15 @@ module JSONAPI
77
92
  def link(name, &block)
78
93
  @_links[name] = Link.as_jsonapi(@_param_hash, &block)
79
94
  end
95
+
96
+ private
97
+
98
+ # @api private
99
+ def _resources_for(models, resource_class)
100
+ resource_class ||= @_resource_inferer
101
+
102
+ ResourceBuilder.build(models, @_param_hash, resource_class)
103
+ end
80
104
  end
81
105
  end
82
106
  end
@@ -0,0 +1,72 @@
1
+ require 'jsonapi/renderer'
2
+
3
+ module JSONAPI
4
+ module Serializable
5
+ class Renderer
6
+ def self.render(resources, options)
7
+ new(resources, options).render
8
+ end
9
+
10
+ def initialize(resources, options)
11
+ @resources = resources
12
+ @options = options.dup
13
+ @klass = @options.delete(:class)
14
+ @namespace = @options.delete(:namespace)
15
+ @inferer = @options.delete(:inferer)
16
+ @exposures = @options.delete(:expose) || {}
17
+ @exposures[:_resource_inferer] = namespace_inferer || @inferer
18
+ end
19
+
20
+ def render
21
+ JSONAPI.render(jsonapi_params.merge(data: jsonapi_resources)).to_json
22
+ end
23
+
24
+ private
25
+
26
+ def jsonapi_params
27
+ @options
28
+ end
29
+
30
+ def jsonapi_resources
31
+ toplevel_inferer = @klass || @inferer
32
+ JSONAPI::Serializable::ResourceBuilder.build(@resources,
33
+ @exposures,
34
+ toplevel_inferer)
35
+ end
36
+
37
+ def namespace_inferer
38
+ return nil unless @namespace
39
+ proc do |klass|
40
+ names = klass.name.split('::')
41
+ klass = names.pop
42
+ [@namespace, names, "Serializable#{klass}"].reject(&:nil?).join('::')
43
+ end
44
+ end
45
+ end
46
+
47
+ class ErrorRenderer
48
+ def self.render(errors, options)
49
+ new(errors, options).render
50
+ end
51
+
52
+ def initialize(errors, options)
53
+ @errors = errors
54
+ @options = options.dup
55
+ end
56
+
57
+ def render
58
+ JSONAPI.render(jsonapi_params.merge(errors: jsonapi_errors)).to_json
59
+ end
60
+
61
+ private
62
+
63
+ def jsonapi_params
64
+ @options
65
+ end
66
+
67
+ def jsonapi_errors
68
+ @errors
69
+ end
70
+ end
71
+ end
72
+ end
@@ -34,19 +34,21 @@ module JSONAPI
34
34
  end
35
35
 
36
36
  def as_jsonapi(params = {})
37
- hash = {}
38
- hash[:id] = jsonapi_id
39
- hash[:type] = jsonapi_type
40
- requested_attrs = params[:fields] || self.class.attribute_blocks.keys
41
- attr = attributes(requested_attrs)
42
- hash[:attributes] = attr if attr.any?
43
- requested_rels = params[:fields] || self.class.relationship_blocks.keys
44
- rels = relationships(requested_rels, params[:include] || [])
45
- hash[:relationships] = rels if rels.any?
46
- hash[:links] = links if links.any?
47
- hash[:meta] = meta unless meta.nil?
37
+ return nil if nil?
48
38
 
49
- hash
39
+ {}.tap do |hash|
40
+ hash[:id] = jsonapi_id
41
+ hash[:type] = jsonapi_type
42
+ requested_attrs = params[:fields] || self.class.attribute_blocks.keys
43
+ attrs = attributes(requested_attrs)
44
+ hash[:attributes] = attrs if attrs.any?
45
+ requested_rels = params[:fields] ||
46
+ self.class.relationship_blocks.keys
47
+ rels = relationships(requested_rels, params[:include] || [])
48
+ hash[:relationships] = rels if rels.any?
49
+ hash[:links] = links if links.any?
50
+ hash[:meta] = meta unless meta.nil?
51
+ end
50
52
  end
51
53
 
52
54
  def jsonapi_type
@@ -0,0 +1,72 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ class ResourceBuilder
4
+ DEFAULT_RESOURCE_INFERER = lambda do |model_klass_name|
5
+ names = model_klass_name.split('::'.freeze)
6
+ klass_name = names.pop
7
+ namespace = names.join('::'.freeze)
8
+
9
+ klass_name = [namespace, "Serializable#{klass_name}"]
10
+ .reject(&:nil?)
11
+ .reject(&:empty?)
12
+ .join('::'.freeze)
13
+
14
+ Object.const_get(klass_name)
15
+ end
16
+
17
+ def self.build(models, expose, klass)
18
+ return models if models.nil? ||
19
+ Array(models).first.respond_to?(:as_jsonapi)
20
+
21
+ resources =
22
+ Array(models).map { |model| new(model, expose, klass).resource }
23
+
24
+ models.respond_to?(:each) ? resources : resources.first
25
+ end
26
+
27
+ attr_reader :resource
28
+
29
+ def initialize(model, expose, klass)
30
+ @model = model
31
+ @expose = expose || {}
32
+ @klass = klass
33
+ @resource = serializable_class.new(serializable_params)
34
+ freeze
35
+ end
36
+
37
+ private
38
+
39
+ def serializable_params
40
+ @expose.merge(model: @model)
41
+ end
42
+
43
+ # rubocop:disable Metrics/MethodLength
44
+ def serializable_class
45
+ klass =
46
+ if @klass.respond_to?(:call)
47
+ @klass.call(@model.class.name)
48
+ elsif @klass.is_a?(Hash)
49
+ @klass[@model.class.name.to_sym]
50
+ elsif @klass.nil?
51
+ DEFAULT_RESOURCE_INFERER.call(@model.class.name)
52
+ else
53
+ @klass
54
+ end
55
+
56
+ reify_class(klass)
57
+ end
58
+ # rubocop:enable Metrics/MethodLength
59
+
60
+ def reify_class(klass)
61
+ if klass.is_a?(Class)
62
+ klass
63
+ elsif klass.is_a?(String)
64
+ Object.const_get(klass)
65
+ else
66
+ # TODO(beauby): Raise meaningful exception.
67
+ raise
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -97,6 +97,9 @@ module JSONAPI
97
97
  def relationship(name, &block)
98
98
  relationship_blocks[name] = block
99
99
  end
100
+ alias has_many relationship
101
+ alias has_one relationship
102
+ alias belongs_to relationship
100
103
 
101
104
  # Declare a link for this resource. The properties of the link are set
102
105
  # by providing a block in which the DSL methods of
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-serializable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1.beta2
4
+ version: 0.1.1.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Hosseini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-25 00:00:00.000000000 Z
11
+ date: 2016-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-renderer
@@ -16,43 +16,43 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.1.beta2
20
- type: :development
19
+ version: 0.1.1.beta3
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.1.beta2
26
+ version: 0.1.1.beta3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.9'
33
+ version: '11.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.9'
40
+ version: '11.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.4'
47
+ version: '3.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.4'
55
- description: DSL for building resource classes to be rendered by jsonapi-renderer.
54
+ version: '3.5'
55
+ description: Powerful DSL for building resource classes - efficient and flexible rendering.
56
56
  email: lucas.hosseini@gmail.com
57
57
  executables: []
58
58
  extensions: []
@@ -67,13 +67,11 @@ files:
67
67
  - lib/jsonapi/serializable/model_dsl.rb
68
68
  - lib/jsonapi/serializable/relationship.rb
69
69
  - lib/jsonapi/serializable/relationship_dsl.rb
70
+ - lib/jsonapi/serializable/renderer.rb
70
71
  - lib/jsonapi/serializable/resource.rb
72
+ - lib/jsonapi/serializable/resource_builder.rb
71
73
  - lib/jsonapi/serializable/resource_dsl.rb
72
- - lib/jsonapi/serializable_error.rb
73
- - lib/jsonapi/serializable_link.rb
74
- - lib/jsonapi/serializable_relationship.rb
75
- - lib/jsonapi/serializable_resource.rb
76
- homepage: https://github.com/beauby/jsonapi-serializable
74
+ homepage: https://github.com/jsonapi-rb/serializable
77
75
  licenses:
78
76
  - MIT
79
77
  metadata: {}
@@ -96,5 +94,5 @@ rubyforge_project:
96
94
  rubygems_version: 2.5.1
97
95
  signing_key:
98
96
  specification_version: 4
99
- summary: Build and render JSON API resources.
97
+ summary: Conveniently serialize JSON API resources.
100
98
  test_files: []
@@ -1,93 +0,0 @@
1
- require 'jsonapi/serializable_link'
2
-
3
- module JSONAPI
4
- class SerializableErrorSource
5
- def self.as_jsonapi(params = {})
6
- self.class.new(params).as_jsonapi
7
- end
8
-
9
- def initialize(params = {})
10
- params.each { |k, v| instance_variable_set("@#{k}", v) }
11
- @_data = {}
12
- end
13
-
14
- def as_jsonapi
15
- @_data
16
- end
17
-
18
- private
19
-
20
- def method_missing(name, arg)
21
- @_data[name] = arg
22
- end
23
- end
24
-
25
- class SerializableError
26
- class << self
27
- attr_accessor :id, :id_block, :status, :status_block, :code, :code_block,
28
- :title, :title_block, :detail, :detail_block, :meta,
29
- :meta_block, :source_block, :link_blocks
30
-
31
- [:id, :status, :code, :title, :detail, :meta].each do |key|
32
- define_method(key) do |*args, &block|
33
- send("@#{key}=", args[0])
34
- send("@#{key}_block=", block)
35
- end
36
- end
37
-
38
- def link(name, &block)
39
- link_blocks[name] = block
40
- end
41
-
42
- def source(&block)
43
- self.source_block = block
44
- end
45
- end
46
-
47
- self.link_blocks = {}
48
-
49
- def self.inherited(klass)
50
- super
51
- klass.link_blocks = self.class.link_blocks.dup
52
- end
53
-
54
- def initialize(params = {})
55
- @_param_hash = params
56
- params.each { |k, v| instance_variable_set("@#{k}", v) }
57
- end
58
-
59
- def as_jsonapi
60
- hash = links.any? ? { links: links } : {}
61
- [:id, :status, :code, :title, :detail, :meta, :source]
62
- .each_with_object(hash) do |key, h|
63
- value = send(key)
64
- h[key] = value unless value.nil?
65
- end
66
- end
67
-
68
- private
69
-
70
- def links
71
- @_links ||= self.class.link_blocks.each_with_object({}) do |(k, v), h|
72
- h[k] = JSONAPI::SerializableLink.as_jsonapi(@_param_hash, v)
73
- end
74
- end
75
-
76
- def source
77
- @_source ||=
78
- JSONAPI::SerializableErrorSource.as_jsonapi(@_param_hash,
79
- self.class.source_block)
80
- end
81
-
82
- [:id, :status, :code, :title, :detail, :meta].each do |key|
83
- define_method(key) do
84
- unless instance_variable_defined?("@#{key}")
85
- instance_variable_set("@#{key}",
86
- self.class.send(key) ||
87
- instance_eval(self.class.send("#{key}_block")))
88
- end
89
- instance_variable_get("@#{key}")
90
- end
91
- end
92
- end
93
- end
@@ -1,34 +0,0 @@
1
- module JSONAPI
2
- class SerializableLink
3
- def self.as_jsonapi(param_hash = {}, &block)
4
- new(param_hash, &block).as_jsonapi
5
- end
6
-
7
- def initialize(param_hash = {}, &block)
8
- param_hash.each do |k, v|
9
- instance_variable_set("@#{k}", v)
10
- end
11
- str_value = instance_eval(&block)
12
- @_href ||= str_value
13
- end
14
-
15
- def as_jsonapi
16
- @_hash ||=
17
- if @_meta.nil?
18
- @_href
19
- else
20
- { href: @_href, meta: @_meta }
21
- end
22
- end
23
-
24
- private
25
-
26
- def href(value = nil, &block)
27
- @_href = block.nil? ? value : instance_eval(&block)
28
- end
29
-
30
- def meta(value = nil, &block)
31
- @_meta = block.nil? ? value : instance_eval(&block)
32
- end
33
- end
34
- end
@@ -1,56 +0,0 @@
1
- require 'jsonapi/serializable_link'
2
-
3
- module JSONAPI
4
- class SerializableRelationship
5
- def initialize(param_hash = {}, &block)
6
- @_param_hash = param_hash
7
- @_param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
8
- @_links = {}
9
- instance_eval(&block)
10
- end
11
-
12
- def data(&block)
13
- if block.nil?
14
- @_data ||= @_data_block.call
15
- else
16
- @_data_block = block
17
- end
18
- end
19
-
20
- def as_jsonapi(included)
21
- hash = {}
22
- hash[:links] = @_links if @_links.any?
23
- hash[:meta] = @_meta unless @_meta.nil?
24
- hash[:data] = eval_linkage_data if included
25
-
26
- hash
27
- end
28
-
29
- private
30
-
31
- def eval_linkage_data
32
- @_linkage_data ||=
33
- if @_linkage_data_block
34
- @_linkage_data_block.call
35
- elsif data.respond_to?(:each)
36
- data.map { |res| { type: res.jsonapi_type, id: res.jsonapi_id } }
37
- elsif data.nil?
38
- nil
39
- else
40
- { type: data.jsonapi_type, id: data.jsonapi_id }
41
- end
42
- end
43
-
44
- def linkage_data(&block)
45
- @_linkage_data_block = block
46
- end
47
-
48
- def meta(value = nil)
49
- @_meta = value || yield
50
- end
51
-
52
- def link(name, &block)
53
- @_links[name] = JSONAPI::SerializableLink.as_jsonapi(@_param_hash, &block)
54
- end
55
- end
56
- end
@@ -1,114 +0,0 @@
1
- require 'jsonapi/serializable_link'
2
- require 'jsonapi/serializable_relationship'
3
-
4
- module JSONAPI
5
- class SerializableResource
6
- class << self
7
- attr_accessor :type_val, :type_block, :id_block, :attribute_blocks,
8
- :relationship_blocks, :link_blocks, :meta_val, :meta_block
9
-
10
- def type(value = nil, &block)
11
- self.type_val = value
12
- self.type_block = block
13
- end
14
-
15
- def id(&block)
16
- self.id_block = block
17
- end
18
-
19
- def meta(value = nil, &block)
20
- self.meta_val = value
21
- self.meta_block = block
22
- end
23
-
24
- def attribute(name, &block)
25
- attribute_blocks[name] = block
26
- end
27
-
28
- def relationship(name, &block)
29
- relationship_blocks[name] = block
30
- end
31
-
32
- def link(name, &block)
33
- link_blocks[name] = block
34
- end
35
- end
36
-
37
- self.attribute_blocks = {}
38
- self.relationship_blocks = {}
39
- self.link_blocks = {}
40
-
41
- def self.inherited(klass)
42
- super
43
- klass.attribute_blocks = attribute_blocks.dup
44
- klass.relationship_blocks = relationship_blocks.dup
45
- klass.link_blocks = link_blocks.dup
46
- end
47
-
48
- def initialize(param_hash = {})
49
- param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
50
- @_id = instance_eval(&self.class.id_block)
51
- @_type = self.class.type_val || instance_eval(&self.class.type_block)
52
- @_meta = if self.class.meta_val
53
- self.class.meta_val
54
- elsif self.class.meta_block
55
- instance_eval(&self.class.meta_block)
56
- end
57
- @_attributes = {}
58
- @_relationships = self.class.relationship_blocks
59
- .each_with_object({}) do |(k, v), h|
60
- h[k] = JSONAPI::SerializableRelationship.new(param_hash, &v)
61
- end
62
- @_links = self.class.link_blocks
63
- .each_with_object({}) do |(k, v), h|
64
- h[k] = JSONAPI::SerializableLink.as_jsonapi(param_hash, &v)
65
- end
66
- end
67
-
68
- def as_jsonapi(params = {})
69
- hash = {}
70
- hash[:id] = @_id
71
- hash[:type] = @_type
72
- attr = attributes(params[:fields] || @_attributes.keys)
73
- hash[:attributes] = attr if attr.any?
74
- rels = relationships(params[:field] || @_relationships.keys,
75
- params[:include] || [])
76
- hash[:relationships] = rels if rels.any?
77
- hash[:links] = @_links if @_links.any?
78
- hash[:meta] = @_meta unless @_meta.nil?
79
-
80
- hash
81
- end
82
-
83
- def jsonapi_type
84
- @_type
85
- end
86
-
87
- def jsonapi_id
88
- @_id
89
- end
90
-
91
- def jsonapi_related(include)
92
- @_relationships
93
- .select { |k, _| include.include?(k) }
94
- .each_with_object({}) { |(k, v), h| h[k] = Array(v.data) }
95
- end
96
-
97
- private
98
-
99
- def attributes(fields)
100
- self.class.attribute_blocks
101
- .select { |k, _| !@_attributes.key?(k) && fields.include?(k) }
102
- .each { |k, v| @_attributes[k] = instance_eval(&v) }
103
- @_attributes.select { |k, _| fields.include?(k) }
104
- end
105
-
106
- def relationships(fields, include)
107
- @_relationships
108
- .select { |k, _| fields.include?(k) }
109
- .each_with_object({}) do |(k, v), h|
110
- h[k] = v.as_jsonapi(include.include?(k))
111
- end
112
- end
113
- end
114
- end