hal_presenter 0.6.0 → 1.0.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
  SHA256:
3
- metadata.gz: 1e7545934daa7962d7706b4e7bc60cb78c9cd75375f6ff32a09618229b3df767
4
- data.tar.gz: 042d67754faeb73d9bac72067f478c9bf1ce62053e32eb380b9c37e8c22c8147
3
+ metadata.gz: 2fe4271a7912587144464a955caafd6d5391f34b6f2ed3a41f5daa5249a39eeb
4
+ data.tar.gz: c17ab721cbbd1ff37ae96fa921a3a3bb1d003f67943c13863058dfda60a42e4d
5
5
  SHA512:
6
- metadata.gz: 89e17c89c666b5f284c69fa9c0d8bc114270e138c03942cdd0c5046220b97525e5e6ac24e3cbaeab176ac703cab96f9e7dd1df7a87e9597490bc52ccdc38b469
7
- data.tar.gz: febb52acd4490e3527caa92bdb6b82b90701efe734f6474e5e4464786bf413c7ad9c8e84488bb17ec5241cecf60aae412bd68459b1a2a8a0f192b2077ca2f252
6
+ metadata.gz: b0d7657cdb1609fe0a9e9a072be80ef61b9f9b8df31750575d9cbe007fdef6f86668b4a4c84431c1b94e04165195704eaced191443b8eaa7a3d91909f8b5bcc8
7
+ data.tar.gz: 9dac165e3f659f3e36c7d1e3f3ec8af60cb74e93152f5f68361b1b13037157fac157d0b5a40e92a60425a2b6c686f2c46a47a43a5da001bbe3efb8d022a4de28
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,3 @@
1
- =����:�fZ�f����3��J7���rS�`g���v"M��+��sfԏV�٢��E��ώ�&^�'�0�p�45զ�����r1hy�<J�����*t����x��(G�"�+)G��aC�^ {�]M
2
- U��)<=T�k,�bLc���+^Dm'9B�m�Ҋ4.|z9�zNfԦR_��~z�Юg�Υ#]y��˷*��]bod��dJ�k��lve�L
3
- 9���GIMה;A%}~
1
+ Sp�gLP@b ��ܘ��Lb���šד��y����� 6��n��K��B}���`V0���3FX:���}��� �tT�a���ݷ<C���� #��@�t<�";�#�
2
+ PӦ���[@���ib ���z��1̢��>���L�
3
+ ������ئ�R������-nv;:L};���c�({f���ІXɲ�
@@ -3,7 +3,7 @@ require 'hal_presenter/property'
3
3
  module HALPresenter
4
4
  module Attributes
5
5
  def attribute(*args, **kw_args, &block)
6
- @_attributes ||= init_attributes
6
+ @_attributes ||= __init_attributes
7
7
  @_attributes = @_attributes.reject { |attr| attr.name == args.first }
8
8
  @_attributes << Property.new(*args, **kw_args, &block)
9
9
  end
@@ -11,16 +11,16 @@ module HALPresenter
11
11
  protected
12
12
 
13
13
  def attributes
14
- @_attributes ||= init_attributes
14
+ @_attributes ||= __init_attributes
15
15
  end
16
16
 
17
17
  private
18
18
 
19
- def init_attributes
19
+ def __init_attributes
20
20
  return [] unless Class === self
21
21
  return [] unless superclass.respond_to?(:attributes, true)
22
22
  superclass.attributes.each do |attr|
23
- attr.change_scope(self)
23
+ attr.change_context(self)
24
24
  end
25
25
  end
26
26
  end
@@ -37,7 +37,7 @@ module HALPresenter
37
37
  protected
38
38
 
39
39
  def collection_properties
40
- @_collection_properties ||= init_collection_params
40
+ @_collection_properties ||= __init_collection_params
41
41
  end
42
42
 
43
43
  def can_serialize_collection?
@@ -46,7 +46,7 @@ module HALPresenter
46
46
 
47
47
  private
48
48
 
49
- def init_collection_params
49
+ def __init_collection_params
50
50
  return unless Class === self
51
51
  if superclass.respond_to?(:collection_properties, true)
52
52
  superclass.collection_properties
@@ -2,28 +2,41 @@ require 'hal_presenter/property'
2
2
 
3
3
  module HALPresenter
4
4
  module Curies
5
- def curie(rel, value = nil, **kw_args, &block)
5
+ class Curie < HALPresenter::Property
6
+ def to_h(resource = nil, options = {})
7
+ href = value(resource, options)
8
+ return {} unless href
9
+
10
+ {
11
+ name: name,
12
+ href: HALPresenter.href(href),
13
+ templated: true
14
+ }
15
+ end
16
+ end
17
+
18
+ def curie(rel, value = nil, embed_depth: nil, &block)
6
19
  if value.nil? && !block_given?
7
20
  raise 'curie must be called with non nil value or be given a block'
8
21
  end
9
- @_curies ||= init_curies
22
+ @_curies ||= __init_curies
10
23
  @_curies = @_curies.reject { |curie| curie.name == rel }
11
- @_curies << Property.new(rel, value, **kw_args, &block)
24
+ @_curies << Curie.new(rel, value, embed_depth: embed_depth, &block)
12
25
  end
13
26
 
14
27
  protected
15
28
 
16
29
  def curies
17
- @_curies ||= init_curies
30
+ @_curies ||= __init_curies
18
31
  end
19
32
 
20
33
  private
21
34
 
22
- def init_curies
35
+ def __init_curies
23
36
  return [] unless Class === self
24
37
  return [] unless superclass.respond_to?(:curies, true)
25
38
  superclass.curies.each do |curie|
26
- curie.change_scope(self)
39
+ curie.change_context(self)
27
40
  end
28
41
  end
29
42
  end
@@ -12,7 +12,7 @@ module HALPresenter
12
12
  end
13
13
 
14
14
  def embed(*args, **kw_args, &block)
15
- @_embedded ||= init_embedded
15
+ @_embedded ||= __init_embedded
16
16
  @_embedded = @_embedded.reject { |embed| embed.name == args.first }
17
17
  @_embedded << Embed.new(*args, **kw_args, &block)
18
18
  end
@@ -20,16 +20,16 @@ module HALPresenter
20
20
  protected
21
21
 
22
22
  def embedded
23
- @_embedded ||= init_embedded
23
+ @_embedded ||= __init_embedded
24
24
  end
25
25
 
26
26
  private
27
27
 
28
- def init_embedded
28
+ def __init_embedded
29
29
  return [] unless Class === self
30
30
  return [] unless superclass.respond_to?(:embedded, true)
31
31
  superclass.embedded.each do |embed|
32
- embed.change_scope(self)
32
+ embed.change_context(self)
33
33
  end
34
34
  end
35
35
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HALPresenter
4
+ class LazyEvaluator
5
+ attr_reader :resource, :options
6
+ alias resources resource
7
+
8
+ def initialize(block)
9
+ @__context = eval 'self', block.binding
10
+ define_singleton_method(:evaluate_block, &block)
11
+ end
12
+
13
+ def update_context(context)
14
+ @__context = context
15
+ end
16
+
17
+ def evaluate(resource, options)
18
+ @resource = resource
19
+ @options = options || {}
20
+ evaluate_block
21
+ ensure
22
+ @resource = nil
23
+ @options = nil
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :__context
29
+
30
+ def method_missing(method, *args, &block)
31
+ return super unless __context.respond_to?(method)
32
+
33
+ define_singleton_method(method) do |*a, &b|
34
+ __context.public_send(method, *a, &b)
35
+ end
36
+
37
+ public_send(method, *args, &block)
38
+ end
39
+
40
+ def respond_to_missing?(method, _include_private = false)
41
+ __context.respond_to?(method) || super
42
+ end
43
+ end
44
+ end
@@ -15,39 +15,59 @@ module HALPresenter
15
15
  module Links
16
16
 
17
17
  class Link < HALPresenter::Property
18
- attr_reader :http_method
19
- def initialize(rel, value = nil, **kw_args, &block)
18
+ attr_reader :type, :deprecation, :profile, :title
19
+ attr_accessor :templated
20
+
21
+ def initialize(rel, value = nil, **kwargs, &block)
20
22
  if value.nil? && !block_given?
21
23
  raise 'link must be called with non nil value or be given a block'
22
24
  end
23
- @http_method = kw_args.delete(:method) || kw_args.delete(:methods)
24
- super(rel, value, **kw_args, &block)
25
+ @type = kwargs[:type]
26
+ @deprecation = kwargs[:deprecation]
27
+ @profile = kwargs[:profile]
28
+ @title = kwargs[:title]
29
+ super(rel, value, embed_depth: kwargs[:embed_depth], &block)
25
30
  end
26
31
 
27
32
  def rel
28
33
  name
29
34
  end
35
+
36
+ def to_h(resource = nil, options = {})
37
+ href = value(resource, options)
38
+ return {} unless href
39
+
40
+ hash = {href: HALPresenter.href(href)}.tap do |h|
41
+ h[:type] = type if type
42
+ h[:deprecation] = deprecation if deprecation
43
+ h[:profile] = profile if profile
44
+ h[:title] = title if title
45
+ h[:templated] = templated if templated
46
+ end
47
+
48
+ {rel => hash}
49
+ end
30
50
  end
31
51
 
32
- def link(rel, value = nil, **kw_args, &block)
33
- @_links ||= init_links
52
+ def link(rel, value = nil, **kwargs, &block)
53
+ @_links ||= __init_links
34
54
  @_links = @_links.reject { |link| link.rel == rel }
35
- @_links << Link.new(rel, value, **kw_args, &block)
55
+ @_links << Link.new(rel, value, **kwargs, &block)
36
56
  end
37
57
 
38
58
  protected
39
59
 
40
60
  def links
41
- @_links ||= init_links
61
+ @_links ||= __init_links
42
62
  end
43
63
 
44
64
  private
45
65
 
46
- def init_links
66
+ def __init_links
47
67
  return [] unless Class === self
48
68
  return [] unless superclass.respond_to?(:links, true)
49
69
  superclass.links.each do |link|
50
- link.change_scope(self)
70
+ link.change_context(self)
51
71
  end
52
72
  end
53
73
  end
@@ -8,12 +8,12 @@ module HALPresenter
8
8
  protected
9
9
 
10
10
  def policy_class
11
- @_policy ||= init_policy
11
+ @_policy ||= __init_policy
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def init_policy
16
+ def __init_policy
17
17
  return unless Class === self
18
18
  return unless superclass.respond_to?(:policy_class, true)
19
19
  superclass.policy_class
@@ -1,58 +1,30 @@
1
+ require 'hal_presenter/lazy_evaluator'
2
+
1
3
  module HALPresenter
2
4
  class Property
3
- attr_reader :name, :resource, :embed_depth, :options
4
5
 
5
- alias :resources :resource
6
+ attr_reader :name, :embed_depth
6
7
 
7
8
  def initialize(name, value = nil, embed_depth: nil, &block)
8
- @name = name
9
+ @name = name.to_sym
9
10
  @value = value
10
11
  @embed_depth = embed_depth
11
- @scope = nil
12
- return unless block_given?
13
- @scope = eval 'self', block.binding
14
- define_singleton_method(:value_from_block, &block)
12
+ @lazy = block_given? && LazyEvaluator.new(block)
15
13
  end
16
14
 
17
- def value(resource = nil, options = {})
18
- @resource = resource
19
- @options = options
20
- if scope
21
- value_from_block
15
+ def value(resource = nil, options = nil)
16
+ if @lazy
17
+ @lazy.evaluate(resource, options)
22
18
  elsif resource && @value.nil?
23
19
  resource.public_send(name) if resource.respond_to?(name)
24
20
  else
25
21
  @value
26
22
  end
27
- ensure
28
- reset
29
- end
30
-
31
- def change_scope(new_scope)
32
- return unless scope
33
- @scope = new_scope
34
- end
35
-
36
- def method_missing(method, *args, &block)
37
- if scope&.respond_to? method
38
- define_singleton_method(method) { |*a, &b| scope.public_send method, *a, &b }
39
- return public_send(method, *args, &block)
40
- end
41
- super
42
- end
43
-
44
- def respond_to_missing?(method, include_private = false)
45
- return true if scope&.respond_to? method
46
- super
47
23
  end
48
24
 
49
- private
50
-
51
- attr_reader :scope
52
-
53
- def reset
54
- @resource = nil
55
- @options = nil
25
+ def change_context(context)
26
+ return unless @lazy
27
+ @lazy.update_context(context)
56
28
  end
57
29
  end
58
30
  end
@@ -27,12 +27,12 @@ module HALPresenter
27
27
  protected
28
28
 
29
29
  def post_serialize_hook
30
- @_post_serialize_hook ||= init_post_serialize_hook
30
+ @_post_serialize_hook ||= __init_post_serialize_hook
31
31
  end
32
32
 
33
33
  private
34
34
 
35
- def init_post_serialize_hook
35
+ def __init_post_serialize_hook
36
36
  return unless Class === self
37
37
  return unless superclass.respond_to?(:post_serialize_hook, true)
38
38
  superclass.post_serialize_hook
@@ -26,6 +26,7 @@ module HALPresenter
26
26
  def to_hal(resource = nil, options = {})
27
27
  options[:_depth] ||= 0
28
28
  hash = to_hash(resource, options)
29
+ move_curies_to_top! hash
29
30
  JSON.generate(hash)
30
31
  end
31
32
 
@@ -38,6 +39,7 @@ module HALPresenter
38
39
  options[:paginate] = HALPresenter.paginate unless options.key? :paginate
39
40
  options[:_depth] ||= 0
40
41
  hash = to_collection_hash(resources, options)
42
+ move_curies_to_top! hash
41
43
  JSON.generate(hash)
42
44
  end
43
45
 
@@ -71,6 +73,7 @@ module HALPresenter
71
73
  serialized[:_embedded] = embedded[:_embedded] || {}
72
74
 
73
75
  # Embedded resources
76
+ options[:_depth] += 1
74
77
  serialized_resources = resources.map { |resource| to_hash(resource, options) }
75
78
  serialized[:_embedded].merge!({properties.name => serialized_resources })
76
79
  end
@@ -85,20 +88,47 @@ module HALPresenter
85
88
  end
86
89
 
87
90
  def serialize_curies(resource, policy, options)
88
- _serialize_curies(curies, resource, policy, options)
91
+ _serialize_curies(curies, resource, options)
89
92
  end
90
93
 
91
94
  def serialize_embedded(resource, policy, options)
92
95
  _serialize_embedded(embedded, resource, policy, options)
93
96
  end
94
97
 
98
+ private
99
+
100
+ def move_curies_to_top!(hash)
101
+ curies = {}
102
+ find_curies(hash).each do |curie|
103
+ name = curie[:name]
104
+ curies[name] = curie
105
+ end
106
+
107
+ return if curies.empty?
108
+
109
+ hash[:_links] ||= {}
110
+ hash[:_links][:curies] = curies.values
111
+ end
112
+
113
+ def find_curies(hash)
114
+ return [] if Hash(hash).empty?
115
+
116
+ curies = hash[:_links].delete(:curies) if hash.key? :_links
117
+ curies ||= []
118
+
119
+ hash.fetch(:_embedded, {}).values.each do |embedded|
120
+ collection = embedded.is_a?(Array) ? embedded : [embedded]
121
+ collection.each { |resrc| curies += find_curies(resrc) }
122
+ end
123
+
124
+ curies
125
+ end
126
+
95
127
  def run_post_serialize_hook!(resource, options, serialized)
96
128
  hook = post_serialize_hook
97
129
  hook&.run(resource, options, serialized)
98
130
  end
99
131
 
100
- private
101
-
102
132
  def _serialize_attributes(attributes, resource, policy, options)
103
133
  attributes.each_with_object({}) do |attribute, hash|
104
134
  next unless nested_depth_ok?(attribute, options[:_depth])
@@ -111,26 +141,19 @@ module HALPresenter
111
141
  serialized = links.each_with_object({}) do |link, hash|
112
142
  next unless nested_depth_ok?(link, options[:_depth])
113
143
  next if policy && !policy.link?(link.rel)
114
- href = link.value(resource, options) or next
115
- hash[link.rel] = { href: HALPresenter.href(href) }.tap do |s|
116
- s[:method] = link.http_method if link.http_method
117
- end
144
+ hash.merge! link.to_h(resource, options)
118
145
  end
119
- curies = _serialize_curies(curies, resource, policy, options)
146
+ curies = _serialize_curies(curies, resource, options)
120
147
  serialized[:curies] = curies if curies.any?
121
148
  return {} if serialized.empty?
122
149
  { _links: serialized }
123
150
  end
124
151
 
125
- def _serialize_curies(curies, resource, policy, options)
152
+ def _serialize_curies(curies, resource, options)
126
153
  curies.each_with_object([]) do |curie, array|
127
154
  next unless nested_depth_ok?(curie, options[:_depth])
128
- href = curie.value(resource, options) or next
129
- array << {
130
- name: curie.name,
131
- href: HALPresenter.href(href),
132
- templated: true
133
- }
155
+ hash = curie.to_h(resource, options)
156
+ array << hash unless hash.empty?
134
157
  end
135
158
  end
136
159
 
@@ -179,5 +202,3 @@ module HALPresenter
179
202
  end
180
203
  end
181
204
  end
182
-
183
-
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hal_presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sammy Henningsson
@@ -30,7 +30,7 @@ cert_chain:
30
30
  ZMhjYR7sRczGJx+GxGU2EaR0bjRsPVlC4ywtFxoOfRG3WaJcpWGEoAoMJX6Z0bRv
31
31
  M40=
32
32
  -----END CERTIFICATE-----
33
- date: 2019-02-22 00:00:00.000000000 Z
33
+ date: 2019-03-08 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rake
@@ -166,6 +166,7 @@ files:
166
166
  - lib/hal_presenter/curies.rb
167
167
  - lib/hal_presenter/deserializer.rb
168
168
  - lib/hal_presenter/embedded.rb
169
+ - lib/hal_presenter/lazy_evaluator.rb
169
170
  - lib/hal_presenter/links.rb
170
171
  - lib/hal_presenter/model.rb
171
172
  - lib/hal_presenter/pagination.rb
metadata.gz.sig CHANGED
Binary file