jsonapi-serializable 0.1.1.beta3 → 0.1.1.beta4

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: 1a382b6d5802f167908d0d6ee82605a7a52d43a0
4
- data.tar.gz: 9c9211218919e4a05e74b010cbc9a5ad51c6533e
3
+ metadata.gz: 5b7a55ca51fb13e04ac2c96153ea3558aef19d35
4
+ data.tar.gz: 7a378903d6206bdc7cb203bd47a5ec415034ec87
5
5
  SHA512:
6
- metadata.gz: bf14811ff7b926f43b45c9cf49032d3fc0c0fe507d4c446d2108fd948de2c5c782cba5b3e90bfe5e6893ee0ef18dcddaf6c91de9e7052445fae25f1b747f65e0
7
- data.tar.gz: 14e585466ae7124d51c0d7562e52fbff0982f91025ed71ad9f6a01e1100379b241e1ccea9248d2ebe84a273bdf50d020671b41a80c672f819226c4cfdc0c9a69
6
+ metadata.gz: a29424f72a6a0170319503da5f7aa3a8bb62633cdcd496d0e0ae89f5a7431fe6b9dd763e8ff6fe44aa2823fa897c191434f6fe211836cc3133dcc57654ebb065
7
+ data.tar.gz: 18ead5e2f56d6cad50e432c4d09f5f7590df9d27e1b52348d0d3ca1f72e8efd22065d0c763cd3e1b8340ab692fb7c1fb8633674f572dc5dfa9eeb5475a19d66f
data/README.md CHANGED
@@ -11,11 +11,8 @@ the [jsonapi-renderer](https://github.com/jsonapi-rb/renderer) gem.
11
11
 
12
12
  - [Installation](#installation)
13
13
  - [Usage](#usage)
14
- - [Example for Model-based Resources](#example-for-model-based-resources)
15
- - [Example for General Resources](#example-for-general-resources)
16
14
  - [Documentation](#documentation)
17
15
  - [`JSONAPI::Serializable::Resource` DSL](#jsonapiserializableresource-dsl)
18
- - [`JSONAPI::Serializable::Model` DSL](#jsonapiserializablemodel-dsl)
19
16
  - [`JSONAPI::Serializable::Relationship` DSL](#jsonapiserializablerelationship-dsl)
20
17
  - [`JSONAPI::Serializable::Link` DSL](#jsonapiserializablelink-dsl)
21
18
  - [`JSONAPI::Serializable::Error` DSL](#jsonapiserializableerror-dsl)
@@ -44,26 +41,22 @@ require 'jsonapi/serializable'
44
41
 
45
42
  Then, define some resource classes:
46
43
 
47
- ### Example for Model-based Resources
48
-
49
- For resources that are simple representations of models, the DSL is simplified:
50
-
51
44
  ```ruby
52
- class PostResource < JSONAPI::Serializable::Model
45
+ class PostResource < JSONAPI::Serializable::Resource
53
46
  type 'posts'
54
47
 
55
48
  attribute :title
56
49
 
57
50
  attribute :date do
58
- @model.created_at
51
+ @object.created_at
59
52
  end
60
53
 
61
- has_one :author, UserResource do
54
+ has_one :author, 'V2::SerializableUser' do
62
55
  link(:self) do
63
- href @url_helper.link_for_rel('posts', @model.id, 'author')
56
+ href @url_helpers.link_for_rel('posts', @object.id, 'author')
64
57
  meta link_meta: 'some meta'
65
58
  end
66
- link(:related) { @url_helper.link_for_res('users', @model.author.id) }
59
+ link(:related) { @url_helpers.link_for_res('users', @object.author.id) }
67
60
  meta do
68
61
  { relationship_meta: 'some meta' }
69
62
  end
@@ -76,78 +69,24 @@ class PostResource < JSONAPI::Serializable::Model
76
69
  end
77
70
 
78
71
  link(:self) do
79
- @url_helper.link_for_res('posts', @model.id)
72
+ @url_helpers.link_for_res('posts', @object.id)
80
73
  end
81
74
  end
82
75
  ```
83
76
 
84
- Then, build your resources from your models and render them:
85
- ```ruby
86
- # post = some post model
87
- # UrlHelper is some helper class
88
- resource = PostResource.new(model: post, url_helper: UrlHelper)
89
- document = JSONAPI.render(data: resource)
90
- ```
91
-
92
- ### Example for General Resources
93
-
94
- In case your resource is not a simple representation of one of your models,
95
- the more general `JSONAPI::Serializable::Resource` class can be used.
96
-
97
- ```ruby
98
- class PostResource < JSONAPI::Serializable::Resource
99
- type 'posts'
100
-
101
- id do
102
- @post.id.to_s
103
- end
104
-
105
- attribute :title do
106
- @post.title
107
- end
108
-
109
- attribute :date do
110
- @post.date
111
- end
112
-
113
- relationship :author do
114
- link(:self) do
115
- href @url_helper.link_for_rel('posts', @post.id, 'author')
116
- meta link_meta: 'some meta'
117
- end
118
- link(:related) { @url_helper.link_for_res('users', @post.author.id) }
119
- data do
120
- if @post.author.nil?
121
- nil
122
- else
123
- UserResource.new(user: @post.author, url_helper: @url_helper)
124
- end
125
- end
126
- meta do
127
- { relationship_meta: 'some meta' }
128
- end
129
- end
130
-
131
- meta do
132
- { resource_meta: 'some meta' }
133
- end
134
-
135
- link(:self) do
136
- @url_helper.link_for_res('posts', @post.id)
137
- end
138
- end
139
- ```
140
- Finally, build your resources from your models and render them:
77
+ Then, render your resources:
141
78
  ```ruby
142
- # post = some post model
143
- # UrlHelper is some helper class
144
- resource = PostResource.new(post: post, url_helper: UrlHelper)
145
- document = JSONAPI.render(data: resource)
79
+ # `post` is some `Post` object
80
+ # `UrlHelpers` is some helper class
81
+ document = JSONAPI::Serializable::Renderer.render(
82
+ post,
83
+ expose: { url_helpers: UrlHelpers.new }
84
+ )
146
85
  ```
147
86
 
148
87
  ## Documentation
149
88
 
150
- ### `JSONAPI::Serializable::Resource` DSL
89
+ ### `JSONAPI::Serializable::AbstractResource` DSL
151
90
 
152
91
  + `#initialize(hash)`
153
92
 
@@ -156,8 +95,8 @@ variables within all DSLs.
156
95
 
157
96
  Example:
158
97
  ```ruby
159
- SerializablePost.new(post: post, url_helper: url_helper)
160
- # => You can then use @post and @url_helper from within the DSL.
98
+ SerializablePost.new(post: post, url_helpers: url_helpers)
99
+ # => You can then use @post and @url_helpers from within the DSL.
161
100
  ```
162
101
 
163
102
  + `::type(value = nil, &block)`
@@ -191,13 +130,13 @@ the [`JSONAPI::Serializable::Relationship` DSL](#jsonapiserializablerelationship
191
130
  Example:
192
131
  ```ruby
193
132
  relationship :comments do
194
- data do
133
+ resources do
195
134
  @post.comments.map do |c|
196
- SerializableComment.new(comment: c, url_helper: @url_helper)
135
+ SerializableComment.new(comment: c, url_helpers: @url_helpers)
197
136
  end
198
137
  end
199
138
  link :self do
200
- @url_helper.link_for_post_comments(post_id: @post.id)
139
+ @url_helpers.link_for_post_comments(post_id: @post.id)
201
140
  end
202
141
  meta do
203
142
  { count: @post.comments.count }
@@ -232,25 +171,25 @@ meta do
232
171
  end
233
172
  ```
234
173
 
235
- ### `JSONAPI::Serializable::Model` DSL
174
+ ### `JSONAPI::Serializable::Resource` DSL
236
175
 
237
- This class is a subclass of `JSONAPI::Serializable::Resource` with a more
176
+ This class is a subclass of `JSONAPI::Serializable::AbstractResource` with a more
238
177
  convenient DSL tailored for resources that are direct representation of some
239
178
  business models.
240
179
 
241
180
  + `#initialize(hash)`
242
181
 
243
- See `JSONAPI::Serializable::Resource` DSL.
182
+ See `JSONAPI::Serializable::AbstractResource` DSL.
244
183
 
245
184
  The model is expected to be provided in the hash with the key `:model`.
246
185
 
247
186
  + `::type(value = nil, &block)`
248
187
 
249
- See `JSONAPI::Serializable::Resource` DSL.
188
+ See `JSONAPI::Serializable::AbstractResource` DSL.
250
189
 
251
190
  + `::id(&block)`
252
191
 
253
- See `JSONAPI::Serializable::Resource` DSL.
192
+ See `JSONAPI::Serializable::AbstractResource` DSL.
254
193
 
255
194
  Defaults to:
256
195
  ```ruby
@@ -259,7 +198,7 @@ id { @model.id }
259
198
 
260
199
  + `::attribute(key, &block)`
261
200
 
262
- See `JSONAPI::Serializable::Resource` DSL.
201
+ See `JSONAPI::Serializable::AbstractResource` DSL.
263
202
 
264
203
  Defaults to the following when no block is provided:
265
204
  ```ruby
@@ -268,6 +207,10 @@ attribute key do
268
207
  end
269
208
  ```
270
209
 
210
+ + `::attributes(*keys)`
211
+
212
+ Define multiple attributes.
213
+
271
214
  + `::has_one(key, resource_klass = nil, &block)`
272
215
 
273
216
  Define a `has_one` relationship on the resource.
@@ -296,28 +239,28 @@ end
296
239
 
297
240
  + `::relationship(key, &block)`
298
241
 
299
- See `JSONAPI::Serializable::Resource` DSL.
242
+ See `JSONAPI::Serializable::AbstractResource` DSL.
300
243
 
301
244
  + `::link(key, &block)`
302
245
 
303
- See `JSONAPI::Serializable::Resource` DSL.
246
+ See `JSONAPI::Serializable::AbstractResource` DSL.
304
247
 
305
248
  + `::meta(value = nil, &block)`
306
249
 
307
- See `JSONAPI::Serializable::Resource` DSL.
250
+ See `JSONAPI::Serializable::AbstractResource` DSL.
308
251
 
309
252
  ### `JSONAPI::Serializable::Relationship` DSL
310
253
 
311
- + `::data(resource_class = nil, &block)`
254
+ + `::resources(resource_class = nil, &block)`
312
255
 
313
- NOTE: This section is outdated. It is still valid, but the data method is now
314
- much more flexible.
256
+ NOTE: This section is outdated. It is still valid, but the resources method is
257
+ now much more flexible.
315
258
 
316
259
  Defines the related serializable resources for the relationship.
317
260
 
318
261
  Example:
319
262
  ```ruby
320
- data do
263
+ resources do
321
264
  if @post.author.nil?
322
265
  nil
323
266
  else
@@ -326,17 +269,21 @@ data do
326
269
  end
327
270
  ```
328
271
 
272
+ + `::data(&block)`
273
+
274
+ Explicitly define linkage data (optional).
275
+
329
276
  + `::link(key, &block)`
330
277
 
331
278
  Define a relationship-level link.
332
279
 
333
- See `JSONAPI::Serializable::Resource` DSL.
280
+ See `JSONAPI::Serializable::AbstractResource` DSL.
334
281
 
335
282
  + `::meta(value = nil, &block)`
336
283
 
337
284
  Define some relationship-level meta member.
338
285
 
339
- See `JSONAPI::Serializable::Resource` DSL.
286
+ See `JSONAPI::Serializable::AbstractResource` DSL.
340
287
 
341
288
  ### `JSONAPI::Serializable::Link` DSL
342
289
 
@@ -0,0 +1,122 @@
1
+ require 'jsonapi/serializable/link'
2
+ require 'jsonapi/serializable/relationship'
3
+ require 'jsonapi/serializable/abstract_resource_dsl'
4
+
5
+ module JSONAPI
6
+ module Serializable
7
+ class AbstractResource
8
+ include AbstractResourceDSL
9
+
10
+ class << self
11
+ attr_accessor :id_block,
12
+ :type_val, :type_block,
13
+ :meta_val, :meta_block,
14
+ :attribute_blocks,
15
+ :relationship_blocks,
16
+ :link_blocks
17
+ end
18
+
19
+ self.attribute_blocks = {}
20
+ self.relationship_blocks = {}
21
+ self.link_blocks = {}
22
+
23
+ def self.inherited(klass)
24
+ super
25
+ klass.type_val = type_val
26
+ klass.type_block = type_block
27
+ klass.id_block = id_block
28
+ klass.meta_val = meta_val
29
+ klass.meta_block = meta_block
30
+ klass.attribute_blocks = attribute_blocks.dup
31
+ klass.relationship_blocks = relationship_blocks.dup
32
+ klass.link_blocks = link_blocks.dup
33
+ end
34
+
35
+ def initialize(exposures = {})
36
+ exposures.each { |k, v| instance_variable_set("@#{k}", v) }
37
+ @_exposures = exposures
38
+ @_type = _type
39
+ @_id = _id
40
+ @_attributes = {}
41
+ @_relationships = _relationships
42
+ @_meta = _meta
43
+ @_links = _links
44
+ end
45
+
46
+ def as_jsonapi(fields: nil, include: [])
47
+ {}.tap do |hash|
48
+ hash[:id] = @_id
49
+ hash[:type] = @_type
50
+ hash[:links] = @_links if @_links.any?
51
+ hash[:meta] = @_meta unless @_meta.nil?
52
+
53
+ attrs = requested_attributes(fields)
54
+ hash[:attributes] = attrs if attrs.any?
55
+
56
+ rels = requested_relationships(fields, include)
57
+ hash[:relationships] = rels if rels.any?
58
+ end
59
+ end
60
+
61
+ def jsonapi_type
62
+ @_type
63
+ end
64
+
65
+ def jsonapi_id
66
+ @_id
67
+ end
68
+
69
+ def jsonapi_related(include)
70
+ @_relationships
71
+ .select { |k, _| include.include?(k) }
72
+ .each_with_object({}) { |(k, v), h| h[k] = v.related_resources }
73
+ end
74
+
75
+ private
76
+
77
+ def _type
78
+ self.class.type_val || instance_eval(&self.class.type_block)
79
+ end
80
+
81
+ def _id
82
+ instance_eval(&self.class.id_block)
83
+ end
84
+
85
+ def _relationships
86
+ self.class.relationship_blocks
87
+ .each_with_object({}) do |(k, v), h|
88
+ h[k] = Relationship.new(@_exposures, &v)
89
+ end
90
+ end
91
+
92
+ def _meta
93
+ if self.class.meta_block
94
+ instance_eval(&self.class.meta_block)
95
+ else
96
+ self.class.meta_val
97
+ end
98
+ end
99
+
100
+ def _links
101
+ self.class.link_blocks
102
+ .each_with_object({}) do |(k, v), h|
103
+ h[k] = Link.as_jsonapi(@_exposures, &v)
104
+ end
105
+ end
106
+
107
+ def requested_attributes(fields)
108
+ self.class.attribute_blocks
109
+ .select { |k, _| fields.nil? || fields.include?(k) }
110
+ .each_with_object({}) { |(k, v), h| h[k] = instance_eval(&v) }
111
+ end
112
+
113
+ def requested_relationships(fields, include)
114
+ @_relationships
115
+ .select { |k, _| fields.nil? || fields.include?(k) }
116
+ .each_with_object({}) do |(k, v), h|
117
+ h[k] = v.as_jsonapi(include.include?(k))
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,130 @@
1
+ module JSONAPI
2
+ module Serializable
3
+ module AbstractResourceDSL
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ # @overload type(value)
10
+ # Declare the JSON API type of this resource.
11
+ # @param [String] value The value of the type.
12
+ #
13
+ # @example
14
+ # type 'users'
15
+ #
16
+ # @overload type(value)
17
+ # Declare the JSON API type of this resource.
18
+ # @yieldreturn [String] The value of the type.
19
+ #
20
+ # @example
21
+ # type { @user.admin? ? "admin" : "users" }
22
+ def type(value = nil, &block)
23
+ self.type_val = value
24
+ self.type_block = block
25
+ end
26
+
27
+ # Declare the JSON API id of this resource.
28
+ #
29
+ # @yieldreturn [String] The id of the resource.
30
+ #
31
+ # @example
32
+ # id { @user.id.to_s }
33
+ def id(&block)
34
+ self.id_block = block
35
+ end
36
+
37
+ # @overload meta(value)
38
+ # Declare the meta information for this resource.
39
+ # @param [Hash] value The meta information hash.
40
+ #
41
+ # @example
42
+ # meta key: value
43
+ #
44
+ # @overload meta(&block)
45
+ # Declare the meta information for this resource.
46
+ # @yieldreturn [String] The meta information hash.
47
+ # @example
48
+ # meta do
49
+ # { key: value }
50
+ # end
51
+ def meta(value = nil, &block)
52
+ self.meta_val = value
53
+ self.meta_block = block
54
+ end
55
+
56
+ # Declare an attribute for this resource.
57
+ #
58
+ # @param [Symbol] name The key of the attribute.
59
+ # @yieldreturn [Hash, String, nil] The block to compute the value.
60
+ #
61
+ # @example
62
+ # attribute(:name) { @user.name }
63
+ def attribute(name, &block)
64
+ attribute_blocks[name] = block
65
+ end
66
+
67
+ # Declare a relationship for this resource. The properties of the
68
+ # relationship are set by providing a block in which the DSL methods
69
+ # of +JSONAPI::Serializable::Relationship+ are called.
70
+ # @see JSONAPI::Serializable::Relationship
71
+ #
72
+ # @param [Symbol] name The key of the relationship.
73
+ #
74
+ # @example
75
+ # relationship :posts do
76
+ # data { @user.posts.map { |p| PostResource.new(post: p) } }
77
+ # end
78
+ #
79
+ # @example
80
+ # relationship :author do
81
+ # data do
82
+ # @post.author && UserResource.new(user: @post.author)
83
+ # end
84
+ # linkage_data do
85
+ # { type: 'users', id: @post.author_id }
86
+ # end
87
+ # link(:self) do
88
+ # "http://api.example.com/posts/#{@post.id}/relationships/author"
89
+ # end
90
+ # link(:related) do
91
+ # "http://api.example.com/posts/#{@post.id}/author"
92
+ # end
93
+ # meta do
94
+ # { author_online: @post.author.online? }
95
+ # end
96
+ # end
97
+ def relationship(name, &block)
98
+ relationship_blocks[name] = block
99
+ end
100
+ alias has_many relationship
101
+ alias has_one relationship
102
+ alias belongs_to relationship
103
+
104
+ # Declare a link for this resource. The properties of the link are set
105
+ # by providing a block in which the DSL methods of
106
+ # +JSONAPI::Serializable::Link+ are called, or the value of the link
107
+ # is returned directly.
108
+ # @see JSONAPI::Serialiable::Link
109
+ #
110
+ # @param [Symbol] name The key of the link.
111
+ # @yieldreturn [Hash, String, nil] The block to compute the value, if
112
+ # any.
113
+ #
114
+ # @example
115
+ # link(:self) do
116
+ # "http://api.example.com/users/#{@user.id}"
117
+ # end
118
+ #
119
+ # @example
120
+ # link(:self) do
121
+ # href "http://api.example.com/users/#{@user.id}"
122
+ # meta is_self: true
123
+ # end
124
+ def link(name, &block)
125
+ link_blocks[name] = block
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -40,9 +40,9 @@ module JSONAPI
40
40
  klass.link_blocks = self.class.link_blocks.dup
41
41
  end
42
42
 
43
- def initialize(params = {})
44
- @_param_hash = params
45
- params.each { |k, v| instance_variable_set("@#{k}", v) }
43
+ def initialize(exposures = {})
44
+ @_exposures = exposures
45
+ exposures.each { |k, v| instance_variable_set("@#{k}", v) }
46
46
  end
47
47
 
48
48
  def as_jsonapi
@@ -58,12 +58,12 @@ module JSONAPI
58
58
 
59
59
  def links
60
60
  @_links ||= self.class.link_blocks.each_with_object({}) do |(k, v), h|
61
- h[k] = Link.as_jsonapi(@_param_hash, v)
61
+ h[k] = Link.as_jsonapi(@_exposures, v)
62
62
  end
63
63
  end
64
64
 
65
65
  def source
66
- @_source ||= ErrorSource.as_jsonapi(@_param_hash,
66
+ @_source ||= ErrorSource.as_jsonapi(@_exposures,
67
67
  self.class.source_block)
68
68
  end
69
69
 
@@ -1,12 +1,12 @@
1
1
  module JSONAPI
2
2
  module Serializable
3
3
  class Link
4
- def self.as_jsonapi(param_hash = {}, &block)
5
- new(param_hash, &block).as_jsonapi
4
+ def self.as_jsonapi(exposures = {}, &block)
5
+ new(exposures, &block).as_jsonapi
6
6
  end
7
7
 
8
- def initialize(param_hash = {}, &block)
9
- param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
8
+ def initialize(exposures = {}, &block)
9
+ exposures.each { |k, v| instance_variable_set("@#{k}", v) }
10
10
  static_value = instance_eval(&block)
11
11
  if static_value.is_a?(Hash)
12
12
  @_hash = static_value
@@ -6,31 +6,42 @@ module JSONAPI
6
6
  class Relationship
7
7
  include RelationshipDSL
8
8
 
9
- def initialize(param_hash = {}, &block)
10
- param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
11
- @_param_hash = param_hash
12
- @_links = {}
9
+ def initialize(exposures = {}, &block)
10
+ exposures.each { |k, v| instance_variable_set("@#{k}", v) }
11
+ @_exposures = exposures
12
+ @_links = {}
13
13
  instance_eval(&block)
14
14
  end
15
15
 
16
16
  def as_jsonapi(included)
17
- hash = {}
18
- hash[:links] = @_links if @_links.any?
19
- hash[:meta] = @_meta unless @_meta.nil?
20
- return hash unless included || (!@_links.any? && @_meta.nil?)
21
- hash[:data] = linkage_data
17
+ {}.tap do |hash|
18
+ hash[:links] = @_links if @_links.any?
19
+ hash[:meta] = @_meta unless @_meta.nil?
20
+ include_linkage = included || (!@_links.any? && @_meta.nil?)
21
+ hash[:data] = linkage_data if include_linkage
22
+ end
23
+ end
24
+
25
+ def related_resources
26
+ return @_related_resources if @_related_resources
22
27
 
23
- hash
28
+ resources = @_resources_block.call
29
+ @_arity = resources.respond_to?(:each) ? :many : :one
30
+ @_related_resources = Array(resources)
31
+
32
+ @_related_resources
24
33
  end
25
34
 
26
35
  private
27
36
 
28
37
  def linkage_data
29
- linkage_data = Array(data).map do |res|
38
+ return @_linkage_block.call if @_linkage_block
39
+
40
+ linkage_data = related_resources.map do |res|
30
41
  { type: res.jsonapi_type, id: res.jsonapi_id }
31
42
  end
32
43
 
33
- data.respond_to?(:each) ? linkage_data : linkage_data.first
44
+ @_arity == :many ? linkage_data : linkage_data.first
34
45
  end
35
46
  end
36
47
  end
@@ -3,55 +3,58 @@ require 'jsonapi/serializable/resource_builder'
3
3
  module JSONAPI
4
4
  module Serializable
5
5
  module RelationshipDSL
6
- # Declare the data for this relationship.
6
+ # Declare the related resources for this relationship.
7
7
  # @param [String,Constant,Hash{Symbol=>String,Constant}] resource_class
8
- # @yieldreturn The data for this relationship.
8
+ # @yieldreturn The related resources for this relationship.
9
9
  # If it is nil, an object implementing the Serializable::Resource
10
10
  # interface, an empty array, or an array of objects implementing the
11
11
  # Serializable::Resource interface, then it is used as is.
12
- # Otherwise an appropriate Serializable::Model subclass is inferred
12
+ # Otherwise an appropriate Serializable::Resource subclass is inferred
13
13
  # from the object(s)' namespace/class, the resource_class parameter if
14
14
  # provided, and the @_resource_inferer.
15
15
  #
16
16
  # @example
17
- # data do
17
+ # resources do
18
18
  # @user.posts.map { |p| PostResource.new(post: p) }
19
19
  # end
20
20
  #
21
21
  # @example
22
- # data do
22
+ # resources do
23
23
  # @post.author && UserResource.new(user: @user.author)
24
24
  # end
25
25
  #
26
26
  # @example
27
- # data do
27
+ # resources do
28
28
  # @user.posts
29
29
  # end
30
30
  # end
31
31
  #
32
32
  # @example
33
- # data SerializablePost do
33
+ # resources SerializablePost do
34
34
  # @user.posts
35
35
  # end
36
36
  #
37
37
  # @example
38
- # data "SerializableUser" do
38
+ # resources "SerializableUser" do
39
39
  # @post.author
40
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
41
+ def resources(resource_class = nil)
42
+ # NOTE(beauby): Lazify computation since it is only needed when
43
+ # the corresponding relationship is included.
44
+ @_resources_block = proc do
45
+ _resources_for(yield, resource_class)
52
46
  end
53
47
  end
54
48
 
49
+ # Explicitly declare linkage data.
50
+ # @yieldreturn The resource linkage.
51
+ def data(&block)
52
+ # NOTE(beauby): Lazify computation since it is only executed when
53
+ # the corresponding relationship is included (or no links and
54
+ # no meta was specified).
55
+ @_linkage_block = block
56
+ end
57
+
55
58
  # @overload meta(value)
56
59
  # Declare the meta information for this relationship.
57
60
  # @param [Hash] value The meta information hash.
@@ -90,16 +93,16 @@ module JSONAPI
90
93
  # meta authorization_needed: true
91
94
  # end
92
95
  def link(name, &block)
93
- @_links[name] = Link.as_jsonapi(@_param_hash, &block)
96
+ @_links[name] = Link.as_jsonapi(@_exposures, &block)
94
97
  end
95
98
 
96
99
  private
97
100
 
98
101
  # @api private
99
- def _resources_for(models, resource_class)
102
+ def _resources_for(objects, resource_class)
100
103
  resource_class ||= @_resource_inferer
101
104
 
102
- ResourceBuilder.build(models, @_param_hash, resource_class)
105
+ ResourceBuilder.build(objects, @_exposures, resource_class)
103
106
  end
104
107
  end
105
108
  end
@@ -1,14 +1,15 @@
1
1
  require 'jsonapi/renderer'
2
+ require 'jsonapi/serializable/resource_builder'
2
3
 
3
4
  module JSONAPI
4
5
  module Serializable
5
6
  class Renderer
6
- def self.render(resources, options)
7
- new(resources, options).render
7
+ def self.render(objects, options)
8
+ new(objects, options).render
8
9
  end
9
10
 
10
- def initialize(resources, options)
11
- @resources = resources
11
+ def initialize(objects, options)
12
+ @objects = objects
12
13
  @options = options.dup
13
14
  @klass = @options.delete(:class)
14
15
  @namespace = @options.delete(:namespace)
@@ -29,7 +30,7 @@ module JSONAPI
29
30
 
30
31
  def jsonapi_resources
31
32
  toplevel_inferer = @klass || @inferer
32
- JSONAPI::Serializable::ResourceBuilder.build(@resources,
33
+ JSONAPI::Serializable::ResourceBuilder.build(@objects,
33
34
  @exposures,
34
35
  toplevel_inferer)
35
36
  end
@@ -1,106 +1,12 @@
1
- require 'jsonapi/serializable/link'
2
- require 'jsonapi/serializable/relationship'
1
+ require 'jsonapi/serializable/abstract_resource'
3
2
  require 'jsonapi/serializable/resource_dsl'
4
3
 
5
4
  module JSONAPI
6
5
  module Serializable
7
- class Resource
6
+ class Resource < AbstractResource
8
7
  include ResourceDSL
9
8
 
10
- class << self
11
- attr_accessor :type_val, :type_block, :id_block, :attribute_blocks,
12
- :relationship_blocks, :link_blocks, :meta_val, :meta_block
13
- end
14
-
15
- self.attribute_blocks = {}
16
- self.relationship_blocks = {}
17
- self.link_blocks = {}
18
-
19
- def self.inherited(klass)
20
- super
21
- klass.type_val = type_val
22
- klass.type_block = type_block
23
- klass.id_block = id_block
24
- klass.meta_val = meta_val
25
- klass.meta_block = meta_block
26
- klass.attribute_blocks = attribute_blocks.dup
27
- klass.relationship_blocks = relationship_blocks.dup
28
- klass.link_blocks = link_blocks.dup
29
- end
30
-
31
- def initialize(param_hash = {})
32
- @_param_hash = param_hash
33
- param_hash.each { |k, v| instance_variable_set("@#{k}", v) }
34
- end
35
-
36
- def as_jsonapi(params = {})
37
- return nil if nil?
38
-
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
52
- end
53
-
54
- def jsonapi_type
55
- @_type ||= self.class.type_val || instance_eval(&self.class.type_block)
56
- end
57
-
58
- def jsonapi_id
59
- @_id ||= instance_eval(&self.class.id_block)
60
- end
61
-
62
- def jsonapi_related(include)
63
- @_relationships
64
- .select { |k, _| include.include?(k) }
65
- .each_with_object({}) { |(k, v), h| h[k] = Array(v.data) }
66
- end
67
-
68
- private
69
-
70
- def attributes(fields)
71
- @_attributes ||= {}
72
- self.class.attribute_blocks
73
- .select { |k, _| !@_attributes.key?(k) && fields.include?(k) }
74
- .each { |k, v| @_attributes[k] = instance_eval(&v) }
75
- @_attributes.select { |k, _| fields.include?(k) }
76
- end
77
-
78
- def relationships(fields, include)
79
- @_relationships ||= self.class.relationship_blocks
80
- .each_with_object({}) do |(k, v), h|
81
- h[k] = Relationship.new(@_param_hash, &v)
82
- end
83
- @_relationships
84
- .select { |k, _| fields.include?(k) }
85
- .each_with_object({}) do |(k, v), h|
86
- h[k] = v.as_jsonapi(include.include?(k))
87
- end
88
- end
89
-
90
- def meta
91
- @_meta ||=
92
- if self.class.meta_val
93
- self.class.meta_val
94
- elsif self.class.meta_block
95
- instance_eval(&self.class.meta_block)
96
- end
97
- end
98
-
99
- def links
100
- @_links ||= self.class.link_blocks.each_with_object({}) do |(k, v), h|
101
- h[k] = Link.as_jsonapi(@_param_hash, &v)
102
- end
103
- end
9
+ id { @object.public_send(:id).to_s }
104
10
  end
105
11
  end
106
12
  end
@@ -1,8 +1,8 @@
1
1
  module JSONAPI
2
2
  module Serializable
3
3
  class ResourceBuilder
4
- DEFAULT_RESOURCE_INFERER = lambda do |model_klass_name|
5
- names = model_klass_name.split('::'.freeze)
4
+ DEFAULT_RESOURCE_INFERER = lambda do |object_klass_name|
5
+ names = object_klass_name.split('::'.freeze)
6
6
  klass_name = names.pop
7
7
  namespace = names.join('::'.freeze)
8
8
 
@@ -14,20 +14,21 @@ module JSONAPI
14
14
  Object.const_get(klass_name)
15
15
  end
16
16
 
17
- def self.build(models, expose, klass)
18
- return models if models.nil? ||
19
- Array(models).first.respond_to?(:as_jsonapi)
17
+ def self.build(objects, expose, klass)
18
+ return objects if objects.nil? ||
19
+ Array(objects).first.respond_to?(:as_jsonapi)
20
20
 
21
- resources =
22
- Array(models).map { |model| new(model, expose, klass).resource }
23
-
24
- models.respond_to?(:each) ? resources : resources.first
21
+ if objects.respond_to?(:each)
22
+ objects.map { |obj| new(obj, expose, klass).resource }
23
+ else
24
+ new(objects, expose, klass).resource
25
+ end
25
26
  end
26
27
 
27
28
  attr_reader :resource
28
29
 
29
- def initialize(model, expose, klass)
30
- @model = model
30
+ def initialize(object, expose, klass)
31
+ @object = object
31
32
  @expose = expose || {}
32
33
  @klass = klass
33
34
  @resource = serializable_class.new(serializable_params)
@@ -37,18 +38,18 @@ module JSONAPI
37
38
  private
38
39
 
39
40
  def serializable_params
40
- @expose.merge(model: @model)
41
+ @expose.merge(object: @object)
41
42
  end
42
43
 
43
44
  # rubocop:disable Metrics/MethodLength
44
45
  def serializable_class
45
46
  klass =
46
47
  if @klass.respond_to?(:call)
47
- @klass.call(@model.class.name)
48
+ @klass.call(@object.class.name)
48
49
  elsif @klass.is_a?(Hash)
49
- @klass[@model.class.name.to_sym]
50
+ @klass[@object.class.name.to_sym]
50
51
  elsif @klass.nil?
51
- DEFAULT_RESOURCE_INFERER.call(@model.class.name)
52
+ DEFAULT_RESOURCE_INFERER.call(@object.class.name)
52
53
  else
53
54
  @klass
54
55
  end
@@ -6,124 +6,27 @@ module JSONAPI
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- # @overload type(value)
10
- # Declare the JSON API type of this resource.
11
- # @param [String] value The value of the type.
12
- #
13
- # @example
14
- # type 'users'
15
- #
16
- # @overload type(value)
17
- # Declare the JSON API type of this resource.
18
- # @yieldreturn [String] The value of the type.
19
- #
20
- # @example
21
- # type { @user.admin? ? "admin" : "users" }
22
- def type(value = nil, &block)
23
- self.type_val = value
24
- self.type_block = block
9
+ def attribute(attr, &block)
10
+ block ||= proc { @object.public_send(attr) }
11
+ super(attr, &block)
25
12
  end
26
13
 
27
- # Declare the JSON API id of this resource.
28
- #
29
- # @yieldreturn [String] The id of the resource.
30
- #
31
- # @example
32
- # id { @user.id.to_s }
33
- def id(&block)
34
- self.id_block = block
14
+ def attributes(*args)
15
+ args.each do |attr|
16
+ attribute(attr)
17
+ end
35
18
  end
36
19
 
37
- # @overload meta(value)
38
- # Declare the meta information for this resource.
39
- # @param [Hash] value The meta information hash.
40
- #
41
- # @example
42
- # meta key: value
43
- #
44
- # @overload meta(&block)
45
- # Declare the meta information for this resource.
46
- # @yieldreturn [String] The meta information hash.
47
- # @example
48
- # meta do
49
- # { key: value }
50
- # end
51
- def meta(value = nil, &block)
52
- self.meta_val = value
53
- self.meta_block = block
54
- end
55
-
56
- # Declare an attribute for this resource.
57
- #
58
- # @param [Symbol] name The key of the attribute.
59
- # @yieldreturn [Hash, String, nil] The block to compute the value.
60
- #
61
- # @example
62
- # attribute(:name) { @user.name }
63
- def attribute(name, &block)
64
- attribute_blocks[name] = block
65
- end
66
-
67
- # Declare a relationship for this resource. The properties of the
68
- # relationship are set by providing a block in which the DSL methods
69
- # of +JSONAPI::Serializable::Relationship+ are called.
70
- # @see JSONAPI::Serializable::Relationship
71
- #
72
- # @param [Symbol] name The key of the relationship.
73
- #
74
- # @example
75
- # relationship :posts do
76
- # data { @user.posts.map { |p| PostResource.new(post: p) } }
77
- # end
78
- #
79
- # @example
80
- # relationship :author do
81
- # data do
82
- # @post.author && UserResource.new(user: @post.author)
83
- # end
84
- # linkage_data do
85
- # { type: 'users', id: @post.author_id }
86
- # end
87
- # link(:self) do
88
- # "http://api.example.com/posts/#{@post.id}/relationships/author"
89
- # end
90
- # link(:related) do
91
- # "http://api.example.com/posts/#{@post.id}/author"
92
- # end
93
- # meta do
94
- # { author_online: @post.author.online? }
95
- # end
96
- # end
97
- def relationship(name, &block)
98
- relationship_blocks[name] = block
20
+ def relationship(rel, resource_class = nil, &block)
21
+ rel_block = proc do
22
+ resources(resource_class) { @object.public_send(rel) }
23
+ instance_eval(&block) unless block.nil?
24
+ end
25
+ super(rel, &rel_block)
99
26
  end
100
27
  alias has_many relationship
101
28
  alias has_one relationship
102
29
  alias belongs_to relationship
103
-
104
- # Declare a link for this resource. The properties of the link are set
105
- # by providing a block in which the DSL methods of
106
- # +JSONAPI::Serializable::Link+ are called, or the value of the link
107
- # is returned directly.
108
- # @see JSONAPI::Serialiable::Link
109
- #
110
- # @param [Symbol] name The key of the link.
111
- # @yieldreturn [Hash, String, nil] The block to compute the value, if
112
- # any.
113
- #
114
- # @example
115
- # link(:self) do
116
- # "http://api.example.com/users/#{@user.id}"
117
- # end
118
- #
119
- # @example
120
- # link(:self) do
121
- # href "http://api.example.com/users/#{@user.id}"
122
- # meta is_self: true
123
- # end
124
- def link(name, &block)
125
- link_blocks[name] = block
126
- end
127
30
  end
128
31
  end
129
32
  end
@@ -1,4 +1,3 @@
1
1
  require 'jsonapi/serializable/error'
2
- require 'jsonapi/serializable/model'
3
2
  require 'jsonapi/serializable/resource'
4
3
  require 'jsonapi/serializable/renderer'
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.beta3
4
+ version: 0.1.1.beta4
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-11-15 00:00:00.000000000 Z
11
+ date: 2016-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-renderer
@@ -60,11 +60,11 @@ extra_rdoc_files: []
60
60
  files:
61
61
  - README.md
62
62
  - lib/jsonapi/serializable.rb
63
+ - lib/jsonapi/serializable/abstract_resource.rb
64
+ - lib/jsonapi/serializable/abstract_resource_dsl.rb
63
65
  - lib/jsonapi/serializable/error.rb
64
66
  - lib/jsonapi/serializable/error_dsl.rb
65
67
  - lib/jsonapi/serializable/link.rb
66
- - lib/jsonapi/serializable/model.rb
67
- - lib/jsonapi/serializable/model_dsl.rb
68
68
  - lib/jsonapi/serializable/relationship.rb
69
69
  - lib/jsonapi/serializable/relationship_dsl.rb
70
70
  - lib/jsonapi/serializable/renderer.rb
@@ -1,12 +0,0 @@
1
- require 'jsonapi/serializable/model_dsl'
2
- require 'jsonapi/serializable/resource'
3
-
4
- module JSONAPI
5
- module Serializable
6
- class Model < Resource
7
- include ModelDSL
8
-
9
- id { @model.public_send(:id).to_s }
10
- end
11
- end
12
- end
@@ -1,27 +0,0 @@
1
- module JSONAPI
2
- module Serializable
3
- module ModelDSL
4
- def self.included(base)
5
- base.extend(ClassMethods)
6
- end
7
-
8
- module ClassMethods
9
- def attribute(attr, &block)
10
- block ||= proc { @model.public_send(attr) }
11
- super(attr, &block)
12
- end
13
-
14
- def relationship(rel, resource_class = nil, &block)
15
- rel_block = proc do
16
- data(resource_class) { @model.public_send(rel) }
17
- instance_eval(&block) unless block.nil?
18
- end
19
- super(rel, &rel_block)
20
- end
21
- alias has_many relationship
22
- alias has_one relationship
23
- alias belongs_to relationship
24
- end
25
- end
26
- end
27
- end