hal_presenter 1.2.1 → 1.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/hal_presenter/curie_collection.rb +158 -0
- data/lib/hal_presenter/deserializer.rb +8 -3
- data/lib/hal_presenter/links.rb +13 -7
- data/lib/hal_presenter/model.rb +27 -21
- data/lib/hal_presenter/pagination.rb +4 -3
- data/lib/hal_presenter/serializer.rb +39 -42
- metadata +4 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10e6de4d852aa101cc4318eb88d152996adeb2e288359a0c9a53f6efcc5e9cc6
|
4
|
+
data.tar.gz: 89080e06a6c5a756bc00d9620663fb8e6eb97906059285666d13f007a4e6b4fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab43657fea638457294930e648d5a33b2a6055ff02e511ba239d55b0b38bb8bad9ea6a3816b2c01674efa38c816876681af075dc5fc6ccb67ad1ebe44a891ae6
|
7
|
+
data.tar.gz: 84f44aa7ef856dbec2e23c56a1aceef04b35b253ebc1dd574c7379aa574f72b57d6b8e969e4a53eff8b7be5da54ecc23ca8d0411d87dbdb2f52a694bb7dcd8a7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module HALPresenter
|
4
|
+
class CurieCollection
|
5
|
+
class CurieWithReferences
|
6
|
+
attr_reader :name, :href, :templated, :rels, :references
|
7
|
+
|
8
|
+
def initialize(curie)
|
9
|
+
@name = curie.fetch(:name)
|
10
|
+
@href = curie.fetch(:href)
|
11
|
+
@templated = curie.fetch(:templated, true)
|
12
|
+
@rels = Hash.new { |hash, key| hash[key] = Set.new }
|
13
|
+
@references = Hash.new do |hash, key|
|
14
|
+
hash[key] = Set.new.compare_by_identity
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_reference(rel, reference, type)
|
19
|
+
rels[type] << rel
|
20
|
+
references[type] << reference
|
21
|
+
end
|
22
|
+
|
23
|
+
def <<(other)
|
24
|
+
other.rels.each do |type, rels|
|
25
|
+
self.rels[type] += rels
|
26
|
+
end
|
27
|
+
other.references.each do |type, references|
|
28
|
+
self.references[type] += references
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def rename(name)
|
33
|
+
self.name = name
|
34
|
+
|
35
|
+
rels.each do |type, rels|
|
36
|
+
rels.each do |rel|
|
37
|
+
new_rel = replace_curie(name, rel)
|
38
|
+
references[type].each do |reference|
|
39
|
+
reference[new_rel] = reference.delete(rel)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_h
|
46
|
+
{
|
47
|
+
name: name,
|
48
|
+
href: href,
|
49
|
+
templated: templated
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_writer :name
|
56
|
+
|
57
|
+
def replace_curie(name, rel)
|
58
|
+
_, rest = rel.to_s.split(':', 2)
|
59
|
+
:"#{name}:#{rest}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
attr_reader :collection
|
64
|
+
|
65
|
+
def self.extract_from!(hash, resolve_collisions: true)
|
66
|
+
new.tap do |curies|
|
67
|
+
curies.add_curies(hash[:_links]&.delete(:curies))
|
68
|
+
curies.send(:add_references, hash[:_links], :links)
|
69
|
+
curies.send(:add_references, hash[:_embedded], :embedded)
|
70
|
+
curies.resolve_collisions! if resolve_collisions
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize
|
75
|
+
@collection = []
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_curies(curies)
|
79
|
+
return unless curies
|
80
|
+
|
81
|
+
curies.each do |curie|
|
82
|
+
next if find(curie[:name])
|
83
|
+
collection << CurieWithReferences.new(curie)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def generate_curie_name(base)
|
88
|
+
name = "#{base}0"
|
89
|
+
name = name.next while find(name.to_sym)
|
90
|
+
name.to_sym
|
91
|
+
end
|
92
|
+
|
93
|
+
def resolve_collisions!
|
94
|
+
collection.reverse_each do |curie|
|
95
|
+
next if collection.none? { |c| c.name == curie.name && c.href != curie.href }
|
96
|
+
new_name = generate_curie_name(curie.name)
|
97
|
+
curie.rename new_name
|
98
|
+
end
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_a
|
104
|
+
collection.map(&:to_h)
|
105
|
+
end
|
106
|
+
|
107
|
+
def empty?
|
108
|
+
collection.empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
def each
|
112
|
+
return collection.each unless block_given?
|
113
|
+
collection.each { |c| yield c }
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def find(name, href = nil)
|
119
|
+
return unless name
|
120
|
+
|
121
|
+
collection.find do |c|
|
122
|
+
next unless c.name.to_sym == name.to_sym
|
123
|
+
href.nil? || c.href == href
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def curie_from(rel)
|
128
|
+
parts = rel.to_s.split(':')
|
129
|
+
parts.first if parts.size > 1
|
130
|
+
end
|
131
|
+
|
132
|
+
def concat(other)
|
133
|
+
other.each do |curie|
|
134
|
+
if existing = find(curie.name, curie.href)
|
135
|
+
existing << curie
|
136
|
+
else
|
137
|
+
collection << curie
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_references(reference, type)
|
143
|
+
return unless reference
|
144
|
+
|
145
|
+
reference.each do |rel, values|
|
146
|
+
curie_name = curie_from(rel)
|
147
|
+
curie = find(curie_name)
|
148
|
+
curie&.add_reference(rel, reference, type)
|
149
|
+
|
150
|
+
values = [values] if values.is_a? Hash
|
151
|
+
values.each do |value|
|
152
|
+
nested = self.class.extract_from!(value, resolve_collisions: false)
|
153
|
+
concat nested.collection
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -1,15 +1,20 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
3
|
module HALPresenter
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
module ClassMethods
|
5
|
+
def from_hal(presenter, payload, resource = nil)
|
6
|
+
presenter.from_hal(payload, resource)
|
7
|
+
end
|
7
8
|
end
|
8
9
|
|
9
10
|
module Deserializer
|
10
11
|
|
11
12
|
class Error < StandardError; end
|
12
13
|
|
14
|
+
def self.included(base)
|
15
|
+
base.extend ClassMethods
|
16
|
+
end
|
17
|
+
|
13
18
|
def from_hal(payload, resource = nil)
|
14
19
|
return if payload.nil? || payload.empty?
|
15
20
|
hash = JSON.parse(payload)
|
data/lib/hal_presenter/links.rb
CHANGED
@@ -3,14 +3,16 @@ require 'hal_presenter/super_init'
|
|
3
3
|
|
4
4
|
module HALPresenter
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
module ClassMethods
|
7
|
+
def base_href=(base)
|
8
|
+
@base_href = base&.sub(%r(/*$), '')
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def href(href)
|
12
|
+
return href if (@base_href ||= '').empty?
|
13
|
+
return href if href =~ %r(\A(\w+://)?[^/])
|
14
|
+
@base_href + href
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
18
|
module Links
|
@@ -56,6 +58,10 @@ module HALPresenter
|
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
61
|
+
def self.included(base)
|
62
|
+
base.extend ClassMethods
|
63
|
+
end
|
64
|
+
|
59
65
|
def link(rel, value = nil, **kwargs, &block)
|
60
66
|
if value.nil? && !block_given?
|
61
67
|
raise 'link must be called with non nil value or be given a block'
|
data/lib/hal_presenter/model.rb
CHANGED
@@ -1,34 +1,40 @@
|
|
1
1
|
module HALPresenter
|
2
2
|
@presenters = {}
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module ClassMethods
|
5
|
+
def register(model:, presenter:)
|
6
|
+
return unless presenter && model
|
7
|
+
@presenters[presenter] = model
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def unregister(presenter)
|
11
|
+
@presenters.delete_if { |d,_| d == presenter }
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def lookup_model(presenter)
|
15
|
+
@presenters[presenter]
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def lookup_presenter(model)
|
19
|
+
presenters = lookup_presenters(model)
|
20
|
+
return presenters.last unless presenters.empty?
|
21
|
+
lookup_presenters(model.first).last if model.respond_to? :first
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
def lookup_presenters(model)
|
25
|
+
clazz = model.is_a?(Class) ? model : model.class
|
26
|
+
presenters = @presenters.select { |_d, m| m == clazz }.keys
|
27
|
+
return presenters unless presenters.empty?
|
28
|
+
return [] unless clazz < BasicObject
|
29
|
+
lookup_presenters(clazz.superclass)
|
30
|
+
end
|
29
31
|
end
|
30
32
|
|
31
33
|
module Model
|
34
|
+
def self.included(base)
|
35
|
+
base.extend ClassMethods
|
36
|
+
end
|
37
|
+
|
32
38
|
def model(clazz)
|
33
39
|
HALPresenter.register(model: clazz, presenter: self)
|
34
40
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module HALPresenter
|
2
|
-
|
2
|
+
module ClassMethods
|
3
3
|
attr_accessor :paginate
|
4
4
|
end
|
5
5
|
|
6
|
-
# TODO: Support Kaminari and Will_paginate
|
7
|
-
|
8
6
|
class Pagination
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
9
10
|
|
10
11
|
class Uri
|
11
12
|
def self.parse(str)
|
@@ -1,32 +1,42 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'hal_presenter/pagination'
|
3
|
+
require 'hal_presenter/curie_collection'
|
3
4
|
|
4
5
|
module HALPresenter
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
7
|
+
module ClassMethods
|
8
|
+
def to_hal(resource, options = {})
|
9
|
+
raise Serializer::Error, "Resource is nil" if resource.nil?
|
10
|
+
options = options.dup
|
11
|
+
presenter = options.delete(:presenter)
|
12
|
+
presenter ||= HALPresenter.lookup_presenter(resource)
|
13
|
+
raise Serializer::Error, "No presenter for #{resource.class}" unless presenter
|
14
|
+
presenter.to_hal(resource, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_collection(resources, options = {})
|
18
|
+
raise Serializer::Error, "resources is nil" if resources.nil?
|
19
|
+
options = options.dup
|
20
|
+
presenter = options.delete(:presenter)
|
21
|
+
presenter ||= HALPresenter.lookup_presenter(resources)
|
22
|
+
raise Serializer::Error, "No presenter for #{resources.first.class}" unless presenter
|
23
|
+
presenter.to_collection(resources, options)
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
module Serializer
|
23
28
|
|
24
29
|
class Error < StandardError; end
|
25
30
|
|
31
|
+
def self.included(base)
|
32
|
+
base.extend(ClassMethods)
|
33
|
+
end
|
34
|
+
|
26
35
|
def to_hal(resource = nil, options = {})
|
36
|
+
options = options.dup
|
27
37
|
options[:_depth] ||= 0
|
28
38
|
hash = to_hash(resource, options)
|
29
|
-
|
39
|
+
move_curies_to_root! hash
|
30
40
|
JSON.generate(hash)
|
31
41
|
end
|
32
42
|
|
@@ -36,10 +46,11 @@ module HALPresenter
|
|
36
46
|
"Trying to serialize a collection using #{self} which has no collection info. " \
|
37
47
|
"Add a 'collection' spec to the serializer or use another serializer"
|
38
48
|
end
|
49
|
+
options = options.dup
|
39
50
|
options[:paginate] = HALPresenter.paginate unless options.key? :paginate
|
40
51
|
options[:_depth] ||= 0
|
41
52
|
hash = to_collection_hash(resources, options)
|
42
|
-
|
53
|
+
move_curies_to_root! hash
|
43
54
|
JSON.generate(hash)
|
44
55
|
end
|
45
56
|
|
@@ -72,8 +83,9 @@ module HALPresenter
|
|
72
83
|
serialized.merge! _serialize_embedded(embedded, resources, policy, options)
|
73
84
|
|
74
85
|
# Embedded resources
|
75
|
-
|
76
|
-
|
86
|
+
embed_options = options.dup
|
87
|
+
embed_options[:_depth] += 1
|
88
|
+
serialized_resources = resources.map { |resource| to_hash(resource, embed_options) }
|
77
89
|
serialized[:_embedded] ||= {}
|
78
90
|
serialized[:_embedded].merge!(properties.name => serialized_resources)
|
79
91
|
end
|
@@ -97,32 +109,16 @@ module HALPresenter
|
|
97
109
|
|
98
110
|
private
|
99
111
|
|
100
|
-
def
|
101
|
-
|
102
|
-
find_curies(hash).each do |curie|
|
103
|
-
name = curie[:name]
|
104
|
-
curies[name] = curie
|
105
|
-
end
|
112
|
+
def move_curies_to_root!(hash)
|
113
|
+
return if Hash(hash).empty?
|
106
114
|
|
107
|
-
|
115
|
+
curie_collection = CurieCollection.extract_from!(hash)
|
116
|
+
return if curie_collection.empty?
|
108
117
|
|
109
118
|
hash[:_links] ||= {}
|
110
|
-
hash[:_links][:curies] =
|
119
|
+
hash[:_links][:curies] = curie_collection.to_a
|
111
120
|
end
|
112
121
|
|
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
122
|
|
127
123
|
def run_post_serialize_hook!(resource, options, serialized)
|
128
124
|
hook = post_serialize_hook
|
@@ -163,13 +159,14 @@ module HALPresenter
|
|
163
159
|
next if policy && !policy.embed?(embed.name)
|
164
160
|
resource = embed.value(object, options) or next
|
165
161
|
presenter = embed.presenter_class
|
166
|
-
|
162
|
+
embed_options = options.dup
|
163
|
+
embed_options[:_depth] += 1
|
167
164
|
hash[embed.name] =
|
168
165
|
if resource.is_a? Array
|
169
|
-
_serialize_embedded_collection(resource, presenter,
|
166
|
+
_serialize_embedded_collection(resource, presenter, embed_options)
|
170
167
|
else
|
171
168
|
presenter ||= HALPresenter.lookup_presenter(resource)
|
172
|
-
presenter.to_hash(resource,
|
169
|
+
presenter.to_hash(resource, embed_options)
|
173
170
|
end
|
174
171
|
end
|
175
172
|
return {} if serialized.empty?
|
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: 1.
|
4
|
+
version: 1.3.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-
|
33
|
+
date: 2019-10-29 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: rake
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/hal_presenter.rb
|
164
164
|
- lib/hal_presenter/attributes.rb
|
165
165
|
- lib/hal_presenter/collection.rb
|
166
|
+
- lib/hal_presenter/curie_collection.rb
|
166
167
|
- lib/hal_presenter/curies.rb
|
167
168
|
- lib/hal_presenter/deserializer.rb
|
168
169
|
- lib/hal_presenter/embedded.rb
|
@@ -197,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
198
|
- !ruby/object:Gem::Version
|
198
199
|
version: '0'
|
199
200
|
requirements: []
|
200
|
-
rubygems_version: 3.0.
|
201
|
+
rubygems_version: 3.0.6
|
201
202
|
signing_key:
|
202
203
|
specification_version: 4
|
203
204
|
summary: JSON HAL serializer
|
metadata.gz.sig
CHANGED
Binary file
|