serega 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/serega/attribute.rb +6 -1
  4. data/lib/serega/config.rb +2 -2
  5. data/lib/serega/map.rb +2 -4
  6. data/lib/serega/map_point.rb +34 -0
  7. data/lib/serega/object_serializer.rb +67 -0
  8. data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +4 -0
  9. data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +27 -8
  10. data/lib/serega/plugins/batch/batch.rb +189 -0
  11. data/lib/serega/plugins/batch/lib/loader.rb +60 -0
  12. data/lib/serega/plugins/batch/lib/loaders.rb +32 -0
  13. data/lib/serega/plugins/batch/lib/plugins_extensions.rb +40 -0
  14. data/lib/serega/plugins/batch/lib/validations/check_batch_opt_key.rb +61 -0
  15. data/lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb +61 -0
  16. data/lib/serega/plugins/batch/lib/validations/check_opt_batch.rb +47 -0
  17. data/lib/serega/plugins/context_metadata/context_metadata.rb +4 -4
  18. data/lib/serega/plugins/formatters/formatters.rb +25 -13
  19. data/lib/serega/plugins/hide_nil/hide_nil.rb +4 -4
  20. data/lib/serega/plugins/metadata/metadata.rb +11 -11
  21. data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +8 -6
  22. data/lib/serega/plugins/preloads/preloads.rb +12 -1
  23. data/lib/serega/plugins/presenter/presenter.rb +6 -5
  24. data/lib/serega/plugins/root/root.rb +12 -12
  25. data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +1 -1
  26. data/lib/serega/serializer.rb +32 -0
  27. data/lib/serega.rb +15 -10
  28. metadata +12 -5
  29. data/lib/serega/convert.rb +0 -45
  30. data/lib/serega/convert_item.rb +0 -37
  31. data/lib/serega/plugins/lazy/lazy.rb +0 -53
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaPlugins
5
+ module Batch
6
+ class CheckOptBatch
7
+ class << self
8
+ def call(opts, block)
9
+ return unless opts.key?(:batch)
10
+
11
+ SeregaValidations::Utils::CheckOptIsHash.call(opts, :batch)
12
+
13
+ batch = opts[:batch]
14
+ SeregaValidations::Utils::CheckAllowedKeys.call(batch, %i[key loader default])
15
+
16
+ check_batch_opt_key(batch[:key])
17
+ check_batch_opt_loader(batch[:loader])
18
+
19
+ check_usage_with_other_params(opts, block)
20
+ end
21
+
22
+ private
23
+
24
+ def check_batch_opt_key(key)
25
+ raise SeregaError, "Option :key must present inside :batch option" unless key
26
+
27
+ CheckBatchOptKey.call(key)
28
+ end
29
+
30
+ def check_batch_opt_loader(loader)
31
+ raise SeregaError, "Option :loader must present inside :batch option" unless loader
32
+
33
+ CheckBatchOptLoader.call(loader)
34
+ end
35
+
36
+ def check_usage_with_other_params(opts, block)
37
+ raise SeregaError, "Option :batch can not be used together with option :key" if opts.key?(:key)
38
+ raise SeregaError, "Option :batch can not be used together with option :value" if opts.key?(:value)
39
+ raise SeregaError, "Option :batch can not be used together with option :const" if opts.key?(:const)
40
+ raise SeregaError, "Option :batch can not be used together with option :delegate" if opts.key?(:delegate)
41
+ raise SeregaError, "Option :batch can not be used together with block" if block
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -15,7 +15,7 @@ class Serega
15
15
 
16
16
  def self.load_plugin(serializer_class, **_opts)
17
17
  serializer_class::SeregaConfig.include(ConfigInstanceMethods)
18
- serializer_class::SeregaConvert.include(SeregaConvertInstanceMethods)
18
+ serializer_class::SeregaSerializer.include(SeregaSerializerInstanceMethods)
19
19
  serializer_class::CheckSerializeParams.include(CheckSerializeParamsInstanceMethods)
20
20
  end
21
21
 
@@ -44,7 +44,7 @@ class Serega
44
44
 
45
45
  module ConfigInstanceMethods
46
46
  def context_metadata
47
- ContextMetadataConfig.new(opts.fetch(:context_metadata))
47
+ @context_metadata ||= ContextMetadataConfig.new(opts.fetch(:context_metadata))
48
48
  end
49
49
  end
50
50
 
@@ -57,8 +57,8 @@ class Serega
57
57
  end
58
58
  end
59
59
 
60
- module SeregaConvertInstanceMethods
61
- def to_h
60
+ module SeregaSerializerInstanceMethods
61
+ def serialize(object)
62
62
  super.tap do |hash|
63
63
  add_context_metadata(hash)
64
64
  end
@@ -7,6 +7,12 @@ class Serega
7
7
  :formatters
8
8
  end
9
9
 
10
+ def self.before_load_plugin(serializer_class, **opts)
11
+ if serializer_class.plugin_used?(:batch)
12
+ raise SeregaError, "Plugin `formatters` must be loaded before `batch`"
13
+ end
14
+ end
15
+
10
16
  def self.load_plugin(serializer_class, **_opts)
11
17
  serializer_class::SeregaConfig.include(ConfigInstanceMethods)
12
18
  serializer_class::SeregaAttribute.include(AttributeInstanceMethods)
@@ -35,21 +41,32 @@ class Serega
35
41
 
36
42
  module ConfigInstanceMethods
37
43
  def formatters
38
- FormattersConfig.new(opts.fetch(:formatters))
44
+ @formatters ||= FormattersConfig.new(opts.fetch(:formatters))
39
45
  end
40
46
  end
41
47
 
42
48
  module AttributeInstanceMethods
43
- def value_block
44
- return @value_block if instance_variable_defined?(:@value_block)
49
+ def formatter
50
+ return @formatter if instance_variable_defined?(:@formatter)
51
+
52
+ @formatter = formatter_resolved
53
+ end
45
54
 
46
- original_block = super
55
+ def formatter_resolved
47
56
  formatter = opts[:format]
48
- return original_block unless formatter
57
+ return unless formatter
49
58
 
50
- new_value_block = formatted_block(formatter, original_block)
59
+ formatter = self.class.serializer_class.config.formatters.opts.fetch(formatter) if formatter.is_a?(Symbol)
60
+ formatter
61
+ end
62
+
63
+ def value_block
64
+ return @value_block if instance_variable_defined?(:@value_block)
65
+ return @value_block = super unless formatter
66
+
67
+ new_value_block = formatted_block(formatter, super)
51
68
 
52
- # Detect formatted :const value in advance
69
+ # Format :const value in advance
53
70
  if opts.key?(:const)
54
71
  const_value = new_value_block.call
55
72
  new_value_block = proc { const_value }
@@ -63,12 +80,7 @@ class Serega
63
80
  def formatted_block(formatter, original_block)
64
81
  proc do |object, context|
65
82
  value = original_block.call(object, context)
66
-
67
- if formatter.is_a?(Symbol)
68
- self.class.serializer_class.config.formatters.opts.fetch(formatter).call(value)
69
- else
70
- formatter.call(value)
71
- end
83
+ formatter.call(value)
72
84
  end
73
85
  end
74
86
  end
@@ -23,7 +23,7 @@ class Serega
23
23
  def self.load_plugin(serializer_class, **_opts)
24
24
  serializer_class::SeregaAttribute.include(AttributeMethods)
25
25
  serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
26
- serializer_class::SeregaConvertItem.extend(SeregaConvertItemClassMethods)
26
+ serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
27
27
  end
28
28
 
29
29
  def self.after_load_plugin(serializer_class, **opts)
@@ -66,11 +66,11 @@ class Serega
66
66
  end
67
67
  end
68
68
 
69
- module SeregaConvertItemClassMethods
69
+ module SeregaObjectSerializerInstanceMethods
70
70
  private
71
71
 
72
- def attach_value(value, *args)
73
- super unless value.nil?
72
+ def attach_final_value(final_value, *)
73
+ super unless final_value.nil?
74
74
  end
75
75
  end
76
76
  end
@@ -20,7 +20,7 @@ class Serega
20
20
  def self.load_plugin(serializer_class, **_opts)
21
21
  serializer_class.extend(ClassMethods)
22
22
  serializer_class::SeregaConfig.include(ConfigInstanceMethods)
23
- serializer_class::SeregaConvert.include(SeregaConvertInstanceMethods)
23
+ serializer_class::SeregaSerializer.include(SeregaSerializerInstanceMethods)
24
24
 
25
25
  require_relative "./meta_attribute"
26
26
  require_relative "./validations/check_block"
@@ -52,7 +52,7 @@ class Serega
52
52
 
53
53
  module ConfigInstanceMethods
54
54
  def metadata
55
- MetadataConfig.new(opts.fetch(:metadata))
55
+ @metadata ||= MetadataConfig.new(opts.fetch(:metadata))
56
56
  end
57
57
  end
58
58
 
@@ -104,26 +104,26 @@ class Serega
104
104
  end
105
105
  end
106
106
 
107
- module SeregaConvertInstanceMethods
108
- def to_h
109
- hash = super
110
- add_metadata(hash)
111
- hash
107
+ module SeregaSerializerInstanceMethods
108
+ def serialize(object)
109
+ super.tap do |hash|
110
+ add_metadata(object, hash)
111
+ end
112
112
  end
113
113
 
114
114
  private
115
115
 
116
- def add_metadata(hash)
116
+ def add_metadata(object, hash)
117
117
  self.class.serializer_class.meta_attributes.each_value do |meta_attribute|
118
- metadata = meta_attribute_value(meta_attribute)
118
+ metadata = meta_attribute_value(object, meta_attribute)
119
119
  next unless metadata
120
120
 
121
121
  deep_merge_metadata(hash, metadata)
122
122
  end
123
123
  end
124
124
 
125
- def meta_attribute_value(meta_attribute)
126
- value = meta_attribute.value(object, opts[:context])
125
+ def meta_attribute_value(object, meta_attribute)
126
+ value = meta_attribute.value(object, context)
127
127
  return if meta_attribute.hide?(value)
128
128
 
129
129
  # Example:
@@ -16,6 +16,8 @@ class Serega
16
16
  # @return [Hash]
17
17
  #
18
18
  def call(map)
19
+ return FROZEN_EMPTY_HASH unless map
20
+
19
21
  preloads = {}
20
22
  append_many(preloads, map)
21
23
  preloads
@@ -24,17 +26,17 @@ class Serega
24
26
  private
25
27
 
26
28
  def append_many(preloads, map)
27
- map.each do |attribute, nested_map|
28
- current_preloads = attribute.preloads
29
+ map.each do |point|
30
+ current_preloads = point.attribute.preloads
29
31
  next unless current_preloads
30
32
 
31
- has_nested = nested_map.any?
33
+ has_nested = point.has_nested_points?
32
34
  current_preloads = SeregaUtils::EnumDeepDup.call(current_preloads) if has_nested
33
35
  append_current(preloads, current_preloads)
34
36
  next unless has_nested
35
37
 
36
- nested_preloads = nested(preloads, attribute.preloads_path)
37
- append_many(nested_preloads, nested_map)
38
+ nested_preloads = nested(preloads, point.preloads_path)
39
+ append_many(nested_preloads, point.nested_points)
38
40
  end
39
41
  end
40
42
 
@@ -49,7 +51,7 @@ class Serega
49
51
  end
50
52
 
51
53
  def nested(preloads, path)
52
- !path || path.empty? ? preloads : preloads.dig(*path)
54
+ (!path || path.empty?) ? preloads : preloads.dig(*path)
53
55
  end
54
56
  end
55
57
 
@@ -29,6 +29,7 @@ class Serega
29
29
  serializer_class.include(InstanceMethods)
30
30
  serializer_class::SeregaAttribute.include(AttributeMethods)
31
31
  serializer_class::SeregaConfig.include(ConfigInstanceMethods)
32
+ serializer_class::SeregaMapPoint.include(MapPointMethods)
32
33
 
33
34
  serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
34
35
 
@@ -85,7 +86,7 @@ class Serega
85
86
 
86
87
  module ConfigInstanceMethods
87
88
  def preloads
88
- PreloadsConfig.new(opts.fetch(:preloads))
89
+ @preloads ||= PreloadsConfig.new(opts.fetch(:preloads))
89
90
  end
90
91
  end
91
92
 
@@ -142,6 +143,16 @@ class Serega
142
143
  end
143
144
  end
144
145
 
146
+ module MapPointMethods
147
+ def preloads
148
+ @preloads ||= PreloadsConstructor.call(nested_points)
149
+ end
150
+
151
+ def preloads_path
152
+ attribute.preloads_path
153
+ end
154
+ end
155
+
145
156
  module CheckAttributeParamsInstanceMethods
146
157
  private
147
158
 
@@ -35,7 +35,7 @@ class Serega
35
35
  #
36
36
  def self.load_plugin(serializer_class, **_opts)
37
37
  serializer_class.extend(ClassMethods)
38
- serializer_class::SeregaConvertItem.extend(SeregaConvertItemClassMethods)
38
+ serializer_class::SeregaSerializer.include(SeregaSerializerInstanceMethods)
39
39
  end
40
40
 
41
41
  #
@@ -94,13 +94,14 @@ class Serega
94
94
  end
95
95
  end
96
96
 
97
- # Includes methods to override SeregaConvertItem class
98
- module SeregaConvertItemClassMethods
97
+ # Includes methods to override SeregaSerializer class
98
+ module SeregaSerializerInstanceMethods
99
99
  #
100
100
  # Replaces serialized object with Presenter.new(object)
101
101
  #
102
- def call(object, *)
103
- object = serializer_class::Presenter.new(object)
102
+ def serialize(object)
103
+ presenter_class = points.first.class.serializer_class::Presenter
104
+ object = presenter_class.new(object)
104
105
  super
105
106
  end
106
107
  end
@@ -12,8 +12,8 @@ class Serega
12
12
 
13
13
  def self.load_plugin(serializer_class, **_opts)
14
14
  serializer_class.extend(ClassMethods)
15
- serializer_class::SeregaConfig.include(SeregaConfigInstanceMethods)
16
- serializer_class::SeregaConvert.include(SeregaConvertInstanceMethods)
15
+ serializer_class::SeregaConfig.include(ConfigInstanceMethods)
16
+ serializer_class::SeregaSerializer.include(SerializerInstanceMethods)
17
17
  end
18
18
 
19
19
  def self.after_load_plugin(serializer_class, **opts)
@@ -70,9 +70,9 @@ class Serega
70
70
  end
71
71
  end
72
72
 
73
- module SeregaConfigInstanceMethods
73
+ module ConfigInstanceMethods
74
74
  def root
75
- RootConfig.new(opts.fetch(:root))
75
+ @root ||= RootConfig.new(opts.fetch(:root))
76
76
  end
77
77
 
78
78
  def root=(value)
@@ -81,21 +81,21 @@ class Serega
81
81
  end
82
82
  end
83
83
 
84
- module SeregaConvertInstanceMethods
85
- def to_h
86
- hash = super
87
- root = build_root(opts)
88
- hash = {root => hash} if root
89
- hash
84
+ module SerializerInstanceMethods
85
+ def serialize(_object)
86
+ result = super
87
+ root = build_root(result, opts)
88
+ result = {root => result} if root
89
+ result
90
90
  end
91
91
 
92
92
  private
93
93
 
94
- def build_root(opts)
94
+ def build_root(result, opts)
95
95
  return opts[:root] if opts.key?(:root)
96
96
 
97
97
  root = self.class.serializer_class.config.root
98
- many? ? root.many : root.one
98
+ result.is_a?(Array) ? root.many : root.one
99
99
  end
100
100
  end
101
101
  end
@@ -53,7 +53,7 @@ class Serega
53
53
  name = attribute.to_sym
54
54
  attribute.clear
55
55
 
56
- current_attrs = !path_stack || path_stack.empty? ? res : res.dig(*path_stack)
56
+ current_attrs = (!path_stack || path_stack.empty?) ? res : res.dig(*path_stack)
57
57
  current_attrs[name] = nested_attributes
58
58
 
59
59
  name
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ class SeregaSerializer
5
+ module SeregaSerializerInstanceMethods
6
+ # @param context [Hash] Serialization context
7
+ # @param many [TrueClass|FalseClass] is object is enumerable
8
+ # @param points [Array<MapPoint>] Serialization points (attributes)
9
+ # @param opts [Hash] Any custom options
10
+ def initialize(context:, points:, many: nil, **opts)
11
+ @context = context
12
+ @points = points
13
+ @many = many
14
+ @opts = opts
15
+ end
16
+
17
+ # @param object [Object] Serialized object
18
+ def serialize(object)
19
+ self.class.serializer_class::SeregaObjectSerializer
20
+ .new(context: context, points: points, many: many, **opts)
21
+ .serialize(object)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :context, :points, :many, :opts
27
+ end
28
+
29
+ extend Serega::SeregaHelpers::SerializerClassHelper
30
+ include SeregaSerializerInstanceMethods
31
+ end
32
+ end
data/lib/serega.rb CHANGED
@@ -37,8 +37,9 @@ require_relative "serega/validations/check_initiate_params"
37
37
  require_relative "serega/validations/check_serialize_params"
38
38
 
39
39
  require_relative "serega/config"
40
- require_relative "serega/convert"
41
- require_relative "serega/convert_item"
40
+ require_relative "serega/object_serializer"
41
+ require_relative "serega/serializer"
42
+ require_relative "serega/map_point"
42
43
  require_relative "serega/map"
43
44
  require_relative "serega/plugins"
44
45
 
@@ -79,13 +80,17 @@ class Serega
79
80
  map_class.serializer_class = subclass
80
81
  subclass.const_set(:SeregaMap, map_class)
81
82
 
82
- convert_class = Class.new(self::SeregaConvert)
83
- convert_class.serializer_class = subclass
84
- subclass.const_set(:SeregaConvert, convert_class)
83
+ map_point_class = Class.new(self::SeregaMapPoint)
84
+ map_point_class.serializer_class = subclass
85
+ subclass.const_set(:SeregaMapPoint, map_point_class)
85
86
 
86
- convert_item_class = Class.new(self::SeregaConvertItem)
87
- convert_item_class.serializer_class = subclass
88
- subclass.const_set(:SeregaConvertItem, convert_item_class)
87
+ serega_serializer_class = Class.new(self::SeregaSerializer)
88
+ serega_serializer_class.serializer_class = subclass
89
+ subclass.const_set(:SeregaSerializer, serega_serializer_class)
90
+
91
+ object_serializer_class = Class.new(self::SeregaObjectSerializer)
92
+ object_serializer_class.serializer_class = subclass
93
+ subclass.const_set(:SeregaObjectSerializer, object_serializer_class)
89
94
 
90
95
  check_attribute_params_class = Class.new(self::CheckAttributeParams)
91
96
  check_attribute_params_class.serializer_class = subclass
@@ -208,7 +213,7 @@ class Serega
208
213
  # @param with [Array, Hash, String, Symbol] Attributes (usually hidden) to serialize additionally
209
214
  #
210
215
  def initialize(opts = FROZEN_EMPTY_HASH)
211
- @opts = opts == FROZEN_EMPTY_HASH ? opts : prepare_modifiers(opts)
216
+ @opts = (opts == FROZEN_EMPTY_HASH) ? opts : prepare_modifiers(opts)
212
217
  self.class::CheckInitiateParams.new(@opts).validate if opts.fetch(:check_initiate_params) { config.check_initiate_params }
213
218
  end
214
219
 
@@ -224,7 +229,7 @@ class Serega
224
229
  self.class::CheckSerializeParams.new(opts).validate
225
230
  opts[:context] ||= {}
226
231
 
227
- self.class::SeregaConvert.call(object, **opts, map: map)
232
+ self.class::SeregaSerializer.new(points: map, **opts).serialize(object)
228
233
  end
229
234
 
230
235
  # @see #call
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Glushkov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-20 00:00:00.000000000 Z
11
+ date: 2022-11-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -21,21 +21,27 @@ files:
21
21
  - lib/serega.rb
22
22
  - lib/serega/attribute.rb
23
23
  - lib/serega/config.rb
24
- - lib/serega/convert.rb
25
- - lib/serega/convert_item.rb
26
24
  - lib/serega/errors.rb
27
25
  - lib/serega/helpers/serializer_class_helper.rb
28
26
  - lib/serega/json/adapter.rb
29
27
  - lib/serega/json/json.rb
30
28
  - lib/serega/json/oj.rb
31
29
  - lib/serega/map.rb
30
+ - lib/serega/map_point.rb
31
+ - lib/serega/object_serializer.rb
32
32
  - lib/serega/plugins.rb
33
33
  - lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb
34
34
  - lib/serega/plugins/activerecord_preloads/lib/preloader.rb
35
+ - lib/serega/plugins/batch/batch.rb
36
+ - lib/serega/plugins/batch/lib/loader.rb
37
+ - lib/serega/plugins/batch/lib/loaders.rb
38
+ - lib/serega/plugins/batch/lib/plugins_extensions.rb
39
+ - lib/serega/plugins/batch/lib/validations/check_batch_opt_key.rb
40
+ - lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb
41
+ - lib/serega/plugins/batch/lib/validations/check_opt_batch.rb
35
42
  - lib/serega/plugins/context_metadata/context_metadata.rb
36
43
  - lib/serega/plugins/formatters/formatters.rb
37
44
  - lib/serega/plugins/hide_nil/hide_nil.rb
38
- - lib/serega/plugins/lazy/lazy.rb
39
45
  - lib/serega/plugins/metadata/meta_attribute.rb
40
46
  - lib/serega/plugins/metadata/metadata.rb
41
47
  - lib/serega/plugins/metadata/validations/check_block.rb
@@ -54,6 +60,7 @@ files:
54
60
  - lib/serega/plugins/root/root.rb
55
61
  - lib/serega/plugins/string_modifiers/parse_string_modifiers.rb
56
62
  - lib/serega/plugins/string_modifiers/string_modifiers.rb
63
+ - lib/serega/serializer.rb
57
64
  - lib/serega/utils/enum_deep_dup.rb
58
65
  - lib/serega/utils/to_hash.rb
59
66
  - lib/serega/validations/attribute/check_block.rb
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- class SeregaConvert
5
- module SeregaConvertClassMethods
6
- def call(object, **opts)
7
- new(object, **opts).to_h
8
- end
9
- end
10
-
11
- module SeregaConvertInstanceMethods
12
- attr_reader :object, :opts
13
-
14
- def initialize(object, **opts)
15
- @object = object
16
- @opts = opts
17
- end
18
-
19
- def to_h
20
- many? ? many(object) : one(object) || {}
21
- end
22
-
23
- private
24
-
25
- def many(objects)
26
- objects.map { |obj| one(obj) }
27
- end
28
-
29
- def one(object)
30
- self.class.serializer_class::SeregaConvertItem.call(object, opts[:context], opts[:map])
31
- end
32
-
33
- def many?
34
- many = opts[:many]
35
- return many unless many.nil?
36
-
37
- object.is_a?(Enumerable)
38
- end
39
- end
40
-
41
- extend Serega::SeregaHelpers::SerializerClassHelper
42
- extend SeregaConvertClassMethods
43
- include SeregaConvertInstanceMethods
44
- end
45
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- class SeregaConvertItem
5
- module SeregaConvertItemClassMethods
6
- def call(object, context, map)
7
- return unless object
8
-
9
- map.each_with_object({}) do |(attribute, nested_attributes), hash|
10
- value = attribute.value(object, context)
11
- attach_value(value, hash, attribute, nested_attributes, context)
12
- end
13
- end
14
-
15
- private
16
-
17
- def attach_value(value, hash, attribute, nested_attributes, context)
18
- hash[attribute.name] =
19
- if nested_attributes.empty?
20
- attribute.relation? ? FROZEN_EMPTY_HASH : value
21
- elsif many?(attribute, value)
22
- value.map { |val| call(val, context, nested_attributes) }
23
- else
24
- call(value, context, nested_attributes)
25
- end
26
- end
27
-
28
- def many?(attribute, object)
29
- is_many = attribute.many
30
- is_many.nil? ? object.is_a?(Enumerable) : is_many
31
- end
32
- end
33
-
34
- extend Serega::SeregaHelpers::SerializerClassHelper
35
- extend SeregaConvertItemClassMethods
36
- end
37
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module SeregaPlugins
5
- module Lazy
6
- def self.plugin_name
7
- :lazy
8
- end
9
-
10
- def self.before_load_plugin(serializer_class, **opts)
11
- end
12
-
13
- def self.load_plugin(serializer_class, **_opts)
14
- serializer_class.extend(ClassMethods)
15
- serializer_class.include(InstanceMethods)
16
- end
17
-
18
- def self.after_load_plugin(serializer_class, **_opts)
19
- serializer_class.config.attribute_keys << :lazy
20
- end
21
- end
22
-
23
- module ClassMethods
24
- def lazy(key:, buffer:, resolver:)
25
- @lazy[key] = { buffer: buffer, resolver: resolver }
26
- end
27
- end
28
-
29
- module InstanceMethods
30
- def initialize(*args, **kwargs)
31
- super
32
- @lazy = {}
33
- end
34
-
35
- def to_h(*args, **kwargs)
36
- result = super
37
- lazy.each_key do |key, |
38
- buffer = lazy.delete(key) # { val => [paths], val2 => [paths2] }
39
- buffer_values = self.class.lazy[key][:resolver].(buffer.keys)
40
-
41
- buffer_values.each do |key, resolved_value|
42
- paths = buffer[key]
43
- paths.each do |path|
44
- result.dig(path[0, -2])
45
- replace(result, buffer_values)
46
- end
47
-
48
- end
49
- end
50
-
51
- register_plugin(Metadata.plugin_name, Metadata)
52
- end
53
- end