serega 0.1.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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