simple_ams 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +28 -0
  3. data/.rubocop.yml +56 -0
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile +2 -2
  6. data/README.md +663 -116
  7. data/Rakefile +3 -3
  8. data/bin/console +3 -3
  9. data/lib/simple_ams.rb +34 -33
  10. data/lib/simple_ams/adapters/ams.rb +26 -32
  11. data/lib/simple_ams/adapters/jsonapi.rb +46 -65
  12. data/lib/simple_ams/document.rb +38 -28
  13. data/lib/simple_ams/document/fields.rb +36 -37
  14. data/lib/simple_ams/document/forms.rb +7 -9
  15. data/lib/simple_ams/document/generics.rb +35 -37
  16. data/lib/simple_ams/document/links.rb +7 -9
  17. data/lib/simple_ams/document/metas.rb +7 -11
  18. data/lib/simple_ams/document/primary_id.rb +14 -17
  19. data/lib/simple_ams/document/relations.rb +99 -109
  20. data/lib/simple_ams/dsl.rb +73 -71
  21. data/lib/simple_ams/methy.rb +2 -2
  22. data/lib/simple_ams/options.rb +268 -266
  23. data/lib/simple_ams/options/adapter.rb +2 -2
  24. data/lib/simple_ams/options/concerns/filterable.rb +29 -34
  25. data/lib/simple_ams/options/concerns/mod.rb +4 -0
  26. data/lib/simple_ams/options/concerns/name_value_hash.rb +25 -26
  27. data/lib/simple_ams/options/concerns/tracked_properties.rb +15 -17
  28. data/lib/simple_ams/options/concerns/value_hash.rb +25 -26
  29. data/lib/simple_ams/options/fields.rb +1 -1
  30. data/lib/simple_ams/options/forms.rb +1 -2
  31. data/lib/simple_ams/options/generics.rb +2 -4
  32. data/lib/simple_ams/options/includes.rb +1 -1
  33. data/lib/simple_ams/options/links.rb +1 -1
  34. data/lib/simple_ams/options/metas.rb +1 -1
  35. data/lib/simple_ams/options/primary_id.rb +1 -1
  36. data/lib/simple_ams/options/relations.rb +9 -7
  37. data/lib/simple_ams/options/type.rb +1 -2
  38. data/lib/simple_ams/renderer.rb +43 -41
  39. data/lib/simple_ams/version.rb +1 -1
  40. data/simple_ams.gemspec +17 -16
  41. metadata +38 -21
  42. data/.travis.yml +0 -15
@@ -1,4 +1,4 @@
1
- require "simple_ams"
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 self.to_s.end_with?('::Collection_')
78
- _name = self.to_s.gsub(
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
- return "#{_name}_collection".to_sym
84
+ "#{_name}_collection".to_sym
85
85
  else
86
- return self.to_s.gsub('Serializer','').downcase.split('::')[-1].to_sym
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{|rel_value|
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
- self.send(key, value)
103
+ send(key, value)
105
104
  else
106
- self.send(key, *value)
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.to_s})"
109
+ "SimpeAMS: #{key} is not recognized, ignoring (from #{self})"
111
110
  )
112
111
  end
113
112
  end
114
113
 
115
- return @_options
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 (args&.empty? || args.nil?)
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
- self.const_set(klass_name, embedded)
169
+ const_set(klass_name, embedded)
171
170
  embedded.with_options(
172
- default_options.merge(options.select{|k| k != :serializer})
171
+ default_options.merge(options.reject { |k| k == :serializer })
173
172
  )
174
173
  embedded.instance_exec(&block) if block
175
174
 
176
- return embedded
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(*args)
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
- links.map{|key, value| append_link([key, value].flatten(1))} if links.is_a?(Hash)
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
- forms.map{|key, value| append_form([key, value].flatten(1))} if forms.is_a?(Hash)
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
- generics.map{|key, value| append_generic([key, value].flatten(1))} if generics.is_a?(Hash)
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
- return self::Collection_
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
- return [value, options]
269
- end
267
+ def _value_hash_for(current, value, options, name)
268
+ _type = current || default_options[name]
269
+ return _type if value.nil?
270
270
 
271
- def append_relationship(rel)
272
- @_relations ||= []
271
+ [value, options]
272
+ end
273
273
 
274
- @_relations << rel
275
- end
274
+ def append_relationship(rel)
275
+ @_relations ||= []
276
276
 
277
- def append_attributes(*attrs)
278
- @_attributes ||= []
277
+ @_relations << rel
278
+ end
279
279
 
280
- @_attributes = (@_attributes << attrs).flatten.compact.uniq
281
- end
280
+ def append_attributes(*attrs)
281
+ @_attributes ||= []
282
282
 
283
- def append_link(link)
284
- @_links ||= []
283
+ @_attributes = (@_attributes << attrs).flatten.compact.uniq
284
+ end
285
285
 
286
- @_links << link
287
- end
286
+ def append_link(link)
287
+ @_links ||= []
288
288
 
289
- def append_meta(meta)
290
- @_metas ||= []
289
+ @_links << link
290
+ end
291
291
 
292
- @_metas << meta
293
- end
292
+ def append_meta(meta)
293
+ @_metas ||= []
294
+
295
+ @_metas << meta
296
+ end
294
297
 
295
- def append_form(form)
296
- @_forms ||= []
298
+ def append_form(form)
299
+ @_forms ||= []
297
300
 
298
- @_forms << form
299
- end
301
+ @_forms << form
302
+ end
300
303
 
301
- def append_generic(generic)
302
- @_generics ||= []
304
+ def append_generic(generic)
305
+ @_generics ||= []
303
306
 
304
- @_generics << generic
305
- end
307
+ @_generics << generic
308
+ end
306
309
 
307
- def empty_options
308
- end
310
+ def empty_options; end
309
311
  end
310
312
  end
@@ -2,9 +2,9 @@ module SimpleAMS::Methy
2
2
  def self.of(hash = {})
3
3
  m = Module.new
4
4
  hash.each do |key, value|
5
- m.send(:define_method, key){ value }
5
+ m.send(:define_method, key) { value }
6
6
  end
7
7
 
8
- return m
8
+ m
9
9
  end
10
10
  end
@@ -1,333 +1,335 @@
1
- require "simple_ams"
1
+ require 'simple_ams'
2
2
 
3
- module SimpleAMS
4
- class Options
5
- include Concerns::TrackedProperties
3
+ class SimpleAMS::Options
4
+ include Concerns::TrackedProperties
6
5
 
7
- class Collection < self; end
6
+ class Collection < self; end
8
7
 
9
- attr_reader :resource, :allowed_options, :injected_options
8
+ attr_reader :resource, :allowed_options, :injected_options
10
9
 
11
- #injected_options is always a Hash object
12
- def initialize(resource = nil, injected_options: {}, allowed_options: nil)
13
- initialize_tracking!
14
- @resource = resource
15
- @injected_options = injected_options || {}
16
- @_internal = @injected_options[:_internal] || {}
17
- @allowed_options = allowed_options || fetch_allowed_options
18
- end
19
- alias collection resource
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
- #performance enchancement method for non-polymorphic collections
22
- def with_resource(resource)
23
- @resource = resource
24
- remove_instance_variable(:@serializer) if defined?(@serializer)
25
- clean_volatile_properties!
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!
26
25
 
27
- return self
28
- end
26
+ self
27
+ end
29
28
 
30
- def relation_options_for(relation_name)
31
- return _relation_options[relation_name] || {}
32
- end
29
+ def relation_options_for(relation_name)
30
+ _relation_options[relation_name] || {}
31
+ end
33
32
 
34
- def primary_id
35
- return tracked(:primary_id).value if tracked(:primary_id).value
33
+ def primary_id
34
+ return tracked(:primary_id).value if tracked(:primary_id).value
36
35
 
37
- return tracked(:primary_id).value = array_of_value_hash_for(PrimaryId, :primary_id)
38
- end
36
+ tracked(:primary_id).value = array_of_value_hash_for(PrimaryId, :primary_id)
37
+ end
39
38
 
40
- def type
41
- return tracked(:type).value if tracked(:type).value
39
+ def type
40
+ return tracked(:type).value if tracked(:type).value
42
41
 
43
- return tracked(:type).value = array_of_value_hash_for(Type, :type)
44
- end
42
+ tracked(:type).value = array_of_value_hash_for(Type, :type)
43
+ end
45
44
 
46
- def name
47
- @name ||= injected_options[:name] || allowed_options[:name] || type.name
48
- end
45
+ def name
46
+ @name ||= injected_options[:name] || allowed_options[:name] || type.name
47
+ end
49
48
 
50
- #TODO: optimize for nested fields?
51
- def fields
52
- return @fields if defined?(@fields)
49
+ # TODO: optimize for nested fields?
50
+ def fields
51
+ return @fields if defined?(@fields)
53
52
 
54
- return @fields = array_of_items_for(Fields, :fields)
55
- end
53
+ @fields = array_of_items_for(Fields, :fields)
54
+ end
56
55
 
57
- def includes
58
- return @includes if defined?(@includes)
56
+ def includes
57
+ return @includes if defined?(@includes)
59
58
 
60
- return @includes = array_of_items_for(Includes, :includes)
61
- end
59
+ @includes = array_of_items_for(Includes, :includes)
60
+ end
62
61
 
63
- #TODO: correctly loop over injected relations, although should be a rarely used feature
64
- def relations
65
- return @relations if defined?(@relations)
62
+ # TODO: correctly loop over injected relations, although should be a rarely used feature
63
+ def relations
64
+ return @relations if defined?(@relations)
66
65
 
67
- relations = injected_options.fetch(:relations, nil)
68
- relations = allowed_options.fetch(:relations, []) if relations.nil?
66
+ relations = injected_options.fetch(:relations, nil)
67
+ relations = allowed_options.fetch(:relations, []) if relations.nil?
69
68
 
70
- return @relations = Relations.new(relations, includes)
71
- end
69
+ @relations = Relations.new(relations, includes)
70
+ end
72
71
 
73
- def links
74
- return tracked(:links).value if tracked(:links).value
72
+ def links
73
+ return tracked(:links).value if tracked(:links).value
75
74
 
76
- return tracked(:links).value = array_of_name_value_hash_for(Links, Links::Link, :links)
77
- end
75
+ tracked(:links).value = array_of_name_value_hash_for(Links, Links::Link, :links)
76
+ end
78
77
 
79
- def metas
80
- return tracked(:metas).value if tracked(:metas).value
78
+ def metas
79
+ return tracked(:metas).value if tracked(:metas).value
81
80
 
82
- return tracked(:metas).value = array_of_name_value_hash_for(Metas, Metas::Meta, :metas)
83
- end
81
+ tracked(:metas).value = array_of_name_value_hash_for(Metas, Metas::Meta, :metas)
82
+ end
84
83
 
85
- def forms
86
- return tracked(:forms).value if tracked(:forms).value
84
+ def forms
85
+ return tracked(:forms).value if tracked(:forms).value
87
86
 
88
- return tracked(:forms).value = array_of_name_value_hash_for(Forms, Forms::Form, :forms)
89
- end
87
+ tracked(:forms).value = array_of_name_value_hash_for(Forms, Forms::Form, :forms)
88
+ end
90
89
 
91
- def generics
92
- return tracked(:generics).value if tracked(:generics).value
90
+ def generics
91
+ return tracked(:generics).value if tracked(:generics).value
93
92
 
94
- return tracked(:generics).value = array_of_name_value_hash_for(
95
- Generics, Generics::Option, :generics
96
- )
97
- end
93
+ tracked(:generics).value = array_of_name_value_hash_for(
94
+ Generics, Generics::Option, :generics
95
+ )
96
+ end
98
97
 
99
- #TODO: handle case of proc
100
- def serializer
101
- return @serializer if defined?(@serializer)
98
+ # TODO: handle case of proc
99
+ def serializer
100
+ return @serializer if defined?(@serializer)
102
101
 
103
- _serializer = injected_options.fetch(:serializer, serializer_class)
102
+ _serializer = injected_options.fetch(:serializer, serializer_class)
104
103
 
105
- return @serializer = instantiated_serializer_for(_serializer)
106
- end
104
+ @serializer = instantiated_serializer_for(_serializer)
105
+ end
107
106
 
108
- def adapter(_serializer: nil)
109
- return @adapter if defined?(@adapter) && _serializer.nil?
110
- serializer = _serializer || serializer
107
+ def adapter(_serializer: nil)
108
+ return @adapter if defined?(@adapter) && _serializer.nil?
111
109
 
112
- @adapter = Adapter.new(*injected_options.fetch(:adapter, [nil]), {
113
- 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
110
+ serializer = _serializer || serializer
127
111
 
128
- return @adapter
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]),
119
+ resource: resource, serializer: serializer
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
- # 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
128
+ @adapter
129
+ end
135
130
 
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
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
- 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
- return @collection_options = self.class::Collection.new(
165
- resource,
166
- injected_options: _injected_options,
167
- allowed_options: _allowed_options
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
- def serializer_class
172
- return @serializer_class if defined?(@serializer_class)
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
- @serializer_class = injected_options.fetch(:serializer, nil)
171
+ def serializer_class
172
+ return @serializer_class if defined?(@serializer_class)
175
173
 
176
- return @serializer_class if @serializer_class
174
+ @serializer_class = injected_options.fetch(:serializer, nil)
177
175
 
178
- return @serializer_class = infer_serializer
179
- end
176
+ return @serializer_class if @serializer_class
180
177
 
181
- #TODO: maybe have that inside :collection? (isomorphism)
182
- def collection_serializer_class
183
- return @collection_serializer_class if defined?(@collection_serializer_class)
178
+ @serializer_class = infer_serializer
179
+ end
184
180
 
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"
189
- end
190
- else
191
- @collection_serializer_class = serializer_class
192
- end
181
+ # TODO: maybe have that inside :collection? (isomorphism)
182
+ def collection_serializer_class
183
+ return @collection_serializer_class if defined?(@collection_serializer_class)
193
184
 
194
- return @collection_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'
189
+ end
190
+ else
191
+ @collection_serializer_class = serializer_class
195
192
  end
196
193
 
197
- private
198
- attr_reader :_internal
199
-
200
- #TODO: add method-based links, should boost performance
201
- def array_of_name_value_hash_for(collection_klass, item_klass, name)
202
- injected = injected_options.fetch(name, nil)
203
- if injected
204
- injected = collection_klass.new(
205
- injected.map{|l| item_klass.new(*l.flatten, {
206
- resource: resource, serializer: serializer
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
- allowed = collection_klass.new(
212
- allowed_options.fetch(name).map{|l| item_klass.new(*l, {
213
- resource: resource, serializer: serializer
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
- def array_of_value_hash_for(klass, name)
225
- _options = injected_options.fetch(name, nil)
226
- _options = allowed_options.fetch(name, nil) unless _options
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
- return klass.new(*_options, {
229
- resource: resource, serializer: serializer
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
- def array_of_items_for(klass, name)
234
- injected = injected_options.fetch(name, nil)
235
+ klass.new(
236
+ *_options,
237
+ resource: resource, serializer: serializer
238
+ )
239
+ end
235
240
 
236
- if injected.nil?
237
- return klass.new(allowed_options.fetch(name).uniq)
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
- def priority_options_for(allowed:, injected:)
247
- if not injected.nil?
248
- allowed = injected.class.new(
249
- injected.map{|s| s.is_a?(Hash) ? (s.first && s.first[0]) : s}
250
- ) & allowed
251
- end
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
- return allowed
254
- end
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
- =begin
257
- def options_for(allowed:, injected:)
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
- #TODO: raise exception if both are nil!
294
- def fetch_allowed_options
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
- if _serializer_class.respond_to?(:simple_ams?)
301
- return _serializer_class&.options
302
- else
303
- raise "#{_serializer_class} does not respond to SimpleAMS methods, did you include the DSL module?"
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
- def instantiated_serializer_for(serializer_klass)
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
- def infer_serializer
318
- namespace = _internal[:module] ? "#{_internal[:module]}::" : ""
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
- class EmptySerializer
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