hal_decorator 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1fdb9a14bc7ef54528db8017406dd28708f6543b
4
+ data.tar.gz: 3daea7984ca3962708d013f493c5f913a6308551
5
+ SHA512:
6
+ metadata.gz: e572bb50f4e82435f9760cb19cfcece75f68810ae2d517c83a6e8876751918d822cae1d90f9e5b0371ca9ab12c89ea9f2f6b3b687a59112763b02a2459a0cebb
7
+ data.tar.gz: d891bc22668258cc50a0e0863338245ed9d24c4e9e73dd4948a9752e31b972731043e22c9b4f5eeba9282d586f1d4061c4eaf1fb84fd9a53227b0a479be2c2c2
checksums.yaml.gz.sig ADDED
Binary file
@@ -0,0 +1,15 @@
1
+ require 'hal_decorator/property'
2
+
3
+ module HALDecorator
4
+ module Attributes
5
+ def attribute(*args, &block)
6
+ @_attributes ||= []
7
+ @_attributes << Property.new(*args, &block)
8
+ end
9
+
10
+ def attributes
11
+ @_attributes ||= []
12
+ @_attributes.dup
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require 'hal_decorator/property'
2
+
3
+ module HALDecorator
4
+ module Collection
5
+
6
+ attr_reader :collection_name
7
+
8
+ class CollectionParameters
9
+ include Attributes
10
+ include Links
11
+ include Curies
12
+
13
+ attr_reader :name
14
+
15
+ def initialize(name, &block)
16
+ @name = name
17
+ instance_exec(&block)
18
+ end
19
+ end
20
+
21
+ def collection(of:, &block)
22
+ @_parameters = CollectionParameters.new(of, &block)
23
+ end
24
+
25
+ def collection_parameters
26
+ @_parameters ||= nil
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ require 'hal_decorator/property'
2
+
3
+ module HALDecorator
4
+ module Curies
5
+ def curie(rel, value = nil, &block)
6
+ if value.nil? && !block_given?
7
+ raise 'curie must be called with non nil value or be given a block'
8
+ end
9
+ @_curies ||= []
10
+ @_curies << Property.new(rel, value, &block)
11
+ end
12
+
13
+ def curies
14
+ @_curies ||= []
15
+ @_curies.dup
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,86 @@
1
+ require 'json'
2
+
3
+ module HALDecorator
4
+
5
+ module Deserializer
6
+
7
+ class Error < StandardError; end
8
+
9
+ def from_hal(payload, resource = nil)
10
+ hash = JSON.parse(payload)
11
+ from_hash(hash, resource)
12
+ end
13
+
14
+ protected
15
+
16
+ def from_hash(hash, resource)
17
+ as_collection = deserialize_as_collection?(hash)
18
+
19
+ if resource.nil?
20
+ model = HALDecorator.lookup_model self
21
+ raise Error, "No model for #{self.class}" unless model
22
+ resource = as_collection ? [] : model.new
23
+ elsif as_collection
24
+ resource.clear
25
+ end
26
+
27
+ if as_collection
28
+ deserialize_collection(hash, resource)
29
+ else
30
+ deserialize_attributes(hash, resource)
31
+ deserialize_embedded(hash, resource)
32
+ end
33
+ resource
34
+ end
35
+
36
+ def deserialize_attributes(hash, resource)
37
+ attributes.each do |attribute|
38
+ setter_method = setter_method_name(attribute.name)
39
+ next unless resource.respond_to? setter_method
40
+ resource.send(setter_method, hash[attribute.name.to_s])
41
+ end
42
+ end
43
+
44
+ def deserialize_embedded(hash, resource)
45
+ embedded.each do |embed|
46
+ setter_method = setter_method_name(embed.name) or next
47
+ next unless resource.respond_to? setter_method
48
+ decorator = embed.decorator_class or next
49
+
50
+ embedded_hash = hash.dig('_embedded', embed.name.to_s)
51
+ next unless embedded_hash&.any?
52
+
53
+ embedded_resource = resource.send(embed.name)
54
+ embedded_resource =
55
+ if embedded_hash.is_a? Array
56
+ embedded_hash.map { |h| decorator.from_hash(h, embedded_resource) }
57
+ else
58
+ decorator.from_hash(embedded_hash, embedded_resource)
59
+ end
60
+ resource.send(setter_method, embedded_resource)
61
+ end
62
+ end
63
+
64
+ def deserialize_collection(hash, resource)
65
+ hash['_embedded'][collection_parameters.name].each do |resource_hash|
66
+ resource << from_hash(resource_hash, nil)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def deserialize_as_collection?(hash)
73
+ name = collection_parameters&.name
74
+ # return true/false (Hash#key? returns nil if not found..)
75
+ name && hash['_embedded']&.key?(name) || false
76
+ end
77
+
78
+ def setter_method_name(attr)
79
+ "#{attr}=".to_sym
80
+ end
81
+
82
+ end
83
+ end
84
+
85
+
86
+
@@ -0,0 +1,24 @@
1
+ require 'hal_decorator/property'
2
+
3
+ module HALDecorator
4
+ module Embedded
5
+ class Embed < HALDecorator::Property
6
+ attr_reader :decorator_class
7
+
8
+ def initialize(name, value = nil, decorator_class: nil, &block)
9
+ super(name, value, &block)
10
+ @decorator_class = decorator_class
11
+ end
12
+ end
13
+
14
+ def embed(*args, &block)
15
+ @_embedded ||= []
16
+ @_embedded << Embed.new(*args, &block)
17
+ end
18
+
19
+ def embedded
20
+ @_embedded ||= []
21
+ @_embedded.dup
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require 'hal_decorator/property'
2
+
3
+ module HALDecorator
4
+ module Links
5
+
6
+ class Link < HALDecorator::Property
7
+ attr_reader :http_method
8
+ def initialize(rel, value = nil, http_method: nil, &block)
9
+ if value.nil? && !block_given?
10
+ raise 'link must be called with non nil value or be given a block'
11
+ end
12
+ @http_method = http_method
13
+ super(rel, value, &block)
14
+ end
15
+ end
16
+
17
+ def link(rel, value = nil, method: nil, methods: nil, &block)
18
+ @_links ||= []
19
+ @_links << Link.new(rel, value, http_method: method || methods, &block)
20
+ end
21
+
22
+ def links
23
+ @_links ||= []
24
+ @_links.dup
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ module HALDecorator
2
+ @decorators = {}
3
+
4
+ def HALDecorator.register(model:, decorator:)
5
+ @decorators[decorator] = model
6
+ end
7
+
8
+ def HALDecorator.unregister(decorator)
9
+ @decorators.delete_if { |d,_| d == decorator }
10
+ end
11
+
12
+ def HALDecorator.lookup_model(decorator)
13
+ @decorators[decorator]
14
+ end
15
+
16
+ def HALDecorator.lookup_decorator(model)
17
+ clazz = model.class == Class ? model : model.class
18
+ decorators = @decorators.select { |d, m| m == clazz }.keys.compact
19
+ decorators.empty? ? nil : decorators
20
+ end
21
+
22
+ module Model
23
+ def model(clazz)
24
+ HALDecorator.register(model: clazz, decorator: self)
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,50 @@
1
+ module HALDecorator
2
+ class Property
3
+ attr_reader :name, :resource, :options
4
+
5
+ alias :resources :resource
6
+
7
+ def initialize(name, value = nil, &block)
8
+ @name = name
9
+ @value = value
10
+ @scope = nil
11
+ return unless block_given?
12
+ @scope = eval 'self', block.binding
13
+ define_singleton_method(:value_from_block, &block)
14
+ end
15
+
16
+ def value(resource = nil, options = {})
17
+ @resource = resource
18
+ @options = options
19
+ if @scope
20
+ value_from_block
21
+ elsif resource && @value.nil?
22
+ resource.public_send(name) if resource.respond_to?(name)
23
+ else
24
+ @value
25
+ end
26
+ ensure
27
+ reset
28
+ end
29
+
30
+ def method_missing(method, *args, &block)
31
+ if @scope&.respond_to? method
32
+ define_singleton_method(method) { |*a, &b| @scope.send method, *a, &b }
33
+ return send(method, *args, &block)
34
+ end
35
+ super
36
+ end
37
+
38
+ def respond_to_missing?(method, include_private = false)
39
+ return true if @scope&.respond_to? method
40
+ super
41
+ end
42
+
43
+ private
44
+
45
+ def reset
46
+ @resource = nil
47
+ @options = nil
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,111 @@
1
+ require 'json'
2
+
3
+ module HALDecorator
4
+
5
+ module Serializer
6
+
7
+ class Error < StandardError; end
8
+
9
+ def to_hal(resource, options = {})
10
+ hash = to_hash(resource, options)
11
+ JSON.generate(hash)
12
+ end
13
+
14
+ def to_hash(object, options, embed: true)
15
+ {}.tap do |serialized|
16
+ serialized.merge! serialize_attributes(object, options)
17
+ serialized.merge! serialize_links(object, options)
18
+ serialized.merge! serialize_embedded(object, options) if embed
19
+ end
20
+ end
21
+
22
+ def to_collection(resources, options = {})
23
+ parameters = collection_parameters
24
+ if parameters.nil?
25
+ raise Error,
26
+ "Trying to serialize a collection using #{self} which has no collection info. " \
27
+ "Add a 'collection' spec to the serializer or use another serializer"
28
+ end
29
+ links = parameters.links
30
+ curies = parameters.curies
31
+ serialized = _serialize_attributes(parameters.attributes, resources, options)
32
+ serialized.merge! _serialize_links(links, curies, resources, options)
33
+
34
+ serialized_resources = resources.map do |resource|
35
+ to_hash(resource, embed: false)
36
+ end
37
+ serialized[:_embedded] = { parameters.name => serialized_resources }
38
+ JSON.generate(serialized)
39
+ end
40
+
41
+ protected
42
+
43
+ def serialize_attributes(object, options)
44
+ _serialize_attributes(attributes, object, options)
45
+ end
46
+
47
+ def serialize_links(object, options)
48
+ _serialize_links(links, curies, object, options)
49
+ end
50
+
51
+ def serialize_curies(object, options)
52
+ _serialize_curies(curies, object, options)
53
+ end
54
+
55
+ def serialize_embedded(object, options)
56
+ _serialize_embedded(embedded, object, options)
57
+ end
58
+
59
+ private
60
+
61
+ def _serialize_attributes(attributes, object, options)
62
+ attributes.each_with_object({}) do |attribute, hash|
63
+ hash[attribute.name] = attribute.value(object, options)
64
+ end
65
+ end
66
+
67
+ def _serialize_links(links, curies, object, options)
68
+ serialized = links.each_with_object({}) do |link, hash|
69
+ value = link.value(object, options) or next
70
+ hash[link.name] = { href: value }.tap do |s|
71
+ s[:method] = link.http_method if link.http_method
72
+ end
73
+ end
74
+ curies = _serialize_curies(curies, object, options)
75
+ serialized[:curies] = curies if curies.any?
76
+ return {} if serialized.empty?
77
+ { _links: serialized }
78
+ end
79
+
80
+ def _serialize_curies(curies, object, options)
81
+ curies.each_with_object([]) do |curie, array|
82
+ array << {
83
+ name: curie.name,
84
+ href: curie.value(object, options),
85
+ templated: true
86
+ }
87
+ end
88
+ end
89
+
90
+ def _serialize_embedded(embedded, object, options)
91
+ serialized = embedded.each_with_object({}) do |embed, hash|
92
+ resource = embed.value(object, options) or next
93
+ decorator = embed.decorator_class
94
+ hash[embed.name] =
95
+ if resource.respond_to? :each
96
+ decorator ||= HALDecorator.lookup_decorator(resource.first).first
97
+ resource.map do |resrc|
98
+ decorator.to_hash(resrc, options, embed: false)
99
+ end
100
+ else
101
+ decorator ||= HALDecorator.lookup_decorator(resource).first
102
+ decorator.to_hash(resource, options, embed: false)
103
+ end
104
+ end
105
+ return {} if serialized.empty?
106
+ { _embedded: serialized }
107
+ end
108
+ end
109
+ end
110
+
111
+
@@ -0,0 +1,47 @@
1
+ require 'hal_decorator/attributes'
2
+ require 'hal_decorator/embedded'
3
+ require 'hal_decorator/links'
4
+ require 'hal_decorator/curies'
5
+ require 'hal_decorator/model'
6
+ require 'hal_decorator/serializer'
7
+ require 'hal_decorator/deserializer'
8
+ require 'hal_decorator/collection'
9
+
10
+
11
+ module HALDecorator
12
+
13
+ def self.included(base)
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ module ClassMethods
18
+ include HALDecorator::Attributes
19
+ include HALDecorator::Links
20
+ include HALDecorator::Curies
21
+ include HALDecorator::Embedded
22
+ include HALDecorator::Collection
23
+ include HALDecorator::Model
24
+ include HALDecorator::Serializer
25
+ include HALDecorator::Deserializer
26
+ end
27
+
28
+ def self.to_hal(resource, options = {})
29
+ raise Serializer::Error, "Resource is nil" if resource.nil?
30
+ decorator = options.delete(:decorator)
31
+ decorator ||= HALDecorator.lookup_decorator(resource)&.first
32
+ raise Serializer::Error, "No decorator for #{resource}" unless decorator
33
+ decorator.to_hal(resource, options)
34
+ end
35
+
36
+ def self.to_collection(resources, options = {})
37
+ raise Serializer::Error, "resources is nil" if resources.nil?
38
+ decorator = options.delete(:decorator)
39
+ decorator ||= HALDecorator.lookup_decorator(resources.first)&.first
40
+ raise Serializer::Error, "No decorator for #{resources.first}" unless decorator
41
+ decorator.to_collection(resources, options)
42
+ end
43
+
44
+ def self.from_hal(decorator, payload, resource = nil)
45
+ decorator.from_hal(payload, resource)
46
+ end
47
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ ���Ts����A�� ��V�����pH*.�\n��)�]�c������6԰̾H�� z��5yהcEp@�HN*أ�n�;_x��?A����?y(:"�֦��c�c��ŗ��4�C��>FJ� �*ɝk�m)F�.ӌw(B�ӯ �v���PK
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hal_decorator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Sammy Henningsson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBIMRowGAYDVQQDDBFzYW1t
14
+ eS5oZW5uaW5nc3NvbjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
15
+ LGQBGRYDY29tMB4XDTE3MDcwODE0MDUxOVoXDTE4MDcwODE0MDUxOVowSDEaMBgG
16
+ A1UEAwwRc2FtbXkuaGVubmluZ3Nzb24xFTATBgoJkiaJk/IsZAEZFgVnbWFpbDET
17
+ MBEGCgmSJomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
18
+ ggEBAK+SDC1mfyhucJ6Va21rIHUGscEtQrdvyBqxFG1s2TgPMAv4RbqwdJVPa7kj
19
+ tbCzslADlUE1oru2C+rcJsMtVGX02ukMIPHT1OjTyy0/EMqLqSy3WeRI8APyDSxC
20
+ Vbe+h5BMf3zZnYfddR6AeG7ln09T1P/tX+9lTMc+I+DW1fUlQgY48CNUayvtJR61
21
+ svXvXMrhLhi29SQig1qmH6Zoe22/JgH+m2JksPndY5Ep3gqfDc6Imwu2vGvmGErJ
22
+ D63FB0XQ/wb4WVH4l7sHQSTfKDp8SImCt1xqNgIyjw578ZG2geGLoncuxgDrbQ/U
23
+ FIJ11lDZd4vLevMhnIxTSJpPr2cCAwEAAaOBijCBhzAJBgNVHRMEAjAAMAsGA1Ud
24
+ DwQEAwIEsDAdBgNVHQ4EFgQUukjj1Cd2ea6IOHDLZe0ymzs2jWkwJgYDVR0RBB8w
25
+ HYEbc2FtbXkuaGVubmluZ3Nzb25AZ21haWwuY29tMCYGA1UdEgQfMB2BG3NhbW15
26
+ Lmhlbm5pbmdzc29uQGdtYWlsLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAGBReofO0
27
+ CDGI8uQNn/btde+zQBiCX0mONJMQ6An760MzOHMlWFi6VaVeeKmYj5xCpI2nWaJN
28
+ 49ALW/v7GZ+JIW5YmbzWIuD8YfwHJYCFPoH0llzg3GCFCMxbYqI3nDtHX3dMxpOc
29
+ 01A72okERe0ne/O5Z4Ym/fOECkyXr0fYondhDQcSuqxU22jsXs1ZjISN8IuHmVkA
30
+ GtGteOIqmA05lP+eCXGvyARGLg1GwZDTjnlH5OfpiT1Oy7Dghewi58Gn4/AlZ4bY
31
+ CNZdF8Vavp6xMQbPHZwqjaeZz2WRXYS7jyYSvCunjwa3OtvXtfbIEGEWE6IM+t9k
32
+ H1g6Q+B6qk9O6g==
33
+ -----END CERTIFICATE-----
34
+ date: 2017-07-27 00:00:00.000000000 Z
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '12.0'
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '10.0'
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '12.0'
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: activesupport
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '5.1'
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '4.0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '5.1'
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: minitest
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.10'
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '5.0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '5.10'
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '5.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: byebug
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '9.0'
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '9.0'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: '9.0'
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '9.0'
116
+ description: |
117
+ Serialize resources according to
118
+ HypertextApplicationLanguage.
119
+ email: sammy.henningsson@gmail.com
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - lib/hal_decorator.rb
125
+ - lib/hal_decorator/attributes.rb
126
+ - lib/hal_decorator/collection.rb
127
+ - lib/hal_decorator/curies.rb
128
+ - lib/hal_decorator/deserializer.rb
129
+ - lib/hal_decorator/embedded.rb
130
+ - lib/hal_decorator/links.rb
131
+ - lib/hal_decorator/model.rb
132
+ - lib/hal_decorator/property.rb
133
+ - lib/hal_decorator/serializer.rb
134
+ homepage: https://github.com/sammyhenningsson/hal_decorator
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.6.11
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: HAL serializer
158
+ test_files: []
metadata.gz.sig ADDED
Binary file