serega 0.40.0 → 0.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +21 -0
- data/README.md +90 -107
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +2 -0
- data/lib/serega/attribute_normalizer.rb +2 -0
- data/lib/serega/attribute_value_resolvers/batch.rb +3 -0
- data/lib/serega/attribute_value_resolvers/const.rb +3 -0
- data/lib/serega/attribute_value_resolvers/delegate.rb +4 -0
- data/lib/serega/attribute_value_resolvers/hash_access.rb +6 -0
- data/lib/serega/attribute_value_resolvers/keyword.rb +3 -0
- data/lib/serega/data_builder.rb +2 -0
- data/lib/serega/engine/level.rb +2 -0
- data/lib/serega/engine/level_queue.rb +2 -0
- data/lib/serega/engine/loader.rb +3 -0
- data/lib/serega/helpers/serializer_class_helper.rb +2 -0
- data/lib/serega/object_serializer.rb +2 -0
- data/lib/serega/plan.rb +3 -0
- data/lib/serega/plan_point.rb +2 -0
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +22 -16
- data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +6 -0
- data/lib/serega/plugins/camel_case/camel_case.rb +13 -13
- data/lib/serega/plugins/context_metadata/context_metadata.rb +8 -1
- data/lib/serega/plugins/depth_limit/depth_limit.rb +15 -12
- data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +12 -10
- data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +1 -0
- data/lib/serega/plugins/formatters/formatters.rb +18 -10
- data/lib/serega/plugins/if/if.rb +29 -32
- data/lib/serega/plugins/if/validations/check_opt_if.rb +1 -0
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +1 -0
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +1 -0
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +1 -0
- data/lib/serega/plugins/metadata/meta_attribute.rb +2 -0
- data/lib/serega/plugins/metadata/metadata.rb +14 -12
- data/lib/serega/plugins/metadata/validations/check_block.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_opt_const.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_opt_value.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_opts.rb +1 -0
- data/lib/serega/plugins/metadata/validations/check_path.rb +1 -0
- data/lib/serega/plugins/presenter/presenter.rb +10 -7
- data/lib/serega/plugins/root/root.rb +10 -6
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +1 -0
- data/lib/serega/plugins/string_modifiers/string_modifiers.rb +21 -0
- data/lib/serega/plugins.rb +2 -0
- data/lib/serega/utils/collection_detector.rb +2 -0
- data/lib/serega/utils/enum_deep_dup.rb +2 -0
- data/lib/serega/utils/enum_deep_freeze.rb +2 -0
- data/lib/serega/utils/method_signature.rb +2 -0
- data/lib/serega/utils/serialized_attribute_error.rb +2 -0
- data/lib/serega/utils/symbol_name.rb +2 -0
- data/lib/serega/utils/to_hash.rb +2 -0
- data/lib/serega/validations/attribute/check_block.rb +3 -0
- data/lib/serega/validations/attribute/check_name.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_base_serializer.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_batch.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_const.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_delegate.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_hash_access.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_hide.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_many.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_method.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_preload.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_serializer.rb +3 -0
- data/lib/serega/validations/attribute/check_opt_value.rb +3 -0
- data/lib/serega/validations/check_attribute_params.rb +3 -0
- data/lib/serega/validations/check_batch_loader_params.rb +3 -0
- data/lib/serega/validations/check_initiate_params.rb +3 -0
- data/lib/serega/validations/check_serialize_params.rb +3 -0
- data/lib/serega/validations/initiate/check_modifiers.rb +3 -0
- data/lib/serega/validations/utils/check_allowed_keys.rb +3 -0
- data/lib/serega/validations/utils/check_opt_is_bool.rb +3 -0
- data/lib/serega/validations/utils/check_opt_is_hash.rb +3 -0
- data/lib/serega/validations/utils/check_opt_is_string_or_symbol.rb +3 -0
- data/lib/serega.rb +6 -0
- metadata +13 -16
|
@@ -3,23 +3,20 @@
|
|
|
3
3
|
class Serega
|
|
4
4
|
module SeregaPlugins
|
|
5
5
|
#
|
|
6
|
-
# Plugin
|
|
6
|
+
# Plugin :metadata
|
|
7
7
|
#
|
|
8
8
|
# Depends on: `:root` plugin, that must be loaded first
|
|
9
9
|
#
|
|
10
|
-
# Adds
|
|
10
|
+
# Adds metadata to the serialized response via the class-level
|
|
11
|
+
# `meta_attribute` method, which accepts:
|
|
11
12
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# - `*path` [Array of Symbols] - nested hash keys.
|
|
13
|
+
# - `*path` [Array<Symbol>] - nested hash keys
|
|
15
14
|
# - `**options` [Hash]
|
|
16
|
-
#
|
|
17
|
-
# - `:
|
|
18
|
-
# - `:
|
|
19
|
-
# - `:
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# - `&block` [Proc] - describes value for current meta attribute
|
|
15
|
+
# - `:const` - a constant metadata value
|
|
16
|
+
# - `:value` - a `#callable` producing the metadata value
|
|
17
|
+
# - `:hide_nil` - hide the key if the value is nil (`false` by default)
|
|
18
|
+
# - `:hide_empty` - hide the key if the value is nil or empty (`false` by default)
|
|
19
|
+
# - `&block` - computes the value for this meta attribute
|
|
23
20
|
#
|
|
24
21
|
# @example
|
|
25
22
|
# class AppSerializer < Serega
|
|
@@ -39,6 +36,7 @@ class Serega
|
|
|
39
36
|
#
|
|
40
37
|
module Metadata
|
|
41
38
|
# @return [Symbol] Plugin name
|
|
39
|
+
# @private
|
|
42
40
|
def self.plugin_name
|
|
43
41
|
:metadata
|
|
44
42
|
end
|
|
@@ -50,6 +48,7 @@ class Serega
|
|
|
50
48
|
#
|
|
51
49
|
# @return [void]
|
|
52
50
|
#
|
|
51
|
+
# @private
|
|
53
52
|
def self.before_load_plugin(serializer_class, **_opts)
|
|
54
53
|
unless serializer_class.plugin_used?(:root)
|
|
55
54
|
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded after the :root plugin. Please load the :root plugin first"
|
|
@@ -64,6 +63,7 @@ class Serega
|
|
|
64
63
|
#
|
|
65
64
|
# @return [void]
|
|
66
65
|
#
|
|
66
|
+
# @private
|
|
67
67
|
def self.load_plugin(serializer_class, **_opts)
|
|
68
68
|
serializer_class.extend(ClassMethods)
|
|
69
69
|
serializer_class.include(InstanceMethods)
|
|
@@ -91,6 +91,7 @@ class Serega
|
|
|
91
91
|
#
|
|
92
92
|
# @return [void]
|
|
93
93
|
#
|
|
94
|
+
# @private
|
|
94
95
|
def self.after_load_plugin(serializer_class, **_opts)
|
|
95
96
|
serializer_class.config.opts[:metadata] = {attribute_keys: %i[const hide_nil hide_empty value]}
|
|
96
97
|
end
|
|
@@ -183,6 +184,7 @@ class Serega
|
|
|
183
184
|
#
|
|
184
185
|
# @see Serega
|
|
185
186
|
#
|
|
187
|
+
# @private
|
|
186
188
|
module InstanceMethods
|
|
187
189
|
private
|
|
188
190
|
|
|
@@ -15,12 +15,10 @@ class Serega
|
|
|
15
15
|
# - The original object is accessible via __getobj__ (standard SimpleDelegator API).
|
|
16
16
|
# - The serialization context is accessible via the private method __ctx__.
|
|
17
17
|
#
|
|
18
|
-
#
|
|
19
|
-
# class
|
|
20
|
-
# a bare `plugin :presenter` adds no wrapping overhead. The check is
|
|
21
|
-
# denormalized: `SerializerClass.custom_presenter?` is asked once per
|
|
22
|
-
# object serializer and the result is reused for the whole level.
|
|
18
|
+
# The `presenter do ... end` block is evaluated inside the serializer's own
|
|
19
|
+
# Presenter class, so multiple blocks accumulate.
|
|
23
20
|
#
|
|
21
|
+
# @example
|
|
24
22
|
# class UserSerializer < Serega
|
|
25
23
|
# plugin :presenter
|
|
26
24
|
#
|
|
@@ -38,10 +36,9 @@ class Serega
|
|
|
38
36
|
# end
|
|
39
37
|
# end
|
|
40
38
|
#
|
|
41
|
-
# The `presenter do ... end` block is evaluated inside the serializer's own
|
|
42
|
-
# Presenter class, so multiple blocks accumulate.
|
|
43
39
|
module Presenter
|
|
44
40
|
# @return [Symbol] Plugin name
|
|
41
|
+
# @private
|
|
45
42
|
def self.plugin_name
|
|
46
43
|
:presenter
|
|
47
44
|
end
|
|
@@ -54,6 +51,7 @@ class Serega
|
|
|
54
51
|
#
|
|
55
52
|
# @return [void]
|
|
56
53
|
#
|
|
54
|
+
# @private
|
|
57
55
|
def self.load_plugin(serializer_class, **_opts)
|
|
58
56
|
serializer_class.extend(ClassMethods)
|
|
59
57
|
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
|
@@ -67,6 +65,7 @@ class Serega
|
|
|
67
65
|
#
|
|
68
66
|
# @return [void]
|
|
69
67
|
#
|
|
68
|
+
# @private
|
|
70
69
|
def self.after_load_plugin(serializer_class, **_opts)
|
|
71
70
|
presenter_class = Class.new(Presenter)
|
|
72
71
|
presenter_class.serializer_class = serializer_class
|
|
@@ -79,8 +78,10 @@ class Serega
|
|
|
79
78
|
end
|
|
80
79
|
|
|
81
80
|
# Presenter class
|
|
81
|
+
# @private
|
|
82
82
|
class Presenter < SimpleDelegator
|
|
83
83
|
# Presenter instance methods
|
|
84
|
+
# @private
|
|
84
85
|
module InstanceMethods
|
|
85
86
|
#
|
|
86
87
|
# @param object [Object] Serialized object to wrap
|
|
@@ -187,6 +188,7 @@ class Serega
|
|
|
187
188
|
#
|
|
188
189
|
# @return [Boolean] whether custom presenter methods were defined
|
|
189
190
|
#
|
|
191
|
+
# @private
|
|
190
192
|
def custom_presenter?
|
|
191
193
|
self::Presenter.modified?
|
|
192
194
|
end
|
|
@@ -207,6 +209,7 @@ class Serega
|
|
|
207
209
|
#
|
|
208
210
|
# @see Serega::SeregaObjectSerializer
|
|
209
211
|
#
|
|
212
|
+
# @private
|
|
210
213
|
module SeregaObjectSerializerInstanceMethods
|
|
211
214
|
# The custom-presenter check is made once per object serializer here
|
|
212
215
|
# and its result is reused for every enqueued chunk of the level.
|
|
@@ -5,7 +5,7 @@ class Serega
|
|
|
5
5
|
#
|
|
6
6
|
# Plugin :root
|
|
7
7
|
#
|
|
8
|
-
#
|
|
8
|
+
# Adds a root key to serialized data.
|
|
9
9
|
#
|
|
10
10
|
# Accepts options:
|
|
11
11
|
# - :root - specifies root for all responses
|
|
@@ -16,14 +16,12 @@ class Serega
|
|
|
16
16
|
# - config.root.one
|
|
17
17
|
# - config.root.many
|
|
18
18
|
# - config.root.one=
|
|
19
|
-
# - config.
|
|
19
|
+
# - config.root.many=
|
|
20
20
|
#
|
|
21
21
|
# Default root is `:data`.
|
|
22
22
|
#
|
|
23
|
-
# Root also
|
|
24
|
-
#
|
|
25
|
-
# Also root can be removed for all responses by providing `root: nil`. In this case no root will be added to response, but
|
|
26
|
-
# you still can to add it per serialization
|
|
23
|
+
# Root can also be changed per serialization, or removed entirely by
|
|
24
|
+
# providing `root: nil` (per serialization it can still be added back).
|
|
27
25
|
#
|
|
28
26
|
# @example Define plugin
|
|
29
27
|
# class UserSerializer < Serega
|
|
@@ -56,6 +54,7 @@ class Serega
|
|
|
56
54
|
ROOT_DEFAULT = :data
|
|
57
55
|
|
|
58
56
|
# @return [Symbol] Plugin name
|
|
57
|
+
# @private
|
|
59
58
|
def self.plugin_name
|
|
60
59
|
:root
|
|
61
60
|
end
|
|
@@ -67,6 +66,7 @@ class Serega
|
|
|
67
66
|
#
|
|
68
67
|
# @return [void]
|
|
69
68
|
#
|
|
69
|
+
# @private
|
|
70
70
|
def self.before_load_plugin(serializer_class, **opts)
|
|
71
71
|
allowed_keys = %i[root root_one root_many]
|
|
72
72
|
opts.each_key do |key|
|
|
@@ -88,6 +88,7 @@ class Serega
|
|
|
88
88
|
#
|
|
89
89
|
# @return [void]
|
|
90
90
|
#
|
|
91
|
+
# @private
|
|
91
92
|
def self.load_plugin(serializer_class, **_opts)
|
|
92
93
|
serializer_class.extend(ClassMethods)
|
|
93
94
|
serializer_class.include(InstanceMethods)
|
|
@@ -103,6 +104,7 @@ class Serega
|
|
|
103
104
|
#
|
|
104
105
|
# @return [void]
|
|
105
106
|
#
|
|
107
|
+
# @private
|
|
106
108
|
def self.after_load_plugin(serializer_class, **opts)
|
|
107
109
|
config = serializer_class.config
|
|
108
110
|
default = opts.fetch(:root, ROOT_DEFAULT)
|
|
@@ -214,6 +216,7 @@ class Serega
|
|
|
214
216
|
#
|
|
215
217
|
# @see Serega
|
|
216
218
|
#
|
|
219
|
+
# @private
|
|
217
220
|
module InstanceMethods
|
|
218
221
|
#
|
|
219
222
|
# Serializes provided object to a tree of Ruby Data objects.
|
|
@@ -261,6 +264,7 @@ class Serega
|
|
|
261
264
|
#
|
|
262
265
|
# @see Serega::SeregaDataBuilder
|
|
263
266
|
#
|
|
267
|
+
# @private
|
|
264
268
|
module DataBuilderClassMethods
|
|
265
269
|
#
|
|
266
270
|
# @param serializer [Serega] Serializer instance carrying the plan
|
|
@@ -2,8 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
4
|
module SeregaPlugins
|
|
5
|
+
#
|
|
6
|
+
# Plugin :string_modifiers
|
|
7
|
+
#
|
|
8
|
+
# Allows `:only`, `:except` and `:with` to be given as a single comma-separated
|
|
9
|
+
# string, with nested attributes in parentheses. Useful for accepting a field
|
|
10
|
+
# list straight from a query parameter.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# class UserSerializer < Serega
|
|
14
|
+
# plugin :string_modifiers
|
|
15
|
+
#
|
|
16
|
+
# attribute :username
|
|
17
|
+
# attribute :first_name
|
|
18
|
+
# attribute :addresses, serializer: AddressSerializer, hide: true
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# UserSerializer.to_h(user, only: "username,addresses(line1,line2)")
|
|
22
|
+
#
|
|
5
23
|
module StringModifiers
|
|
6
24
|
# @return [Symbol] Plugin name
|
|
25
|
+
# @private
|
|
7
26
|
def self.plugin_name
|
|
8
27
|
:string_modifiers
|
|
9
28
|
end
|
|
@@ -16,6 +35,7 @@ class Serega
|
|
|
16
35
|
#
|
|
17
36
|
# @return [void]
|
|
18
37
|
#
|
|
38
|
+
# @private
|
|
19
39
|
def self.load_plugin(serializer_class, **_opts)
|
|
20
40
|
serializer_class.include(InstanceMethods)
|
|
21
41
|
require_relative "parse_string_modifiers"
|
|
@@ -26,6 +46,7 @@ class Serega
|
|
|
26
46
|
#
|
|
27
47
|
# @see Serega
|
|
28
48
|
#
|
|
49
|
+
# @private
|
|
29
50
|
module InstanceMethods
|
|
30
51
|
private
|
|
31
52
|
|
data/lib/serega/plugins.rb
CHANGED
|
@@ -17,6 +17,7 @@ class Serega
|
|
|
17
17
|
#
|
|
18
18
|
# @return [void]
|
|
19
19
|
#
|
|
20
|
+
# @private
|
|
20
21
|
def register_plugin(name, mod)
|
|
21
22
|
@plugins[name] = mod
|
|
22
23
|
end
|
|
@@ -36,6 +37,7 @@ class Serega
|
|
|
36
37
|
#
|
|
37
38
|
# @return [Class<Module>] Plugin core module
|
|
38
39
|
#
|
|
40
|
+
# @private
|
|
39
41
|
def find_plugin(name)
|
|
40
42
|
return name if name.is_a?(Module)
|
|
41
43
|
return @plugins[name] if @plugins.key?(name)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
|
+
# @private
|
|
4
5
|
module SeregaUtils
|
|
5
6
|
#
|
|
6
7
|
# Utility to check if an object should be serialized as a collection.
|
|
@@ -8,6 +9,7 @@ class Serega
|
|
|
8
9
|
# Hashes and Structs are Enumerable, but enumerate their own member
|
|
9
10
|
# values, so they are treated as single objects.
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
class CollectionDetector
|
|
12
14
|
class << self
|
|
13
15
|
#
|
|
@@ -4,10 +4,12 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Utilities
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaUtils
|
|
8
9
|
#
|
|
9
10
|
# Utility to make method arguments signature
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
class MethodSignature
|
|
12
14
|
SYMBOL_TO_PROC_SIGNATURE_RUBY2 = [[:rest]]
|
|
13
15
|
SYMBOL_TO_PROC_SIGNATURE_RUBY3 = [[:req], [:rest]]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
|
+
# @private
|
|
4
5
|
module SeregaUtils
|
|
5
6
|
#
|
|
6
7
|
# Reraises an error, adding which attribute and serializer were being
|
|
@@ -8,6 +9,7 @@ class Serega
|
|
|
8
9
|
# and the batch attach phase so the message stays identical for every
|
|
9
10
|
# attribute, whether its value is resolved inline or during batch loading.
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
module SerializedAttributeError
|
|
12
14
|
module_function
|
|
13
15
|
|
data/lib/serega/utils/to_hash.rb
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
|
+
# @private
|
|
4
5
|
module SeregaValidations
|
|
5
6
|
#
|
|
6
7
|
# Attribute parameters validators
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
module Attribute
|
|
9
11
|
#
|
|
10
12
|
# Attribute `block` parameter validator
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
class CheckBlock
|
|
13
16
|
# Explains the changed attribute block behavior. Shown when the block
|
|
14
17
|
# looks like an old-style value block — it accepts parameters or
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
|
+
# @private
|
|
4
5
|
module SeregaValidations
|
|
6
|
+
# @private
|
|
5
7
|
module Attribute
|
|
6
8
|
#
|
|
7
9
|
# Attribute `name` parameter validator
|
|
8
10
|
#
|
|
11
|
+
# @private
|
|
9
12
|
class CheckName
|
|
10
13
|
# Regexp for valid attribute name
|
|
11
14
|
FORMAT = /\A[\w~-]+\z/
|