jsonapi-serializable 0.1.1.beta2 → 0.1.1.beta3

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: 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