jsonapi-serializable 0.2.1 → 0.3.0

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: a2bfb6228e6b03c8bde3724af76fdbcedc097e0e
4
- data.tar.gz: 28e75ac8293502f8e2a617c79fff3f803ca172d7
3
+ metadata.gz: e06e5be75e2c53c3f257807493bb7c896a669241
4
+ data.tar.gz: b0c29ac61252006bc763a1e08567037cff3f9e49
5
5
  SHA512:
6
- metadata.gz: 909fa65c618b4507da112491cc7b84646c07146dd027c5ba52386509ed9ea090916b413e78940f3fd4dad8cc2c518d56bd727953ad871ef4b404205ba5c9f39d
7
- data.tar.gz: 8d924e246526821a8ab66d571054cdbe50b235c3d909e5c4c3ca935d6f57fac9b6221e3dcde1ce81eeebfcd32e99bf40bbc87e980a1113c0811bf7c76a32133a
6
+ metadata.gz: a3d7759a8a216e92a71e56f1324082a69b6f51ce69653136c39187b527a37dafd2dd17919c70b1389b48412938098af9d6f83fdfaa0167be257e09cb18b6c8fd
7
+ data.tar.gz: 333ba881f8e1799bd2db5a0ed8c92b86f5906530550f0a0e03de63d451d41d66b0674198e91c572d312aee21c9f02d6048480fddc615451373828f06f62b504f
@@ -35,12 +35,6 @@ module JSONAPI
35
35
  :link_blocks
36
36
  end
37
37
 
38
- def self.create(hash)
39
- hash.each_with_object(new) do |(k, v), e|
40
- e.instance_variable_set("@_#{k}", v)
41
- end
42
- end
43
-
44
38
  self.link_blocks = {}
45
39
 
46
40
  def self.inherited(klass)
@@ -1,38 +1,31 @@
1
- require 'jsonapi/serializable/resource_builder'
2
-
3
1
  module JSONAPI
4
2
  module Serializable
5
3
  class Relationship
6
4
  module DSL
7
5
  # Declare the related resources for this relationship.
8
6
  # @yieldreturn The related resources 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::Resource subclass is inferred
13
- # from the object(s)' namespace/class, the `class` relationship
14
- # option, and the @_resource_builder.
15
- #
16
- # @example
17
- # data do
18
- # @user.posts.map { |p| PostResource.new(post: p) }
19
- # end
20
- #
21
- # @example
22
- # data do
23
- # @post.author && UserResource.new(user: @user.author)
24
- # end
25
7
  #
26
8
  # @example
27
9
  # data do
28
- # @user.posts
10
+ # @object.posts
29
11
  # end
30
12
  # end
31
13
  def data
32
14
  # NOTE(beauby): Lazify computation since it is only needed when
33
15
  # the corresponding relationship is included.
34
16
  @_resources_block = proc do
35
- @_resource_builder.build(yield, @_exposures, @_options[:class])
17
+ resources = yield
18
+ if resources.nil?
19
+ nil
20
+ elsif resources.respond_to?(:to_ary)
21
+ Array(resources).map do |obj|
22
+ @_class[obj.class.name.to_sym]
23
+ .new(@_exposures.merge(object: obj))
24
+ end
25
+ else
26
+ @_class[resources.class.name.to_sym]
27
+ .new(@_exposures.merge(object: resources))
28
+ end
36
29
  end
37
30
  end
38
31
 
@@ -1,9 +1,8 @@
1
1
  require 'jsonapi/renderer'
2
- require 'jsonapi/serializable/resource_builder'
3
2
 
4
3
  module JSONAPI
5
4
  module Serializable
6
- class SuccessRenderer
5
+ class Renderer
7
6
  def initialize(renderer = JSONAPI::Renderer.new)
8
7
  @renderer = renderer
9
8
  end
@@ -11,13 +10,9 @@ module JSONAPI
11
10
  # Serialize resources into a JSON API document.
12
11
  #
13
12
  # @param resources [nil,Object,Array]
14
- # @param options [Hash]@see JSONAPI.render
15
- # @option class [Class,Symbol,String,Hash{Symbol,String=>Class,Symbol,String}]
16
- # The serializable resource class(es) to use for the primary resources.
17
- # @option namespace [String] The namespace in which to look for
18
- # serializable resource classes.
19
- # @option inferrer [#call] The callable used for inferring a serializable
20
- # resource class name from a resource class name.
13
+ # @param options [Hash] @see JSONAPI.render
14
+ # @option class [Hash{Symbol=>Class}] A map specifying for each type
15
+ # the corresponding serializable resource class.
21
16
  # @option expose [Hash] The exposures made available in serializable
22
17
  # resource class instances as instance variables.
23
18
  # @return [Hash]
@@ -27,7 +22,7 @@ module JSONAPI
27
22
  # # => { data: nil }
28
23
  #
29
24
  # @example
30
- # renderer.render(user)
25
+ # renderer.render(user, class: { User: SerializableUser })
31
26
  # # => {
32
27
  # data: {
33
28
  # type: 'users',
@@ -38,52 +33,60 @@ module JSONAPI
38
33
  # }
39
34
  #
40
35
  # @example
41
- # renderer.render([user1, user2])
36
+ # renderer.render([user1, user2], class: { User: SerializableUser })
42
37
  # # => { data: [{ type: 'users', id: 'foo', ... }, ...] }
43
38
  def render(resources, options = {})
44
39
  options = options.dup
45
- klass = options.delete(:class)
46
- namespace = options.delete(:namespace)
47
- inferrer = options.delete(:inferrer) || namespace_inferrer(namespace)
48
- expose = options.delete(:expose) || {}
49
- resource_builder = JSONAPI::Serializable::ResourceBuilder.new(inferrer)
50
- exposures = expose.merge(_resource_builder: resource_builder)
40
+ klass = options.delete(:class) || {}
41
+ exposures = options.delete(:expose) || {}
42
+ exposures = exposures.merge(_class: klass)
51
43
 
52
- resources = resource_builder.build(resources, exposures, klass)
44
+ resources = build_resources(resources, exposures, klass)
53
45
 
54
46
  @renderer.render(options.merge(data: resources))
55
47
  end
56
48
 
57
- private
58
-
59
- # @api private
60
- def namespace_inferrer(namespace)
61
- proc do |class_name|
62
- names = class_name.split('::')
63
- klass = names.pop
64
- [namespace, *names, "Serializable#{klass}"].reject(&:nil?).join('::')
65
- end
66
- end
67
- end
68
-
69
- class ErrorsRenderer
70
- def initialize(renderer = JSONAPI::Renderer.new)
71
- @renderer = renderer
72
- end
73
-
74
49
  # Serialize errors into a JSON API document.
75
50
  #
76
51
  # @param errors [Array]
77
52
  # @param options [Hash] @see JSONAPI.render
53
+ # @option class [Hash{Symbol=>Class}] A map specifying for each type
54
+ # the corresponding serializable error class.
55
+ # @option expose [Hash] The exposures made available in serializable
56
+ # error class instances as instance variables.
78
57
  # @return [Hash]
79
58
  #
80
59
  # @example
81
60
  # error = JSONAPI::Serializable::Error.create(id: 'foo', title: 'bar')
82
61
  # renderer.render([error])
83
62
  # # => { errors: [{ id: 'foo', title: 'bar' }] }
84
- def render(errors, options = {})
63
+ def render_errors(errors, options = {})
64
+ options = options.dup
65
+ klass = options.delete(:class) || {}
66
+ exposures = options.delete(:expose) || {}
67
+
68
+ errors = errors.map { |e| _build(e, exposures, klass) }
69
+
85
70
  @renderer.render(options.merge(errors: errors))
86
71
  end
72
+
73
+ private
74
+
75
+ # @api private
76
+ def build_resources(resources, exposures, klass)
77
+ if resources.nil?
78
+ nil
79
+ elsif resources.respond_to?(:to_ary)
80
+ Array(resources).map { |obj| _build(obj, exposures, klass) }
81
+ else
82
+ _build(resources, exposures, klass)
83
+ end
84
+ end
85
+
86
+ # @api private
87
+ def _build(object, exposures, klass)
88
+ klass[object.class.name.to_sym].new(exposures.merge(object: object))
89
+ end
87
90
  end
88
91
  end
89
92
  end
@@ -1,5 +1,3 @@
1
- require 'jsonapi/serializable/resource_builder'
2
-
3
1
  require 'jsonapi/serializable/resource/dsl'
4
2
 
5
3
  require 'jsonapi/serializable/link'
@@ -18,9 +16,7 @@ module JSONAPI
18
16
 
19
17
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
20
18
  def initialize(exposures = {})
21
- @_exposures = {
22
- _resource_builder: JSONAPI::Serializable::ResourceBuilder.new
23
- }.merge(exposures)
19
+ @_exposures = exposures
24
20
  @_exposures.each { |k, v| instance_variable_set("@#{k}", v) }
25
21
 
26
22
  @_id = instance_eval(&self.class.id_block).to_s
@@ -81,6 +77,12 @@ module JSONAPI
81
77
  .each_with_object({}) { |(k, v), h| h[k] = v.related_resources }
82
78
  end
83
79
 
80
+ def jsonapi_cache_key(options)
81
+ "#{jsonapi_type} - #{jsonapi_id}" \
82
+ "- #{options[:include].to_a.sort}" \
83
+ "- #{(options[:fields] || Set.new).to_a.sort}"
84
+ end
85
+
84
86
  private
85
87
 
86
88
  # @api private
@@ -29,14 +29,14 @@ module JSONAPI
29
29
  attr_accessor :link_condition_blocks
30
30
  end
31
31
  self.field_condition_blocks ||= {}
32
- self.link_condition_blocks ||= {}
32
+ self.link_condition_blocks ||= {}
33
33
  end
34
34
  end
35
35
 
36
36
  def inherited(klass)
37
37
  super
38
38
  klass.field_condition_blocks = field_condition_blocks.dup
39
- klass.link_condition_blocks = link_condition_blocks.dup
39
+ klass.link_condition_blocks = link_condition_blocks.dup
40
40
  end
41
41
 
42
42
  # Handle the `if` and `unless` options for attributes.
@@ -34,7 +34,7 @@ module JSONAPI
34
34
  # @yieldreturn [String] The id of the resource.
35
35
  #
36
36
  # @example
37
- # id { @user.id.to_s }
37
+ # id { @object.id.to_s }
38
38
  def id(&block)
39
39
  self.id_block = block
40
40
  end
@@ -93,12 +93,12 @@ module JSONAPI
93
93
  #
94
94
  # @example
95
95
  # link(:self) do
96
- # "http://api.example.com/users/#{@user.id}"
96
+ # "http://api.example.com/users/#{@object.id}"
97
97
  # end
98
98
  #
99
99
  # @example
100
100
  # link(:self) do
101
- # href "http://api.example.com/users/#{@user.id}"
101
+ # href "http://api.example.com/users/#{@object.id}"
102
102
  # meta is_self: true
103
103
  # end
104
104
  def link(name, &block)
@@ -133,26 +133,21 @@ module JSONAPI
133
133
  # @param [Hash] options The options for the relationship.
134
134
  #
135
135
  # @example
136
- # relationship :posts do
137
- # resources { @user.posts.map { |p| PostResource.new(post: p) } }
138
- # end
139
- #
140
- # @example
141
136
  # relationship :author do
142
- # resources do
143
- # @post.author && UserResource.new(user: @post.author)
144
- # end
145
137
  # data do
146
- # { type: 'users', id: @post.author_id }
138
+ # @object.author
139
+ # end
140
+ # linkage do
141
+ # { type: 'users', id: @object.author_id }
147
142
  # end
148
143
  # link(:self) do
149
- # "http://api.example.com/posts/#{@post.id}/relationships/author"
144
+ # "http://api.example.com/posts/#{@object.id}/relationships/author"
150
145
  # end
151
146
  # link(:related) do
152
- # "http://api.example.com/posts/#{@post.id}/author"
147
+ # "http://api.example.com/posts/#{@object.id}/author"
153
148
  # end
154
149
  # meta do
155
- # { author_online: @post.author.online? }
150
+ # { author_online: @object.author.online? }
156
151
  # end
157
152
  # end
158
153
  def relationship(name, options = {}, &block)
@@ -164,8 +159,8 @@ module JSONAPI
164
159
  relationship_options[name.to_sym] = options
165
160
  end
166
161
 
167
- alias has_many relationship
168
- alias has_one relationship
162
+ alias has_many relationship
163
+ alias has_one relationship
169
164
  alias belongs_to relationship
170
165
  end
171
166
  end
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.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Hosseini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-13 00:00:00.000000000 Z
11
+ date: 2017-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-renderer
@@ -16,20 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.1'
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 0.1.3
19
+ version: 0.2.0
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '0.1'
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 0.1.3
26
+ version: 0.2.0
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: rake
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -59,19 +53,33 @@ dependencies:
59
53
  - !ruby/object:Gem::Version
60
54
  version: '3.5'
61
55
  - !ruby/object:Gem::Dependency
62
- name: codecov
56
+ name: simplecov
63
57
  requirement: !ruby/object:Gem::Requirement
64
58
  requirements:
65
- - - "~>"
59
+ - - ">="
66
60
  - !ruby/object:Gem::Version
67
- version: '0.1'
61
+ version: '0'
68
62
  type: :development
69
63
  prerelease: false
70
64
  version_requirements: !ruby/object:Gem::Requirement
71
65
  requirements:
72
- - - "~>"
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: benchmark-ips
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
73
81
  - !ruby/object:Gem::Version
74
- version: '0.1'
82
+ version: '0'
75
83
  description: Powerful DSL for building resource classes - efficient and flexible rendering.
76
84
  email: lucas.hosseini@gmail.com
77
85
  executables: []
@@ -90,9 +98,6 @@ files:
90
98
  - lib/jsonapi/serializable/resource/conditional_fields.rb
91
99
  - lib/jsonapi/serializable/resource/dsl.rb
92
100
  - lib/jsonapi/serializable/resource/key_format.rb
93
- - lib/jsonapi/serializable/resource/relationship.rb
94
- - lib/jsonapi/serializable/resource/relationship/dsl.rb
95
- - lib/jsonapi/serializable/resource_builder.rb
96
101
  homepage: https://github.com/jsonapi-rb/jsonapi-serializable
97
102
  licenses:
98
103
  - MIT
@@ -113,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
118
  version: '0'
114
119
  requirements: []
115
120
  rubyforge_project:
116
- rubygems_version: 2.6.12
121
+ rubygems_version: 2.6.13
117
122
  signing_key:
118
123
  specification_version: 4
119
124
  summary: Conveniently serialize JSON API resources.
@@ -1,62 +0,0 @@
1
- require 'jsonapi/serializable/link'
2
- require 'jsonapi/serializable/resource/relationship/dsl'
3
-
4
- module JSONAPI
5
- module Serializable
6
- class Resource
7
- class Relationship
8
- include DSL
9
-
10
- def initialize(exposures = {}, options = {}, &block)
11
- exposures.each { |k, v| instance_variable_set("@#{k}", v) }
12
- @_exposures = exposures
13
- @_options = options
14
- @_links = {}
15
- instance_eval(&block)
16
- end
17
-
18
- def as_jsonapi(included)
19
- {}.tap do |hash|
20
- hash[:links] = @_links if @_links.any?
21
- hash[:data] = linkage_data if included || @_include_linkage
22
- hash[:meta] = @_meta unless @_meta.nil?
23
- hash[:meta] = { included: false } if hash.empty?
24
- end
25
- end
26
-
27
- # @api private
28
- def related_resources
29
- @_related_resources ||= Array(resources)
30
- end
31
-
32
- # @api private
33
- def links
34
- @_links
35
- end
36
-
37
- # @api private
38
- def meta
39
- @_meta
40
- end
41
-
42
- # @api private
43
- def resources
44
- @_resources ||= @_resources_block.call
45
- end
46
-
47
- private
48
-
49
- # @api private
50
- def linkage_data
51
- return @_linkage_block.call if @_linkage_block
52
-
53
- linkage_data = related_resources.map do |res|
54
- { type: res.jsonapi_type, id: res.jsonapi_id }
55
- end
56
-
57
- resources.respond_to?(:each) ? linkage_data : linkage_data.first
58
- end
59
- end
60
- end
61
- end
62
- end
@@ -1,103 +0,0 @@
1
- require 'jsonapi/serializable/resource_builder'
2
-
3
- module JSONAPI
4
- module Serializable
5
- class Resource
6
- class Relationship
7
- module DSL
8
- # Declare the related resources for this relationship.
9
- # @yieldreturn The related resources for this relationship.
10
- # If it is nil, an object implementing the Serializable::Resource
11
- # interface, an empty array, or an array of objects implementing the
12
- # Serializable::Resource interface, then it is used as is.
13
- # Otherwise an appropriate Serializable::Resource subclass is
14
- # inferred from the object(s)' namespace/class, the `class`
15
- # relationship option, and the @_resource_builder.
16
- #
17
- # @example
18
- # data do
19
- # @user.posts.map { |p| PostResource.new(post: p) }
20
- # end
21
- #
22
- # @example
23
- # data do
24
- # @post.author && UserResource.new(user: @user.author)
25
- # end
26
- #
27
- # @example
28
- # data do
29
- # @user.posts
30
- # end
31
- # end
32
- def data
33
- # NOTE(beauby): Lazify computation since it is only needed when
34
- # the corresponding relationship is included.
35
- @_resources_block = proc do
36
- @_resource_builder.build(yield, @_exposures, @_options[:class])
37
- end
38
- end
39
-
40
- # @overload linkage(options = {}, &block)
41
- # Explicitly declare linkage data.
42
- # @yieldreturn The resource linkage.
43
- #
44
- # @example
45
- # linkage do
46
- # @object.posts.map { |p| { id: p.id.to_s, type: 'posts' } }
47
- # end
48
- #
49
- # @overload linkage(options = {})
50
- # Forces standard linkage even if relationship not included.
51
- #
52
- # @example
53
- # linkage always: true
54
- def linkage(always: false, &block)
55
- @_include_linkage = always
56
- @_linkage_block = block
57
- end
58
-
59
- # @overload meta(value)
60
- # Declare the meta information for this relationship.
61
- # @param [Hash] value The meta information hash.
62
- #
63
- # @example
64
- # meta paginated: true
65
- #
66
- # @overload meta(&block)
67
- # Declare the meta information for this relationship.
68
- # @yieldreturn [Hash] The meta information hash.
69
- #
70
- # @example
71
- # meta do
72
- # { paginated: true }
73
- # end
74
- def meta(value = nil)
75
- @_meta = value || yield
76
- end
77
-
78
- # Declare a link for this relationship. The properties of the link are set
79
- # by providing a block in which the DSL methods of
80
- # +JSONAPI::Serializable::Link+ are called.
81
- # @see JSONAPI::Serialiable::Link
82
- #
83
- # @param [Symbol] name The key of the link.
84
- # @yieldreturn [Hash, String, nil] The block to compute the value, if any.
85
- #
86
- # @example
87
- # link(:self) do
88
- # "http://api.example.com/users/#{@user.id}/relationships/posts"
89
- # end
90
- #
91
- # @example
92
- # link(:related) do
93
- # href "http://api.example.com/users/#{@user.id}/posts"
94
- # meta authorization_needed: true
95
- # end
96
- def link(name, &block)
97
- @_links[name] = Link.as_jsonapi(@_exposures, &block)
98
- end
99
- end
100
- end
101
- end
102
- end
103
- end
@@ -1,56 +0,0 @@
1
- module JSONAPI
2
- module Serializable
3
- class ResourceBuilder
4
- # @api private
5
- def initialize(inferrer = nil)
6
- @inferrer = inferrer
7
- @lookup_cache = {}
8
-
9
- freeze
10
- end
11
-
12
- # @api private
13
- def build(objects, expose, klass = nil)
14
- return objects if objects.nil? ||
15
- Array(objects).first.respond_to?(:as_jsonapi)
16
-
17
- if objects.respond_to?(:to_ary)
18
- Array(objects).map { |obj| _build(obj, expose, klass) }
19
- else
20
- _build(objects, expose, klass)
21
- end
22
- end
23
-
24
- private
25
-
26
- # @api private
27
- def _build(object, expose, klass)
28
- serializable_class(object.class.name, klass)
29
- .new(expose.merge(object: object))
30
- end
31
-
32
- # @api private
33
- def serializable_class(object_class_name, klass)
34
- klass = klass[object_class_name.to_sym] if klass.is_a?(Hash)
35
-
36
- @lookup_cache[[object_class_name, klass.to_s]] ||=
37
- reify_class(klass || @inferrer.call(object_class_name))
38
- end
39
-
40
- # @api private
41
- def reify_class(klass)
42
- if klass.is_a?(Class)
43
- klass
44
- elsif klass.is_a?(String) || klass.is_a?(Symbol)
45
- begin
46
- Object.const_get(klass)
47
- rescue NameError
48
- raise NameError, "Undefined serializable class #{klass}"
49
- end
50
- else
51
- raise ArgumentError, "Invalid serializable class #{klass}"
52
- end
53
- end
54
- end
55
- end
56
- end