simple_ams 0.2.1 → 0.2.6
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
- data/.github/workflows/ruby.yml +28 -0
- data/.rubocop.yml +56 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +2 -2
- data/README.md +665 -116
- data/Rakefile +3 -3
- data/bin/console +3 -3
- data/lib/simple_ams.rb +34 -33
- data/lib/simple_ams/adapters/ams.rb +26 -32
- data/lib/simple_ams/adapters/jsonapi.rb +47 -64
- data/lib/simple_ams/document.rb +38 -37
- data/lib/simple_ams/document/fields.rb +36 -37
- data/lib/simple_ams/document/forms.rb +7 -9
- data/lib/simple_ams/document/generics.rb +35 -37
- data/lib/simple_ams/document/links.rb +7 -9
- data/lib/simple_ams/document/metas.rb +7 -11
- data/lib/simple_ams/document/primary_id.rb +14 -17
- data/lib/simple_ams/document/relations.rb +99 -109
- data/lib/simple_ams/dsl.rb +73 -71
- data/lib/simple_ams/methy.rb +2 -2
- data/lib/simple_ams/options.rb +267 -265
- data/lib/simple_ams/options/adapter.rb +2 -2
- data/lib/simple_ams/options/concerns/filterable.rb +29 -34
- data/lib/simple_ams/options/concerns/mod.rb +4 -0
- data/lib/simple_ams/options/concerns/name_value_hash.rb +25 -26
- data/lib/simple_ams/options/concerns/tracked_properties.rb +15 -17
- data/lib/simple_ams/options/concerns/value_hash.rb +25 -26
- data/lib/simple_ams/options/fields.rb +1 -1
- data/lib/simple_ams/options/forms.rb +1 -2
- data/lib/simple_ams/options/generics.rb +2 -4
- data/lib/simple_ams/options/includes.rb +1 -1
- data/lib/simple_ams/options/links.rb +1 -1
- data/lib/simple_ams/options/metas.rb +1 -1
- data/lib/simple_ams/options/primary_id.rb +1 -1
- data/lib/simple_ams/options/relations.rb +9 -7
- data/lib/simple_ams/options/type.rb +1 -2
- data/lib/simple_ams/renderer.rb +43 -41
- data/lib/simple_ams/version.rb +1 -1
- data/simple_ams.gemspec +17 -17
- metadata +30 -27
- data/.travis.yml +0 -5
data/lib/simple_ams/dsl.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'simple_ams'
|
2
2
|
|
3
3
|
module SimpleAMS::DSL
|
4
4
|
def self.included(host_class)
|
@@ -17,7 +17,7 @@ module SimpleAMS::DSL
|
|
17
17
|
links: links,
|
18
18
|
metas: metas,
|
19
19
|
forms: forms,
|
20
|
-
generics: generics
|
20
|
+
generics: generics
|
21
21
|
}
|
22
22
|
end
|
23
23
|
end
|
@@ -26,13 +26,13 @@ module SimpleAMS::DSL
|
|
26
26
|
end
|
27
27
|
|
28
28
|
module ClassMethods
|
29
|
-
#TODO: Shouldn't we call here super to presever user's behavior ?
|
29
|
+
# TODO: Shouldn't we call here super to presever user's behavior ?
|
30
30
|
def inherited(subclass)
|
31
31
|
subclass.with_options(
|
32
32
|
options.merge(
|
33
|
-
#TODO: maybe add another group of elements under dsl?
|
34
|
-
#this could be DSL::Type.new(type).explicit?
|
35
|
-
type[-1][:_explicit] ? {} : {type: nil}
|
33
|
+
# TODO: maybe add another group of elements under dsl?
|
34
|
+
# this could be DSL::Type.new(type).explicit?
|
35
|
+
type[-1][:_explicit] ? {} : { type: nil }
|
36
36
|
)
|
37
37
|
)
|
38
38
|
|
@@ -49,16 +49,16 @@ module SimpleAMS::DSL
|
|
49
49
|
links: links,
|
50
50
|
metas: metas,
|
51
51
|
forms: forms,
|
52
|
-
generics: generics
|
52
|
+
generics: generics
|
53
53
|
}
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
_klass.with_options(
|
58
58
|
self::Collection_.options.merge(
|
59
|
-
#TODO: maybe add another group of elements under dsl?
|
60
|
-
#this could be DSL::Type.new(type).explicit?
|
61
|
-
type[-1][:_explicit] ? {} : {type: nil}
|
59
|
+
# TODO: maybe add another group of elements under dsl?
|
60
|
+
# this could be DSL::Type.new(type).explicit?
|
61
|
+
type[-1][:_explicit] ? {} : { type: nil }
|
62
62
|
)
|
63
63
|
)
|
64
64
|
subclass.const_set('Collection_', _klass)
|
@@ -72,47 +72,46 @@ module SimpleAMS::DSL
|
|
72
72
|
}
|
73
73
|
end
|
74
74
|
|
75
|
-
#TODO: Add tests !!
|
75
|
+
# TODO: Add tests !!
|
76
76
|
def _default_type_name
|
77
|
-
if
|
78
|
-
_name =
|
79
|
-
'Serializer',''
|
77
|
+
if to_s.end_with?('::Collection_')
|
78
|
+
_name = to_s.gsub(
|
79
|
+
'Serializer', ''
|
80
80
|
).gsub(
|
81
81
|
'::Collection_', ''
|
82
82
|
).downcase.split('::')[-1]
|
83
83
|
|
84
|
-
|
84
|
+
"#{_name}_collection".to_sym
|
85
85
|
else
|
86
|
-
|
86
|
+
to_s.gsub('Serializer', '').downcase.split('::')[-1].to_sym
|
87
87
|
end
|
88
88
|
end
|
89
|
+
|
89
90
|
def with_options(options = {})
|
90
91
|
@_options = options
|
91
92
|
meths = SimpleAMS::DSL::ClassMethods.instance_methods(false)
|
92
93
|
@_options.each do |key, value|
|
93
94
|
if key == :relations
|
94
|
-
(value || []).each
|
95
|
+
(value || []).each do |rel_value|
|
95
96
|
append_relationship(rel_value)
|
96
|
-
}
|
97
|
-
elsif key.to_sym == :collection
|
98
|
-
#TODO: Add proc option maybe?
|
99
|
-
if value.is_a?(Hash)
|
100
|
-
collection{}.with_options(value)
|
101
97
|
end
|
98
|
+
elsif key.to_sym == :collection
|
99
|
+
# TODO: Add proc option maybe?
|
100
|
+
collection {}.with_options(value) if value.is_a?(Hash)
|
102
101
|
elsif meths.include?(key)
|
103
102
|
if (value.is_a?(Array) && value[0].is_a?(Array)) || value.is_a?(Hash)
|
104
|
-
|
103
|
+
send(key, value)
|
105
104
|
else
|
106
|
-
|
105
|
+
send(key, *value)
|
107
106
|
end
|
108
107
|
else
|
109
108
|
SimpleAMS.configuration.logger.info(
|
110
|
-
"SimpeAMS: #{key} is not recognized, ignoring (from #{self
|
109
|
+
"SimpeAMS: #{key} is not recognized, ignoring (from #{self})"
|
111
110
|
)
|
112
111
|
end
|
113
112
|
end
|
114
113
|
|
115
|
-
|
114
|
+
@_options
|
116
115
|
end
|
117
116
|
|
118
117
|
def adapter(value = nil, options = {})
|
@@ -129,7 +128,7 @@ module SimpleAMS::DSL
|
|
129
128
|
|
130
129
|
def attributes(*args)
|
131
130
|
@_attributes ||= []
|
132
|
-
return @_attributes.uniq if
|
131
|
+
return @_attributes.uniq if args&.empty? || args.nil?
|
133
132
|
|
134
133
|
append_attributes(args)
|
135
134
|
end
|
@@ -167,20 +166,20 @@ module SimpleAMS::DSL
|
|
167
166
|
def embedded_class_for(name, options, block)
|
168
167
|
embedded = Class.new(self)
|
169
168
|
klass_name = "Embedded#{name.to_s.capitalize}Options_"
|
170
|
-
|
169
|
+
const_set(klass_name, embedded)
|
171
170
|
embedded.with_options(
|
172
|
-
default_options.merge(options.
|
171
|
+
default_options.merge(options.reject { |k| k == :serializer })
|
173
172
|
)
|
174
173
|
embedded.instance_exec(&block) if block
|
175
174
|
|
176
|
-
|
175
|
+
embedded
|
177
176
|
end
|
178
177
|
|
179
|
-
#TODO: there is no memoization here, hence we ignore includes manually set !!
|
180
|
-
#Consider fixing it by employing an observer that will clean the instance var
|
181
|
-
#each time @_relations is updated
|
182
|
-
def includes(*
|
183
|
-
relations.map{|rel| rel[1] }
|
178
|
+
# TODO: there is no memoization here, hence we ignore includes manually set !!
|
179
|
+
# Consider fixing it by employing an observer that will clean the instance var
|
180
|
+
# each time @_relations is updated
|
181
|
+
def includes(*_args)
|
182
|
+
relations.map { |rel| rel[1] }
|
184
183
|
end
|
185
184
|
|
186
185
|
def link(name, value, options = {})
|
@@ -201,7 +200,8 @@ module SimpleAMS::DSL
|
|
201
200
|
|
202
201
|
def links(links = [])
|
203
202
|
return @_links ||= [] if links.empty?
|
204
|
-
|
203
|
+
|
204
|
+
links.map { |key, value| append_link([key, value].flatten(1)) } if links.is_a?(Hash)
|
205
205
|
|
206
206
|
@_links ||= links
|
207
207
|
end
|
@@ -209,21 +209,23 @@ module SimpleAMS::DSL
|
|
209
209
|
def metas(metas = [])
|
210
210
|
return @_metas ||= [] if metas.empty?
|
211
211
|
|
212
|
-
metas.map{|key, value| append_meta([key, value].flatten(1))} if metas.is_a?(Hash)
|
212
|
+
metas.map { |key, value| append_meta([key, value].flatten(1)) } if metas.is_a?(Hash)
|
213
213
|
|
214
214
|
@_metas ||= metas
|
215
215
|
end
|
216
216
|
|
217
217
|
def forms(forms = [])
|
218
218
|
return @_forms ||= [] if forms.empty?
|
219
|
-
|
219
|
+
|
220
|
+
forms.map { |key, value| append_form([key, value].flatten(1)) } if forms.is_a?(Hash)
|
220
221
|
|
221
222
|
@_forms ||= forms
|
222
223
|
end
|
223
224
|
|
224
225
|
def generics(generics = [])
|
225
226
|
return @_generics ||= [] if generics.empty?
|
226
|
-
|
227
|
+
|
228
|
+
generics.map { |key, value| append_generic([key, value].flatten(1)) } if generics.is_a?(Hash)
|
227
229
|
|
228
230
|
@_generics ||= generics
|
229
231
|
end
|
@@ -237,7 +239,7 @@ module SimpleAMS::DSL
|
|
237
239
|
|
238
240
|
self::Collection_.type(name) if name
|
239
241
|
|
240
|
-
|
242
|
+
self::Collection_
|
241
243
|
end
|
242
244
|
|
243
245
|
def options
|
@@ -261,50 +263,50 @@ module SimpleAMS::DSL
|
|
261
263
|
end
|
262
264
|
|
263
265
|
private
|
264
|
-
def _value_hash_for(current, value, options, name)
|
265
|
-
_type = current || default_options[name]
|
266
|
-
return _type if value.nil?
|
267
266
|
|
268
|
-
|
269
|
-
|
267
|
+
def _value_hash_for(current, value, options, name)
|
268
|
+
_type = current || default_options[name]
|
269
|
+
return _type if value.nil?
|
270
270
|
|
271
|
-
|
272
|
-
|
271
|
+
[value, options]
|
272
|
+
end
|
273
273
|
|
274
|
-
|
275
|
-
|
274
|
+
def append_relationship(rel)
|
275
|
+
@_relations ||= []
|
276
276
|
|
277
|
-
|
278
|
-
|
277
|
+
@_relations << rel
|
278
|
+
end
|
279
279
|
|
280
|
-
|
281
|
-
|
280
|
+
def append_attributes(*attrs)
|
281
|
+
@_attributes ||= []
|
282
282
|
|
283
|
-
|
284
|
-
|
283
|
+
@_attributes = (@_attributes << attrs).flatten.compact.uniq
|
284
|
+
end
|
285
285
|
|
286
|
-
|
287
|
-
|
286
|
+
def append_link(link)
|
287
|
+
@_links ||= []
|
288
288
|
|
289
|
-
|
290
|
-
|
289
|
+
@_links << link
|
290
|
+
end
|
291
291
|
|
292
|
-
|
293
|
-
|
292
|
+
def append_meta(meta)
|
293
|
+
@_metas ||= []
|
294
|
+
|
295
|
+
@_metas << meta
|
296
|
+
end
|
294
297
|
|
295
|
-
|
296
|
-
|
298
|
+
def append_form(form)
|
299
|
+
@_forms ||= []
|
297
300
|
|
298
|
-
|
299
|
-
|
301
|
+
@_forms << form
|
302
|
+
end
|
300
303
|
|
301
|
-
|
302
|
-
|
304
|
+
def append_generic(generic)
|
305
|
+
@_generics ||= []
|
303
306
|
|
304
|
-
|
305
|
-
|
307
|
+
@_generics << generic
|
308
|
+
end
|
306
309
|
|
307
|
-
|
308
|
-
end
|
310
|
+
def empty_options; end
|
309
311
|
end
|
310
312
|
end
|
data/lib/simple_ams/methy.rb
CHANGED
data/lib/simple_ams/options.rb
CHANGED
@@ -1,333 +1,335 @@
|
|
1
|
-
require
|
1
|
+
require 'simple_ams'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
include Concerns::TrackedProperties
|
3
|
+
class SimpleAMS::Options
|
4
|
+
include Concerns::TrackedProperties
|
6
5
|
|
7
|
-
|
6
|
+
class Collection < self; end
|
8
7
|
|
9
|
-
|
8
|
+
attr_reader :resource, :allowed_options, :injected_options
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
# injected_options is always a Hash object
|
11
|
+
def initialize(resource = nil, injected_options: {}, allowed_options: nil)
|
12
|
+
initialize_tracking!
|
13
|
+
@resource = resource
|
14
|
+
@injected_options = injected_options || {}
|
15
|
+
@_internal = @injected_options[:_internal] || {}
|
16
|
+
@allowed_options = allowed_options || fetch_allowed_options
|
17
|
+
end
|
18
|
+
alias collection resource
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
# performance enchancement method for non-polymorphic collections
|
21
|
+
def with_resource(resource)
|
22
|
+
@resource = resource
|
23
|
+
remove_instance_variable(:@serializer) if defined?(@serializer)
|
24
|
+
clean_volatile_properties!
|
24
25
|
|
25
|
-
|
26
|
+
self
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
def relation_options_for(relation_name)
|
30
|
+
_relation_options[relation_name] || {}
|
31
|
+
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
+
def primary_id
|
34
|
+
return tracked(:primary_id).value if tracked(:primary_id).value
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
tracked(:primary_id).value = array_of_value_hash_for(PrimaryId, :primary_id)
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
def type
|
40
|
+
return tracked(:type).value if tracked(:type).value
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
tracked(:type).value = array_of_value_hash_for(Type, :type)
|
43
|
+
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
+
def name
|
46
|
+
@name ||= injected_options[:name] || allowed_options[:name] || type.name
|
47
|
+
end
|
45
48
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
+
# TODO: optimize for nested fields?
|
50
|
+
def fields
|
51
|
+
return @fields if defined?(@fields)
|
49
52
|
|
50
|
-
|
51
|
-
|
52
|
-
return @fields if defined?(@fields)
|
53
|
+
@fields = array_of_items_for(Fields, :fields)
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
+
def includes
|
57
|
+
return @includes if defined?(@includes)
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
@includes = array_of_items_for(Includes, :includes)
|
60
|
+
end
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
+
# TODO: correctly loop over injected relations, although should be a rarely used feature
|
63
|
+
def relations
|
64
|
+
return @relations if defined?(@relations)
|
62
65
|
|
63
|
-
|
64
|
-
|
65
|
-
return @relations if defined?(@relations)
|
66
|
+
relations = injected_options.fetch(:relations, nil)
|
67
|
+
relations = allowed_options.fetch(:relations, []) if relations.nil?
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
+
@relations = Relations.new(relations, includes)
|
70
|
+
end
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
+
def links
|
73
|
+
return tracked(:links).value if tracked(:links).value
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
+
tracked(:links).value = array_of_name_value_hash_for(Links, Links::Link, :links)
|
76
|
+
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
+
def metas
|
79
|
+
return tracked(:metas).value if tracked(:metas).value
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
+
tracked(:metas).value = array_of_name_value_hash_for(Metas, Metas::Meta, :metas)
|
82
|
+
end
|
81
83
|
|
82
|
-
|
83
|
-
|
84
|
+
def forms
|
85
|
+
return tracked(:forms).value if tracked(:forms).value
|
84
86
|
|
85
|
-
|
86
|
-
|
87
|
+
tracked(:forms).value = array_of_name_value_hash_for(Forms, Forms::Form, :forms)
|
88
|
+
end
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
+
def generics
|
91
|
+
return tracked(:generics).value if tracked(:generics).value
|
90
92
|
|
91
|
-
|
92
|
-
|
93
|
+
tracked(:generics).value = array_of_name_value_hash_for(
|
94
|
+
Generics, Generics::Option, :generics
|
95
|
+
)
|
96
|
+
end
|
93
97
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
+
# TODO: handle case of proc
|
99
|
+
def serializer
|
100
|
+
return @serializer if defined?(@serializer)
|
98
101
|
|
99
|
-
|
100
|
-
def serializer
|
101
|
-
return @serializer if defined?(@serializer)
|
102
|
+
_serializer = injected_options.fetch(:serializer, serializer_class)
|
102
103
|
|
103
|
-
|
104
|
+
@serializer = instantiated_serializer_for(_serializer)
|
105
|
+
end
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
+
def adapter(_serializer: nil)
|
108
|
+
return @adapter if defined?(@adapter) && _serializer.nil?
|
107
109
|
|
108
|
-
|
109
|
-
return @adapter if defined?(@adapter) && _serializer.nil?
|
110
|
-
serializer = _serializer || serializer
|
110
|
+
serializer = _serializer || serializer
|
111
111
|
|
112
|
-
|
112
|
+
@adapter = Adapter.new(
|
113
|
+
*injected_options.fetch(:adapter, [nil]),
|
114
|
+
resource: resource, serializer: serializer
|
115
|
+
)
|
116
|
+
if @adapter.value.nil?
|
117
|
+
@adapter = Adapter.new(
|
118
|
+
*allowed_options.fetch(:adapter, [nil]),
|
113
119
|
resource: resource, serializer: serializer
|
114
|
-
|
115
|
-
if @adapter.value.nil?
|
116
|
-
@adapter = Adapter.new(*allowed_options.fetch(:adapter, [nil]), {
|
117
|
-
resource: resource, serializer: serializer
|
118
|
-
})
|
119
|
-
end
|
120
|
-
=begin
|
121
|
-
if @adapter.value.nil?
|
122
|
-
@adapter = Adapter.new(SimpleAMS::Adapters::AMS, {
|
123
|
-
resource: resource, serializer: serializer
|
124
|
-
})
|
125
|
-
end
|
126
|
-
=end
|
127
|
-
|
128
|
-
return @adapter
|
120
|
+
)
|
129
121
|
end
|
122
|
+
# if @adapter.value.nil?
|
123
|
+
# @adapter = Adapter.new(SimpleAMS::Adapters::AMS, {
|
124
|
+
# resource: resource, serializer: serializer
|
125
|
+
# })
|
126
|
+
# end
|
130
127
|
|
131
|
-
|
132
|
-
|
133
|
-
@expose ||= injected_options.fetch(:expose, {})
|
134
|
-
end
|
128
|
+
@adapter
|
129
|
+
end
|
135
130
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
type: type.raw,
|
141
|
-
name: name,
|
142
|
-
fields: fields.raw,
|
143
|
-
serializer: serializer_class,
|
144
|
-
#relations: relations.raw, #TODO: why have I commented that out ?
|
145
|
-
includes: includes.raw,
|
146
|
-
links: links.raw,
|
147
|
-
metas: metas.raw,
|
148
|
-
expose: expose,
|
149
|
-
_internal: _internal
|
150
|
-
}
|
151
|
-
end
|
131
|
+
# the following should be the same for all (nested) serializers of the same document
|
132
|
+
def expose
|
133
|
+
@expose ||= injected_options.fetch(:expose, {})
|
134
|
+
end
|
152
135
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
136
|
+
def as_hash
|
137
|
+
{
|
138
|
+
adapter: adapter.raw,
|
139
|
+
primary_id: primary_id.raw,
|
140
|
+
type: type.raw,
|
141
|
+
name: name,
|
142
|
+
fields: fields.raw,
|
143
|
+
serializer: serializer_class,
|
144
|
+
# relations: relations.raw, #TODO: why have I commented that out ?
|
145
|
+
includes: includes.raw,
|
146
|
+
links: links.raw,
|
147
|
+
metas: metas.raw,
|
148
|
+
expose: expose,
|
149
|
+
_internal: _internal
|
150
|
+
}
|
151
|
+
end
|
170
152
|
|
171
|
-
|
172
|
-
|
153
|
+
def collection_options
|
154
|
+
return @collection_options if defined?(@collection_options)
|
155
|
+
|
156
|
+
# TODO: Do we need that merge ?
|
157
|
+
_injected_options = @injected_options.fetch(:collection, {}).merge({
|
158
|
+
serializer: collection_serializer_class,
|
159
|
+
adapter: adapter(_serializer: collection_serializer_class).raw,
|
160
|
+
expose: expose
|
161
|
+
})
|
162
|
+
_allowed_options = @allowed_options.fetch(:collection).options
|
163
|
+
|
164
|
+
@collection_options = self.class::Collection.new(
|
165
|
+
resource,
|
166
|
+
injected_options: _injected_options,
|
167
|
+
allowed_options: _allowed_options
|
168
|
+
)
|
169
|
+
end
|
173
170
|
|
174
|
-
|
171
|
+
def serializer_class
|
172
|
+
return @serializer_class if defined?(@serializer_class)
|
175
173
|
|
176
|
-
|
174
|
+
@serializer_class = injected_options.fetch(:serializer, nil)
|
177
175
|
|
178
|
-
|
179
|
-
|
176
|
+
return @serializer_class if @serializer_class
|
177
|
+
|
178
|
+
@serializer_class = infer_serializer
|
179
|
+
end
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
|
181
|
+
# TODO: maybe have that inside :collection? (isomorphism)
|
182
|
+
def collection_serializer_class
|
183
|
+
return @collection_serializer_class if defined?(@collection_serializer_class)
|
184
184
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
else
|
191
|
-
@collection_serializer_class = serializer_class
|
185
|
+
if serializer_class.is_a?(Proc) # TODO: maybe we should do duck typing instead?
|
186
|
+
@collection_serializer_class = injected_options[:collection_serializer]
|
187
|
+
if @collection_serializer_class.nil?
|
188
|
+
raise 'In case of a proc serializer, you need to specify a collection_serializer'
|
192
189
|
end
|
193
|
-
|
194
|
-
|
190
|
+
else
|
191
|
+
@collection_serializer_class = serializer_class
|
195
192
|
end
|
196
193
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
194
|
+
@collection_serializer_class
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
attr_reader :_internal
|
200
|
+
|
201
|
+
# TODO: add method-based links, should boost performance
|
202
|
+
def array_of_name_value_hash_for(collection_klass, item_klass, name)
|
203
|
+
injected = injected_options.fetch(name, nil)
|
204
|
+
if injected
|
205
|
+
injected = collection_klass.new(
|
206
|
+
injected.map do |l|
|
207
|
+
item_klass.new(
|
208
|
+
*l.flatten,
|
209
|
+
resource: resource, serializer: serializer
|
208
210
|
)
|
209
211
|
end
|
212
|
+
)
|
213
|
+
end
|
210
214
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
+
allowed = collection_klass.new(
|
216
|
+
allowed_options.fetch(name).map do |l|
|
217
|
+
item_klass.new(
|
218
|
+
*l,
|
219
|
+
resource: resource, serializer: serializer
|
215
220
|
)
|
216
|
-
|
217
|
-
return collection_klass.new(priority_options_for(
|
218
|
-
#TODO: correctly loop over injected properties
|
219
|
-
injected: injected,
|
220
|
-
allowed: allowed,
|
221
|
-
).uniq{|item| item.name})
|
222
221
|
end
|
222
|
+
)
|
223
223
|
|
224
|
-
|
225
|
-
|
226
|
-
|
224
|
+
collection_klass.new(priority_options_for(
|
225
|
+
# TODO: correctly loop over injected properties
|
226
|
+
injected: injected,
|
227
|
+
allowed: allowed
|
228
|
+
).uniq(&:name))
|
229
|
+
end
|
227
230
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
end
|
231
|
+
def array_of_value_hash_for(klass, name)
|
232
|
+
_options = injected_options.fetch(name, nil)
|
233
|
+
_options ||= allowed_options.fetch(name, nil)
|
232
234
|
|
233
|
-
|
234
|
-
|
235
|
+
klass.new(
|
236
|
+
*_options,
|
237
|
+
resource: resource, serializer: serializer
|
238
|
+
)
|
239
|
+
end
|
235
240
|
|
236
|
-
|
237
|
-
|
238
|
-
else
|
239
|
-
return klass.new(priority_options_for(
|
240
|
-
injected: klass.new(injected_options.fetch(name, nil)),
|
241
|
-
allowed: klass.new(allowed_options.fetch(name).uniq)
|
242
|
-
).uniq)
|
243
|
-
end
|
244
|
-
end
|
241
|
+
def array_of_items_for(klass, name)
|
242
|
+
injected = injected_options.fetch(name, nil)
|
245
243
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
244
|
+
if injected.nil?
|
245
|
+
klass.new(allowed_options.fetch(name).uniq)
|
246
|
+
else
|
247
|
+
klass.new(priority_options_for(
|
248
|
+
injected: klass.new(injected_options.fetch(name, nil)),
|
249
|
+
allowed: klass.new(allowed_options.fetch(name).uniq)
|
250
|
+
).uniq)
|
251
|
+
end
|
252
|
+
end
|
252
253
|
|
253
|
-
|
254
|
-
|
254
|
+
def priority_options_for(allowed:, injected:)
|
255
|
+
unless injected.nil?
|
256
|
+
allowed = injected.class.new(
|
257
|
+
injected.map { |s| s.is_a?(Hash) ? s.keys : s }.flatten
|
258
|
+
) & allowed
|
259
|
+
end
|
255
260
|
|
256
|
-
|
257
|
-
|
258
|
-
(allowed || []).concat(injected || [])
|
259
|
-
end
|
260
|
-
=end
|
261
|
-
|
262
|
-
def _relation_options
|
263
|
-
return @_relation_options if defined?(@_relation_options)
|
264
|
-
|
265
|
-
@_relation_options = relations.inject({}){|memo, relation|
|
266
|
-
includes_value = (injected_options[:includes] || {}).find{|incl_hash|
|
267
|
-
incl_hash.is_a?(Hash) &&
|
268
|
-
(incl_hash.first && incl_hash.first[0]).to_s == relation.name.to_s
|
269
|
-
}
|
270
|
-
if includes_value
|
271
|
-
includes_value = includes_value[relation.name]
|
272
|
-
else
|
273
|
-
#it's important here to return empty array if nothing is found..
|
274
|
-
includes_value = []
|
275
|
-
end
|
276
|
-
|
277
|
-
fields_value = (injected_options[:fields] || {}).find{|field_hash|
|
278
|
-
field_hash.is_a?(Hash) &&
|
279
|
-
(field_hash.first && field_hash.first[0]).to_s == relation.name.to_s
|
280
|
-
}
|
281
|
-
|
282
|
-
#.. while here just nil will work (pick default fields from serializer)
|
283
|
-
fields_value = fields_value[relation.name] if fields_value
|
284
|
-
|
285
|
-
memo[relation.name] = {
|
286
|
-
includes: includes_value,
|
287
|
-
fields: fields_value
|
288
|
-
}
|
289
|
-
memo
|
290
|
-
}
|
291
|
-
end
|
261
|
+
allowed
|
262
|
+
end
|
292
263
|
|
293
|
-
|
294
|
-
|
295
|
-
_serializer_class = self.serializer_class
|
296
|
-
if _serializer_class.is_a?(Proc) #TODO: maybe we should do duck typing instead?
|
297
|
-
_serializer_class = self.collection_serializer_class
|
298
|
-
end
|
264
|
+
def _relation_options
|
265
|
+
return @_relation_options if defined?(@_relation_options)
|
299
266
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
end
|
305
|
-
end
|
267
|
+
# TODO: should use 2.7 filter_map soon
|
268
|
+
@_relation_options = relations.each_with_object({}) do |relation, memo|
|
269
|
+
includes_value = (injected_options[:includes] || {}).find do |incl_hash|
|
270
|
+
next unless incl_hash.is_a?(Hash)
|
306
271
|
|
307
|
-
|
308
|
-
serializer_klass.new.extend(
|
309
|
-
SimpleAMS::Methy.of(
|
310
|
-
expose.merge({
|
311
|
-
object: resource
|
312
|
-
})
|
313
|
-
)
|
314
|
-
)
|
272
|
+
incl_hash.keys.include?(relation.name)
|
315
273
|
end
|
274
|
+
includes_value = if includes_value
|
275
|
+
includes_value[relation.name]
|
276
|
+
else
|
277
|
+
# it's important here to return empty array if nothing is found..
|
278
|
+
[]
|
279
|
+
end
|
316
280
|
|
317
|
-
|
318
|
-
|
319
|
-
resource_klass = resource.kind_of?(Array) ? resource[0].class : resource.class
|
320
|
-
if resource_klass == NilClass
|
321
|
-
return EmptySerializer
|
322
|
-
else
|
323
|
-
return Object.const_get("#{namespace}#{resource_klass.to_s}Serializer")
|
324
|
-
end
|
325
|
-
rescue NameError => _
|
326
|
-
raise "Could not infer serializer for #{resource.class}, maybe specify it? (tried #{namespace}#{resource_klass.to_s}Serializer)"
|
327
|
-
end
|
281
|
+
fields_value = (injected_options[:fields] || {}).find do |field_hash|
|
282
|
+
next unless field_hash.is_a?(Hash)
|
328
283
|
|
329
|
-
|
330
|
-
include SimpleAMS::DSL
|
284
|
+
field_hash.keys.include?(relation.name)
|
331
285
|
end
|
286
|
+
|
287
|
+
# .. while here just nil will work (pick default fields from serializer)
|
288
|
+
fields_value = fields_value[relation.name] if fields_value
|
289
|
+
|
290
|
+
memo[relation.name] = {
|
291
|
+
includes: includes_value,
|
292
|
+
fields: fields_value
|
293
|
+
}
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# TODO: raise exception if both are nil!
|
298
|
+
def fetch_allowed_options
|
299
|
+
_serializer_class = serializer_class
|
300
|
+
_serializer_class = collection_serializer_class if _serializer_class.is_a?(Proc)
|
301
|
+
|
302
|
+
unless _serializer_class.respond_to?(:simple_ams?)
|
303
|
+
raise "#{_serializer_class} does not respond to SimpleAMS methods, did you include the DSL module?"
|
304
|
+
end
|
305
|
+
|
306
|
+
_serializer_class&.options
|
307
|
+
end
|
308
|
+
|
309
|
+
def instantiated_serializer_for(serializer_klass)
|
310
|
+
serializer_klass.new.extend(
|
311
|
+
SimpleAMS::Methy.of(
|
312
|
+
expose.merge({
|
313
|
+
object: resource
|
314
|
+
})
|
315
|
+
)
|
316
|
+
)
|
317
|
+
end
|
318
|
+
|
319
|
+
def infer_serializer
|
320
|
+
namespace = _internal[:module] ? "#{_internal[:module]}::" : ''
|
321
|
+
resource_klass = resource.respond_to?(:to_a) && resource.respond_to?(:last) ? resource[0].class : resource.class
|
322
|
+
if resource_klass == NilClass
|
323
|
+
EmptySerializer
|
324
|
+
else
|
325
|
+
Object.const_get("#{namespace}#{resource_klass}Serializer")
|
326
|
+
end
|
327
|
+
rescue NameError => _e
|
328
|
+
tried = "#{namespace}#{resource_klass}Serializer"
|
329
|
+
raise "Could not infer serializer for #{resource.class}, maybe specify it? (tried #{tried})"
|
330
|
+
end
|
331
|
+
|
332
|
+
class EmptySerializer
|
333
|
+
include SimpleAMS::DSL
|
332
334
|
end
|
333
335
|
end
|