serega 0.1.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/serega/attribute.rb +17 -4
  4. data/lib/serega/config.rb +69 -27
  5. data/lib/serega/convert.rb +7 -7
  6. data/lib/serega/convert_item.rb +4 -4
  7. data/lib/serega/errors.rb +12 -0
  8. data/lib/serega/helpers/serializer_class_helper.rb +1 -1
  9. data/lib/serega/json/adapter.rb +17 -0
  10. data/lib/serega/json/json.rb +17 -0
  11. data/lib/serega/json/oj.rb +17 -0
  12. data/lib/serega/map.rb +25 -15
  13. data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +3 -3
  14. data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +2 -2
  15. data/lib/serega/plugins/context_metadata/context_metadata.rb +34 -11
  16. data/lib/serega/plugins/formatters/formatters.rb +35 -6
  17. data/lib/serega/plugins/hide_nil/hide_nil.rb +7 -7
  18. data/lib/serega/plugins/metadata/meta_attribute.rb +5 -5
  19. data/lib/serega/plugins/metadata/metadata.rb +30 -5
  20. data/lib/serega/plugins/metadata/validations/check_block.rb +4 -4
  21. data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +3 -3
  22. data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +3 -3
  23. data/lib/serega/plugins/metadata/validations/check_opts.rb +3 -3
  24. data/lib/serega/plugins/metadata/validations/check_path.rb +3 -3
  25. data/lib/serega/plugins/preloads/lib/enum_deep_freeze.rb +1 -1
  26. data/lib/serega/plugins/preloads/lib/format_user_preloads.rb +1 -1
  27. data/lib/serega/plugins/preloads/lib/main_preload_path.rb +1 -1
  28. data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +2 -2
  29. data/lib/serega/plugins/preloads/preloads.rb +63 -5
  30. data/lib/serega/plugins/preloads/validations/check_opt_preload.rb +17 -0
  31. data/lib/serega/plugins/preloads/validations/check_opt_preload_path.rb +4 -4
  32. data/lib/serega/plugins/presenter/presenter.rb +6 -6
  33. data/lib/serega/plugins/root/root.rb +48 -8
  34. data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +1 -1
  35. data/lib/serega/plugins/string_modifiers/string_modifiers.rb +7 -7
  36. data/lib/serega/plugins.rb +7 -7
  37. data/lib/serega/utils/enum_deep_dup.rb +1 -1
  38. data/lib/serega/utils/to_hash.rb +2 -2
  39. data/lib/serega/validations/attribute/check_block.rb +3 -3
  40. data/lib/serega/validations/attribute/check_name.rb +3 -3
  41. data/lib/serega/validations/attribute/check_opt_const.rb +5 -5
  42. data/lib/serega/validations/attribute/check_opt_delegate.rb +57 -0
  43. data/lib/serega/validations/attribute/check_opt_hide.rb +2 -2
  44. data/lib/serega/validations/attribute/check_opt_key.rb +5 -5
  45. data/lib/serega/validations/attribute/check_opt_many.rb +2 -2
  46. data/lib/serega/validations/attribute/check_opt_serializer.rb +3 -3
  47. data/lib/serega/validations/attribute/check_opt_value.rb +7 -7
  48. data/lib/serega/validations/check_attribute_params.rb +4 -3
  49. data/lib/serega/validations/check_initiate_params.rb +23 -10
  50. data/lib/serega/validations/check_serialize_params.rb +16 -10
  51. data/lib/serega/{plugins/validate_modifiers/validate.rb → validations/initiate/check_modifiers.rb} +5 -5
  52. data/lib/serega/validations/utils/check_allowed_keys.rb +2 -2
  53. data/lib/serega/validations/utils/check_opt_is_bool.rb +2 -2
  54. data/lib/serega/validations/utils/check_opt_is_hash.rb +2 -2
  55. data/lib/serega/validations/utils/check_opt_is_string_or_symbol.rb +2 -2
  56. data/lib/serega.rb +52 -72
  57. metadata +9 -6
  58. data/lib/serega/plugins/validate_modifiers/validate_modifiers.rb +0 -44
  59. data/lib/serega/utils/as_json.rb +0 -35
  60. data/lib/serega/utils/to_json.rb +0 -22
data/lib/serega.rb CHANGED
@@ -4,9 +4,6 @@ require_relative "serega/version"
4
4
 
5
5
  # Parent class for your serializers
6
6
  class Serega
7
- # A generic exception Serega uses.
8
- class Error < StandardError; end
9
-
10
7
  # @return [Hash] frozen hash
11
8
  FROZEN_EMPTY_HASH = {}.freeze
12
9
 
@@ -14,11 +11,11 @@ class Serega
14
11
  FROZEN_EMPTY_ARRAY = [].freeze
15
12
  end
16
13
 
14
+ require_relative "serega/errors"
17
15
  require_relative "serega/helpers/serializer_class_helper"
18
16
  require_relative "serega/utils/enum_deep_dup"
19
17
  require_relative "serega/utils/to_hash"
20
- require_relative "serega/utils/to_json"
21
- require_relative "serega/utils/as_json"
18
+ require_relative "serega/json/adapter"
22
19
 
23
20
  require_relative "serega/attribute"
24
21
  require_relative "serega/validations/utils/check_allowed_keys"
@@ -29,10 +26,12 @@ require_relative "serega/validations/attribute/check_block"
29
26
  require_relative "serega/validations/attribute/check_name"
30
27
  require_relative "serega/validations/attribute/check_opt_const"
31
28
  require_relative "serega/validations/attribute/check_opt_hide"
29
+ require_relative "serega/validations/attribute/check_opt_delegate"
32
30
  require_relative "serega/validations/attribute/check_opt_key"
33
31
  require_relative "serega/validations/attribute/check_opt_many"
34
32
  require_relative "serega/validations/attribute/check_opt_serializer"
35
33
  require_relative "serega/validations/attribute/check_opt_value"
34
+ require_relative "serega/validations/initiate/check_modifiers"
36
35
  require_relative "serega/validations/check_attribute_params"
37
36
  require_relative "serega/validations/check_initiate_params"
38
37
  require_relative "serega/validations/check_serialize_params"
@@ -44,55 +43,49 @@ require_relative "serega/map"
44
43
  require_relative "serega/plugins"
45
44
 
46
45
  class Serega
47
- @config = Config.new(
48
- {
49
- plugins: [],
50
- initiate_keys: %i[only with except],
51
- attribute_keys: %i[key value serializer many hide const],
52
- serialize_keys: %i[context many],
53
- max_cached_map_per_serializer_count: 50,
54
- to_json: ->(data) { Utils::ToJSON.call(data) }
55
- }
56
- )
57
-
58
- check_attribute_params_class = Class.new(Validations::CheckAttributeParams)
46
+ @config = SeregaConfig.new
47
+
48
+ # Validates `Serializer.attribute` params
49
+ check_attribute_params_class = Class.new(SeregaValidations::CheckAttributeParams)
59
50
  check_attribute_params_class.serializer_class = self
60
51
  const_set(:CheckAttributeParams, check_attribute_params_class)
61
52
 
62
- check_initiate_params_class = Class.new(Validations::CheckInitiateParams)
53
+ # Validates `Serializer#new` params
54
+ check_initiate_params_class = Class.new(SeregaValidations::CheckInitiateParams)
63
55
  check_initiate_params_class.serializer_class = self
64
56
  const_set(:CheckInitiateParams, check_initiate_params_class)
65
57
 
66
- check_serialize_params_class = Class.new(Validations::CheckSerializeParams)
58
+ # Validates `serializer#call(obj, PARAMS)` params
59
+ check_serialize_params_class = Class.new(SeregaValidations::CheckSerializeParams)
67
60
  check_serialize_params_class.serializer_class = self
68
61
  const_set(:CheckSerializeParams, check_serialize_params_class)
69
62
 
70
63
  # Core serializer class methods
71
64
  module ClassMethods
72
- # @return [Config] current serializer config
65
+ # @return [SeregaConfig] current serializer config
73
66
  attr_reader :config
74
67
 
75
68
  private def inherited(subclass)
76
- config_class = Class.new(self::Config)
69
+ config_class = Class.new(self::SeregaConfig)
77
70
  config_class.serializer_class = subclass
78
- subclass.const_set(:Config, config_class)
79
- subclass.instance_variable_set(:@config, subclass::Config.new(config.opts))
71
+ subclass.const_set(:SeregaConfig, config_class)
72
+ subclass.instance_variable_set(:@config, subclass::SeregaConfig.new(config.opts))
80
73
 
81
- attribute_class = Class.new(self::Attribute)
74
+ attribute_class = Class.new(self::SeregaAttribute)
82
75
  attribute_class.serializer_class = subclass
83
- subclass.const_set(:Attribute, attribute_class)
76
+ subclass.const_set(:SeregaAttribute, attribute_class)
84
77
 
85
- map_class = Class.new(self::Map)
78
+ map_class = Class.new(self::SeregaMap)
86
79
  map_class.serializer_class = subclass
87
- subclass.const_set(:Map, map_class)
80
+ subclass.const_set(:SeregaMap, map_class)
88
81
 
89
- convert_class = Class.new(self::Convert)
82
+ convert_class = Class.new(self::SeregaConvert)
90
83
  convert_class.serializer_class = subclass
91
- subclass.const_set(:Convert, convert_class)
84
+ subclass.const_set(:SeregaConvert, convert_class)
92
85
 
93
- convert_item_class = Class.new(self::ConvertItem)
86
+ convert_item_class = Class.new(self::SeregaConvertItem)
94
87
  convert_item_class.serializer_class = subclass
95
- subclass.const_set(:ConvertItem, convert_item_class)
88
+ subclass.const_set(:SeregaConvertItem, convert_item_class)
96
89
 
97
90
  check_attribute_params_class = Class.new(self::CheckAttributeParams)
98
91
  check_attribute_params_class.serializer_class = subclass
@@ -123,9 +116,9 @@ class Serega
123
116
  # @return [class<Module>] Loaded plugin module
124
117
  #
125
118
  def plugin(name, **opts)
126
- raise Error, "This plugin is already loaded" if plugin_used?(name)
119
+ raise SeregaError, "This plugin is already loaded" if plugin_used?(name)
127
120
 
128
- plugin = Plugins.find_plugin(name)
121
+ plugin = SeregaPlugins.find_plugin(name)
129
122
 
130
123
  # We split loading of plugin to three parts - before_load, load, after_load:
131
124
  #
@@ -137,7 +130,7 @@ class Serega
137
130
  plugin.after_load_plugin(self, **opts) if plugin.respond_to?(:after_load_plugin)
138
131
 
139
132
  # Store attached plugins, so we can check it is loaded later
140
- config[:plugins] << (plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin)
133
+ config.plugins << (plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin)
141
134
 
142
135
  plugin
143
136
  end
@@ -156,7 +149,7 @@ class Serega
156
149
  else name
157
150
  end
158
151
 
159
- config[:plugins].include?(plugin_name)
152
+ config.plugins.include?(plugin_name)
160
153
  end
161
154
 
162
155
  #
@@ -175,29 +168,15 @@ class Serega
175
168
  # @param opts [Hash] Options to serialize attribute
176
169
  # @param block [Proc] Custom block to find attribute value. Accepts object and context.
177
170
  #
178
- # @return [Serega::Attribute] Added attribute
171
+ # @return [Serega::SeregaAttribute] Added attribute
179
172
  #
180
173
  def attribute(name, **opts, &block)
181
- attribute = self::Attribute.new(name: name, opts: opts, block: block)
174
+ attribute = self::SeregaAttribute.new(name: name, opts: opts, block: block)
182
175
  attributes[attribute.name] = attribute
183
176
  end
184
177
 
185
- #
186
- # Adds attribute with forced :serializer option
187
- #
188
- # @param name [Symbol] Attribute name. Attribute value will be found by executing `object.<name>`
189
- # @param serializer [Serega, Proc] Specifies nested serializer for relationship
190
- # @param opts [Hash] Options for attribute serialization
191
- # @param block [Proc] Custom block to find attribute value. Accepts object and context.
192
- #
193
- # @return [Serega::Attribute] Added attribute
194
- #
195
- def relation(name, serializer:, **opts, &block)
196
- attribute(name, serializer: serializer, **opts, &block)
197
- end
198
-
199
178
  def call(object, opts = FROZEN_EMPTY_HASH)
200
- initiate_keys = config[:initiate_keys]
179
+ initiate_keys = config.initiate_keys
201
180
  new(opts.slice(*initiate_keys)).to_h(object, opts.except(*initiate_keys))
202
181
  end
203
182
 
@@ -206,13 +185,12 @@ class Serega
206
185
  end
207
186
 
208
187
  def to_json(object, opts = FROZEN_EMPTY_HASH)
209
- initiate_keys = config[:initiate_keys]
188
+ initiate_keys = config.initiate_keys
210
189
  new(opts.slice(*initiate_keys)).to_json(object, opts.except(*initiate_keys))
211
190
  end
212
191
 
213
192
  def as_json(object, opts = FROZEN_EMPTY_HASH)
214
- initiate_keys = config[:initiate_keys]
215
- new(opts.slice(*initiate_keys)).as_json(object, opts.except(*initiate_keys))
193
+ config.from_json.call(to_json(object, opts))
216
194
  end
217
195
  end
218
196
 
@@ -230,9 +208,8 @@ class Serega
230
208
  # @param with [Array, Hash, String, Symbol] Attributes (usually hidden) to serialize additionally
231
209
  #
232
210
  def initialize(opts = FROZEN_EMPTY_HASH)
233
- self.class::CheckInitiateParams.call(opts)
234
- opts = prepare_modifiers(opts) if opts && (opts != FROZEN_EMPTY_HASH)
235
- @opts = opts
211
+ @opts = opts == FROZEN_EMPTY_HASH ? opts : prepare_modifiers(opts)
212
+ self.class::CheckInitiateParams.new(@opts).validate if opts.fetch(:check_initiate_params) { config.check_initiate_params }
236
213
  end
237
214
 
238
215
  #
@@ -244,10 +221,10 @@ class Serega
244
221
  # @return [Hash] Serialization result
245
222
  #
246
223
  def call(object, opts = {})
247
- self.class::CheckSerializeParams.call(opts)
224
+ self.class::CheckSerializeParams.new(opts).validate
248
225
  opts[:context] ||= {}
249
226
 
250
- self.class::Convert.call(object, **opts, map: map)
227
+ self.class::SeregaConvert.call(object, **opts, map: map)
251
228
  end
252
229
 
253
230
  # @see #call
@@ -262,37 +239,40 @@ class Serega
262
239
  #
263
240
  # @return [Hash] Serialization result
264
241
  #
265
- def to_json(object, opts = FROZEN_EMPTY_HASH)
242
+ def to_json(object, opts = {})
266
243
  hash = to_h(object, opts)
267
- self.class.config[:to_json].call(hash)
244
+ config.to_json.call(hash)
268
245
  end
269
246
 
270
247
  #
271
248
  # Serializes provided object as json (uses only JSON-compatible types)
272
- # When you later serialize/deserialize it from JSON you should receive
249
+ # When you later serialize/de-serialize it from JSON you should receive
273
250
  # equal object
274
251
  #
275
252
  # @param object [Object] Serialized object
276
253
  #
277
254
  # @return [Hash] Serialization result
278
255
  #
279
- def as_json(object, opts = FROZEN_EMPTY_HASH)
280
- hash = to_h(object, opts)
281
- Utils::AsJSON.call(hash, to_json: self.class.config[:to_json])
256
+ def as_json(object, opts = {})
257
+ json = to_json(object, opts)
258
+ config.from_json.call(json)
282
259
  end
283
260
 
284
261
  private
285
262
 
263
+ def config
264
+ self.class.config
265
+ end
266
+
286
267
  def map
287
- @map ||= self.class::Map.call(opts)
268
+ @map ||= self.class::SeregaMap.call(opts)
288
269
  end
289
270
 
290
271
  def prepare_modifiers(opts)
291
- {
292
- only: Utils::ToHash.call(opts[:only]),
293
- except: Utils::ToHash.call(opts[:except]),
294
- with: Utils::ToHash.call(opts[:with])
295
- }
272
+ opts.each_with_object({}) do |(key, value), obj|
273
+ value = SeregaUtils::ToHash.call(value) if (key == :only) || (key == :except) || (key == :with)
274
+ obj[key] = value
275
+ end
296
276
  end
297
277
  end
298
278
 
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.1.4
4
+ version: 0.3.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-07-25 00:00:00.000000000 Z
11
+ date: 2022-08-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -23,7 +23,11 @@ files:
23
23
  - lib/serega/config.rb
24
24
  - lib/serega/convert.rb
25
25
  - lib/serega/convert_item.rb
26
+ - lib/serega/errors.rb
26
27
  - lib/serega/helpers/serializer_class_helper.rb
28
+ - lib/serega/json/adapter.rb
29
+ - lib/serega/json/json.rb
30
+ - lib/serega/json/oj.rb
27
31
  - lib/serega/map.rb
28
32
  - lib/serega/plugins.rb
29
33
  - lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb
@@ -43,20 +47,18 @@ files:
43
47
  - lib/serega/plugins/preloads/lib/main_preload_path.rb
44
48
  - lib/serega/plugins/preloads/lib/preloads_constructor.rb
45
49
  - lib/serega/plugins/preloads/preloads.rb
50
+ - lib/serega/plugins/preloads/validations/check_opt_preload.rb
46
51
  - lib/serega/plugins/preloads/validations/check_opt_preload_path.rb
47
52
  - lib/serega/plugins/presenter/presenter.rb
48
53
  - lib/serega/plugins/root/root.rb
49
54
  - lib/serega/plugins/string_modifiers/parse_string_modifiers.rb
50
55
  - lib/serega/plugins/string_modifiers/string_modifiers.rb
51
- - lib/serega/plugins/validate_modifiers/validate.rb
52
- - lib/serega/plugins/validate_modifiers/validate_modifiers.rb
53
- - lib/serega/utils/as_json.rb
54
56
  - lib/serega/utils/enum_deep_dup.rb
55
57
  - lib/serega/utils/to_hash.rb
56
- - lib/serega/utils/to_json.rb
57
58
  - lib/serega/validations/attribute/check_block.rb
58
59
  - lib/serega/validations/attribute/check_name.rb
59
60
  - lib/serega/validations/attribute/check_opt_const.rb
61
+ - lib/serega/validations/attribute/check_opt_delegate.rb
60
62
  - lib/serega/validations/attribute/check_opt_hide.rb
61
63
  - lib/serega/validations/attribute/check_opt_key.rb
62
64
  - lib/serega/validations/attribute/check_opt_many.rb
@@ -65,6 +67,7 @@ files:
65
67
  - lib/serega/validations/check_attribute_params.rb
66
68
  - lib/serega/validations/check_initiate_params.rb
67
69
  - lib/serega/validations/check_serialize_params.rb
70
+ - lib/serega/validations/initiate/check_modifiers.rb
68
71
  - lib/serega/validations/utils/check_allowed_keys.rb
69
72
  - lib/serega/validations/utils/check_opt_is_bool.rb
70
73
  - lib/serega/validations/utils/check_opt_is_hash.rb
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module Plugins
5
- module ValidateModifiers
6
- def self.plugin_name
7
- :validate_modifiers
8
- end
9
-
10
- def self.load_plugin(serializer_class, **_opts)
11
- serializer_class.include(InstanceMethods)
12
- require_relative "./validate"
13
- end
14
-
15
- def self.after_load_plugin(serializer_class, **opts)
16
- serializer_class.config[:validate_modifiers] = {auto: opts.fetch(:auto, true)}
17
- end
18
-
19
- module InstanceMethods
20
- # Raises error if some modifiers are invalid
21
- def validate_modifiers
22
- @modifiers_validated ||= begin
23
- Validate.call(self.class, opts[:only])
24
- Validate.call(self.class, opts[:except])
25
- Validate.call(self.class, opts[:with])
26
- true
27
- end
28
- end
29
-
30
- private
31
-
32
- def initialize(opts)
33
- super
34
- validate_modifiers if self.class.config[:validate_modifiers][:auto]
35
- end
36
- end
37
-
38
- module InstanceMethods
39
- end
40
- end
41
-
42
- register_plugin(ValidateModifiers.plugin_name, ValidateModifiers)
43
- end
44
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module Utils
5
- class AsJSON
6
- DOUBLE_QUOTE = '"'
7
-
8
- class << self
9
- def call(data, to_json:)
10
- case data
11
- when Hash
12
- data.each_with_object({}) do |(key, value), new_data|
13
- new_key = key.to_s
14
- new_value = call(value, to_json: to_json)
15
- new_data[new_key] = new_value
16
- end
17
- when Array
18
- data.map { |value| call(value, to_json: to_json) }
19
- when NilClass, Integer, Float, String, TrueClass, FalseClass
20
- data
21
- when Symbol
22
- data.to_s
23
- else
24
- res = to_json.call(data)
25
- if res.start_with?(DOUBLE_QUOTE) && res.end_with?(DOUBLE_QUOTE)
26
- res.delete_prefix!(DOUBLE_QUOTE)
27
- res.delete_suffix!(DOUBLE_QUOTE)
28
- end
29
- res
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module Utils
5
- class ToJSON
6
- class << self
7
- def call(data)
8
- json_adapter.dump(data)
9
- end
10
-
11
- private
12
-
13
- def json_adapter
14
- @json_adapter ||= begin
15
- require "json"
16
- ::JSON
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end