serega 0.42.0 → 0.50.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.
- checksums.yaml +4 -4
- data/README.md +124 -1207
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +186 -131
- data/lib/serega/attribute_normalizer.rb +164 -345
- data/lib/serega/attribute_normalizers/batch.rb +45 -0
- data/lib/serega/attribute_normalizers/block.rb +81 -0
- data/lib/serega/attribute_normalizers/delegate.rb +34 -0
- data/lib/serega/attribute_normalizers/hash_access.rb +37 -0
- data/lib/serega/attribute_normalizers/preloads.rb +46 -0
- data/lib/serega/attribute_value_resolvers/batch.rb +5 -54
- data/lib/serega/attribute_value_resolvers/const.rb +2 -24
- data/lib/serega/attribute_value_resolvers/delegate.rb +17 -28
- data/lib/serega/attribute_value_resolvers/hash_access.rb +34 -52
- data/lib/serega/attribute_value_resolvers/keyword.rb +10 -25
- data/lib/serega/attribute_values.rb +46 -0
- data/lib/serega/batch_loader.rb +37 -0
- data/lib/serega/conditions.rb +56 -0
- data/lib/serega/config.rb +105 -144
- data/lib/serega/engine/pulls.rb +64 -0
- data/lib/serega/engine/run.rb +106 -0
- data/lib/serega/errors.rb +36 -8
- data/lib/serega/formatter.rb +98 -0
- data/lib/serega/plan/cache.rb +96 -0
- data/lib/serega/plan/per_ractor_cache.rb +23 -0
- data/lib/serega/plan.rb +101 -128
- data/lib/serega/plan_point.rb +44 -151
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +13 -80
- data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +8 -75
- data/lib/serega/plugins/context_metadata/context_metadata.rb +40 -123
- data/lib/serega/plugins/metadata/check_params.rb +80 -0
- data/lib/serega/plugins/metadata/meta_attribute.rb +40 -79
- data/lib/serega/plugins/metadata/metadata.rb +40 -168
- data/lib/serega/plugins/root/root.rb +91 -235
- data/lib/serega/plugins.rb +16 -49
- data/lib/serega/presenter.rb +61 -19
- data/lib/serega/result_builder.rb +68 -0
- data/lib/serega/result_code.rb +203 -0
- data/lib/serega/shareable.rb +52 -0
- data/lib/serega/source_group.rb +187 -0
- data/lib/serega/utils/collection_detector.rb +19 -13
- data/lib/serega/utils/deep_merge.rb +26 -0
- data/lib/serega/utils/enum_deep_dup.rb +10 -16
- data/lib/serega/utils/enum_deep_freeze.rb +8 -14
- data/lib/serega/utils/method_signature.rb +6 -15
- data/lib/serega/utils/parse_string_modifiers.rb +63 -0
- data/lib/serega/utils/ractor_local.rb +36 -0
- data/lib/serega/utils/serialized_attribute_error.rb +60 -20
- data/lib/serega/utils/to_hash.rb +5 -26
- data/lib/serega/validations/attribute/check_block.rb +3 -15
- data/lib/serega/validations/attribute/check_name.rb +4 -15
- data/lib/serega/validations/attribute/check_opt_base_serializer.rb +3 -15
- data/lib/serega/validations/attribute/check_opt_batch.rb +26 -56
- data/lib/serega/validations/attribute/check_opt_condition.rb +55 -0
- data/lib/serega/validations/attribute/check_opt_delegate.rb +10 -63
- data/lib/serega/validations/attribute/check_opt_format.rb +36 -0
- data/lib/serega/validations/attribute/check_opt_hash_access.rb +11 -59
- data/lib/serega/validations/attribute/check_opt_hide.rb +3 -14
- data/lib/serega/validations/attribute/check_opt_many.rb +18 -20
- data/lib/serega/validations/attribute/check_opt_method.rb +3 -25
- data/lib/serega/validations/attribute/check_opt_preload.rb +3 -26
- data/lib/serega/validations/attribute/check_opt_serializer.rb +4 -18
- data/lib/serega/validations/attribute/check_opt_value.rb +3 -21
- data/lib/serega/validations/check_attribute_params.rb +92 -71
- data/lib/serega/validations/check_batch_loader_params.rb +43 -62
- data/lib/serega/validations/check_formatter.rb +80 -0
- data/lib/serega/validations/check_serialize_keywords.rb +23 -0
- data/lib/serega/validations/initiate/check_modifiers.rb +14 -20
- data/lib/serega/validations/utils/check_allowed_keys.rb +3 -13
- data/lib/serega/validations/utils/check_hash_access_value.rb +44 -0
- data/lib/serega/validations/utils/check_opt_is_bool.rb +3 -13
- data/lib/serega/validations/utils/check_opt_is_hash.rb +3 -13
- data/lib/serega/validations/utils/check_opt_is_string_or_symbol.rb +3 -13
- data/lib/serega/version.rb +1 -4
- data/lib/serega.rb +459 -388
- data/sig/serega/plugins.rbs +49 -0
- data/sig/serega.rbs +142 -0
- metadata +42 -38
- data/lib/serega/data_builder.rb +0 -54
- data/lib/serega/engine/level.rb +0 -59
- data/lib/serega/engine/level_queue.rb +0 -56
- data/lib/serega/engine/loader.rb +0 -70
- data/lib/serega/helpers/serializer_class_helper.rb +0 -19
- data/lib/serega/object_serializer.rb +0 -125
- data/lib/serega/plugins/camel_case/camel_case.rb +0 -213
- data/lib/serega/plugins/depth_limit/depth_limit.rb +0 -206
- data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +0 -69
- data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +0 -38
- data/lib/serega/plugins/formatters/formatters.rb +0 -322
- data/lib/serega/plugins/if/if.rb +0 -287
- data/lib/serega/plugins/if/validations/check_opt_if.rb +0 -72
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +0 -77
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +0 -72
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +0 -77
- data/lib/serega/plugins/metadata/validations/check_block.rb +0 -47
- data/lib/serega/plugins/metadata/validations/check_opt_const.rb +0 -39
- data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +0 -35
- data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +0 -35
- data/lib/serega/plugins/metadata/validations/check_opt_value.rb +0 -61
- data/lib/serega/plugins/metadata/validations/check_opts.rb +0 -59
- data/lib/serega/plugins/metadata/validations/check_path.rb +0 -50
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +0 -111
- data/lib/serega/plugins/string_modifiers/string_modifiers.rb +0 -63
- data/lib/serega/utils/symbol_name.rb +0 -39
- data/lib/serega/validations/attribute/check_opt_const.rb +0 -40
- data/lib/serega/validations/check_initiate_params.rb +0 -57
- data/lib/serega/validations/check_serialize_params.rb +0 -54
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module If
|
|
6
|
-
#
|
|
7
|
-
# Validator for attribute :if_value option
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class CheckOptIfValue
|
|
11
|
-
class << self
|
|
12
|
-
#
|
|
13
|
-
# Checks attribute :if_value option that must be [nil, Symbol, Proc, #call]
|
|
14
|
-
#
|
|
15
|
-
# @param opts [Hash] Attribute options
|
|
16
|
-
#
|
|
17
|
-
# @raise [SeregaError] Attribute validation error
|
|
18
|
-
#
|
|
19
|
-
# @return [void]
|
|
20
|
-
#
|
|
21
|
-
def call(opts)
|
|
22
|
-
return unless opts.key?(:if_value)
|
|
23
|
-
|
|
24
|
-
check_usage_with_other_params(opts)
|
|
25
|
-
check_type(opts[:if_value])
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def check_usage_with_other_params(opts)
|
|
31
|
-
raise SeregaError, "Option :if_value can not be used together with option :serializer" if opts.key?(:serializer)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def check_type(value)
|
|
35
|
-
return if value.is_a?(Symbol)
|
|
36
|
-
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
|
37
|
-
|
|
38
|
-
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
|
39
|
-
raise SeregaError, signature_error unless valid_signature?(signature)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def must_be_callable
|
|
43
|
-
"Invalid attribute option :if_value. It must be a Symbol, a Proc or respond to :call"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def valid_signature?(signature)
|
|
47
|
-
case signature
|
|
48
|
-
when "0" # no parameters
|
|
49
|
-
true
|
|
50
|
-
when "1" # (value)
|
|
51
|
-
true
|
|
52
|
-
when "2" # (value, context)
|
|
53
|
-
true
|
|
54
|
-
when "1_ctx" # (value, :ctx)
|
|
55
|
-
true
|
|
56
|
-
when "2_ctx" # (value, context, :ctx)
|
|
57
|
-
true
|
|
58
|
-
else
|
|
59
|
-
false
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def signature_error
|
|
64
|
-
<<~ERROR.strip
|
|
65
|
-
Invalid attribute option :if_value parameters, valid parameters signatures:
|
|
66
|
-
- () # no parameters
|
|
67
|
-
- (value) # one positional parameter
|
|
68
|
-
- (value, context) # two positional parameters
|
|
69
|
-
- (value, :ctx) # one positional parameter and :ctx keyword
|
|
70
|
-
- (value, context, :ctx) # two positional parameters and :ctx keyword
|
|
71
|
-
ERROR
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module If
|
|
6
|
-
#
|
|
7
|
-
# Validator for attribute :unless option
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class CheckOptUnless
|
|
11
|
-
class << self
|
|
12
|
-
#
|
|
13
|
-
# Checks attribute :unless option that must be [nil, Symbol, Proc, #call]
|
|
14
|
-
#
|
|
15
|
-
# @param opts [Hash] Attribute options
|
|
16
|
-
#
|
|
17
|
-
# @raise [SeregaError] Attribute validation error
|
|
18
|
-
#
|
|
19
|
-
# @return [void]
|
|
20
|
-
#
|
|
21
|
-
def call(opts)
|
|
22
|
-
return unless opts.key?(:unless)
|
|
23
|
-
|
|
24
|
-
check_type(opts[:unless])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def check_type(value)
|
|
30
|
-
return if value.is_a?(Symbol)
|
|
31
|
-
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
|
32
|
-
|
|
33
|
-
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
|
34
|
-
raise SeregaError, signature_error unless valid_signature?(signature)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def must_be_callable
|
|
38
|
-
"Invalid attribute option :unless. It must be a Symbol, a Proc or respond to :call"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def valid_signature?(signature)
|
|
42
|
-
case signature
|
|
43
|
-
when "0" # no parameters
|
|
44
|
-
true
|
|
45
|
-
when "1" # (object)
|
|
46
|
-
true
|
|
47
|
-
when "2" # (object, context)
|
|
48
|
-
true
|
|
49
|
-
when "1_ctx" # (object, :ctx)
|
|
50
|
-
true
|
|
51
|
-
when "2_ctx" # (object, context, :ctx)
|
|
52
|
-
true
|
|
53
|
-
else
|
|
54
|
-
false
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def signature_error
|
|
59
|
-
<<~ERROR.strip
|
|
60
|
-
Invalid attribute option :unless parameters, valid parameters signatures:
|
|
61
|
-
- () # no parameters
|
|
62
|
-
- (object) # one positional parameter
|
|
63
|
-
- (object, context) # two positional parameters
|
|
64
|
-
- (object, :ctx) # one positional parameter and :ctx keyword
|
|
65
|
-
- (object, context, :ctx) # two positional parameters and :ctx keyword
|
|
66
|
-
ERROR
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module If
|
|
6
|
-
#
|
|
7
|
-
# Validator for attribute :unless_value option
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class CheckOptUnlessValue
|
|
11
|
-
class << self
|
|
12
|
-
#
|
|
13
|
-
# Checks attribute :unless_value option that must be [nil, Symbol, Proc, #call]
|
|
14
|
-
#
|
|
15
|
-
# @param opts [Hash] Attribute options
|
|
16
|
-
#
|
|
17
|
-
# @raise [SeregaError] Attribute validation error
|
|
18
|
-
#
|
|
19
|
-
# @return [void]
|
|
20
|
-
#
|
|
21
|
-
def call(opts)
|
|
22
|
-
return unless opts.key?(:unless_value)
|
|
23
|
-
|
|
24
|
-
check_usage_with_other_params(opts)
|
|
25
|
-
check_type(opts[:unless_value])
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def check_usage_with_other_params(opts)
|
|
31
|
-
raise SeregaError, "Option :unless_value can not be used together with option :serializer" if opts.key?(:serializer)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def check_type(value)
|
|
35
|
-
return if value.is_a?(Symbol)
|
|
36
|
-
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
|
37
|
-
|
|
38
|
-
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
|
39
|
-
raise SeregaError, signature_error unless valid_signature?(signature)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def must_be_callable
|
|
43
|
-
"Invalid attribute option :unless_value. It must be a Symbol, a Proc or respond to :call"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def valid_signature?(signature)
|
|
47
|
-
case signature
|
|
48
|
-
when "0" # no parameters
|
|
49
|
-
true
|
|
50
|
-
when "1" # (value)
|
|
51
|
-
true
|
|
52
|
-
when "2" # (value, context)
|
|
53
|
-
true
|
|
54
|
-
when "1_ctx" # (value, :ctx)
|
|
55
|
-
true
|
|
56
|
-
when "2_ctx" # (value, context, :ctx)
|
|
57
|
-
true
|
|
58
|
-
else
|
|
59
|
-
false
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def signature_error
|
|
64
|
-
<<~ERROR.strip
|
|
65
|
-
Invalid attribute option :unless_value parameters, valid parameters signatures:
|
|
66
|
-
- () # no parameters
|
|
67
|
-
- (value) # one positional parameter
|
|
68
|
-
- (value, context) # two positional parameters
|
|
69
|
-
- (value, :ctx) # one positional parameter and :ctx keyword
|
|
70
|
-
- (value, context, :ctx) # two positional parameters and :ctx keyword
|
|
71
|
-
ERROR
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute block parameter
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckBlock
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Checks block provided with attribute
|
|
15
|
-
# Block must have up to two arguments - object(s) and context.
|
|
16
|
-
#
|
|
17
|
-
# @example without arguments
|
|
18
|
-
# metadata(:version) { CONSTANT_VERSION }
|
|
19
|
-
#
|
|
20
|
-
# @example with one argument
|
|
21
|
-
# metadata(:paging) { |scope| { { page: scope.page, per_page: scope.per_page, total_count: scope.total_count } }
|
|
22
|
-
#
|
|
23
|
-
# @example with two arguments
|
|
24
|
-
# metadata(:paging) { |scope, context| { { ... } if context[:pagy] }
|
|
25
|
-
#
|
|
26
|
-
# @param block [Proc] Block that returns serialized meta attribute value
|
|
27
|
-
#
|
|
28
|
-
# @raise [SeregaError] SeregaError that block has invalid arguments
|
|
29
|
-
#
|
|
30
|
-
# @return [void]
|
|
31
|
-
#
|
|
32
|
-
def call(block)
|
|
33
|
-
signature = SeregaUtils::MethodSignature.call(block, pos_limit: 2, keyword_args: [])
|
|
34
|
-
raise SeregaError, block_error unless %w[0 1 2].include?(signature)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def block_error
|
|
40
|
-
"Block can have maximum two parameters (object(s), context)"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# MetaAttribute `:const` option validator
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckOptConst
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Checks meta_attribute :const option
|
|
15
|
-
#
|
|
16
|
-
# @param opts [Hash] MetaAttribute options
|
|
17
|
-
#
|
|
18
|
-
# @raise [SeregaError] validation error
|
|
19
|
-
#
|
|
20
|
-
# @return [void]
|
|
21
|
-
#
|
|
22
|
-
def call(opts, block = nil)
|
|
23
|
-
return unless opts.key?(:const)
|
|
24
|
-
|
|
25
|
-
check_usage_with_other_params(opts, block)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def check_usage_with_other_params(opts, block)
|
|
31
|
-
raise SeregaError, "Option :const can not be used together with option :value" if opts.key?(:value)
|
|
32
|
-
raise SeregaError, "Option :const can not be used together with block" if block
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute :hide_empty option
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckOptHideEmpty
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Checks attribute :hide_empty option
|
|
15
|
-
#
|
|
16
|
-
# @param opts [Hash] Attribute options
|
|
17
|
-
#
|
|
18
|
-
# @raise [SeregaError] SeregaError that option has invalid value
|
|
19
|
-
#
|
|
20
|
-
# @return [void]
|
|
21
|
-
#
|
|
22
|
-
def call(opts)
|
|
23
|
-
return unless opts.key?(:hide_empty)
|
|
24
|
-
|
|
25
|
-
value = opts[:hide_empty]
|
|
26
|
-
return if value == true
|
|
27
|
-
|
|
28
|
-
raise SeregaError, "Invalid option :hide_empty => #{value.inspect}. Must be true"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute :hide_nil option
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckOptHideNil
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Checks attribute :hide_nil option
|
|
15
|
-
#
|
|
16
|
-
# @param opts [Hash] Attribute options
|
|
17
|
-
#
|
|
18
|
-
# @raise [SeregaError] SeregaError that option has invalid value
|
|
19
|
-
#
|
|
20
|
-
# @return [void]
|
|
21
|
-
#
|
|
22
|
-
def call(opts)
|
|
23
|
-
return unless opts.key?(:hide_nil)
|
|
24
|
-
|
|
25
|
-
value = opts[:hide_nil]
|
|
26
|
-
return if value == true
|
|
27
|
-
|
|
28
|
-
raise SeregaError, "Invalid option :hide_nil => #{value.inspect}. Must be true"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute :value option
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckOptValue
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Checks attribute :value option
|
|
15
|
-
#
|
|
16
|
-
# @param opts [Hash] Attribute options
|
|
17
|
-
#
|
|
18
|
-
# @raise [SeregaError] SeregaError that option has invalid value
|
|
19
|
-
#
|
|
20
|
-
# @return [void]
|
|
21
|
-
#
|
|
22
|
-
def call(opts, block = nil)
|
|
23
|
-
return unless opts.key?(:value)
|
|
24
|
-
|
|
25
|
-
check_usage_with_other_params(opts, block)
|
|
26
|
-
|
|
27
|
-
check_value(opts[:value])
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
def check_usage_with_other_params(opts, block)
|
|
33
|
-
raise SeregaError, "Option :value can not be used together with option :const" if opts.key?(:const)
|
|
34
|
-
raise SeregaError, "Option :value can not be used together with block" if block
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def check_value(value)
|
|
38
|
-
check_value_type(value)
|
|
39
|
-
|
|
40
|
-
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [])
|
|
41
|
-
|
|
42
|
-
raise SeregaError, params_count_error unless %w[0 1 2].include?(signature)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def check_value_type(value)
|
|
46
|
-
raise SeregaError, type_error if !value.is_a?(Proc) && !value.respond_to?(:call)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def type_error
|
|
50
|
-
"Option :value value must be a Proc or respond to #call"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def params_count_error
|
|
54
|
-
"Option :value value can have maximum 2 parameters (object(s), context)"
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute options
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckOpts
|
|
12
|
-
class << self
|
|
13
|
-
#
|
|
14
|
-
# Validates meta_attribute options
|
|
15
|
-
# Checks used options are allowed and then checks options values.
|
|
16
|
-
#
|
|
17
|
-
# @param opts [Hash] Attribute options
|
|
18
|
-
# @param block [Proc] Attribute block
|
|
19
|
-
# @param allowed_keys [Array<Symbol>] Allowed options keys
|
|
20
|
-
#
|
|
21
|
-
# @raise [SeregaError] when attribute has invalid options
|
|
22
|
-
#
|
|
23
|
-
# @return [void]
|
|
24
|
-
#
|
|
25
|
-
def call(opts, block, allowed_keys)
|
|
26
|
-
check_allowed_options_keys(opts, allowed_keys)
|
|
27
|
-
check_each_opt(opts, block)
|
|
28
|
-
check_any_value_provided(opts, block)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def check_allowed_options_keys(opts, allowed_keys)
|
|
34
|
-
opts.each_key do |key|
|
|
35
|
-
next if allowed_keys.include?(key.to_sym)
|
|
36
|
-
|
|
37
|
-
allowed = allowed_keys.map(&:inspect).join(", ")
|
|
38
|
-
raise SeregaError, "Invalid option #{key.inspect}. Allowed options are: #{allowed}"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def check_each_opt(opts, block)
|
|
43
|
-
CheckOptHideEmpty.call(opts)
|
|
44
|
-
CheckOptHideNil.call(opts)
|
|
45
|
-
CheckOptValue.call(opts, block)
|
|
46
|
-
CheckOptConst.call(opts, block)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def check_any_value_provided(opts, block)
|
|
50
|
-
return if opts.key?(:const) || opts.key?(:value) || block
|
|
51
|
-
|
|
52
|
-
raise SeregaError, "Please provide block argument or add :value or :const option"
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
module Metadata
|
|
6
|
-
class MetaAttribute
|
|
7
|
-
#
|
|
8
|
-
# Validator for meta_attribute :path parameter
|
|
9
|
-
#
|
|
10
|
-
# @private
|
|
11
|
-
class CheckPath
|
|
12
|
-
# Regexp for valid path
|
|
13
|
-
FORMAT = /\A[\w~-]+\z/
|
|
14
|
-
|
|
15
|
-
private_constant :FORMAT
|
|
16
|
-
|
|
17
|
-
class << self
|
|
18
|
-
#
|
|
19
|
-
# Checks allowed characters.
|
|
20
|
-
# Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~".
|
|
21
|
-
#
|
|
22
|
-
# @param path [Array<String, Symbol>] Metadata attribute path names
|
|
23
|
-
#
|
|
24
|
-
# @raise [SeregaError] when metadata attribute name has invalid format
|
|
25
|
-
# @return [void]
|
|
26
|
-
#
|
|
27
|
-
def call(path)
|
|
28
|
-
path.each { |attr_name| check_name(attr_name) }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def check_name(name)
|
|
34
|
-
name = name.to_s
|
|
35
|
-
|
|
36
|
-
raise SeregaError, message(name) unless FORMAT.match?(name)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def message(name)
|
|
40
|
-
<<~MESSAGE.tr("\n", "")
|
|
41
|
-
Invalid metadata path #{name.inspect}.
|
|
42
|
-
Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~"
|
|
43
|
-
MESSAGE
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
module SeregaPlugins
|
|
5
|
-
#
|
|
6
|
-
# Plugin :string_modifiers
|
|
7
|
-
#
|
|
8
|
-
# Allows to specify modifiers as strings.
|
|
9
|
-
#
|
|
10
|
-
# Serialized attributes must be split with `,` and nested attributes can be defined inside brackets `(`, `)`.
|
|
11
|
-
#
|
|
12
|
-
# @example
|
|
13
|
-
# PostSerializer.plugin :string_modifiers
|
|
14
|
-
# PostSerializer.new(only: "id,user(id,username)").to_h(post)
|
|
15
|
-
# PostSerializer.new(except: "user(username,email)").to_h(post)
|
|
16
|
-
# PostSerializer.new(with: "user(email)").to_h(post)
|
|
17
|
-
#
|
|
18
|
-
# # Modifiers can still be provided old way with nested hashes or arrays.
|
|
19
|
-
# PostSerializer.new(with: {user: %i[email, username]}).to_h(post)
|
|
20
|
-
#
|
|
21
|
-
module StringModifiers
|
|
22
|
-
#
|
|
23
|
-
# Modifiers parser
|
|
24
|
-
#
|
|
25
|
-
# @private
|
|
26
|
-
class ParseStringModifiers
|
|
27
|
-
COMMA = ","
|
|
28
|
-
COMMA_CODEPOINT = COMMA.ord
|
|
29
|
-
LPAREN = "("
|
|
30
|
-
LPAREN_CODEPOINT = LPAREN.ord
|
|
31
|
-
RPAREN = ")"
|
|
32
|
-
RPAREN_CODEPOINT = RPAREN.ord
|
|
33
|
-
private_constant :COMMA, :LPAREN, :RPAREN, :COMMA_CODEPOINT, :LPAREN_CODEPOINT, :RPAREN_CODEPOINT
|
|
34
|
-
|
|
35
|
-
class << self
|
|
36
|
-
#
|
|
37
|
-
# Parses string modifiers
|
|
38
|
-
#
|
|
39
|
-
# @param fields [String]
|
|
40
|
-
#
|
|
41
|
-
# @return [Hash] parsed modifiers in form of nested hash
|
|
42
|
-
#
|
|
43
|
-
# @example
|
|
44
|
-
# parse("user") => { user: {} }
|
|
45
|
-
# parse("user(id)") => { user: { id: {} } }
|
|
46
|
-
# parse("user(id,name)") => { user: { id: {}, name: {} } }
|
|
47
|
-
# parse("user,comments") => { user: {}, comments: {} }
|
|
48
|
-
# parse("user(comments(text))") => { user: { comments: { text: {} } } }
|
|
49
|
-
def parse(fields)
|
|
50
|
-
result = {}
|
|
51
|
-
attribute_storage = result
|
|
52
|
-
path_stack = (fields.include?(LPAREN) || fields.include?(RPAREN)) ? [] : nil
|
|
53
|
-
|
|
54
|
-
start_index = 0
|
|
55
|
-
end_index = 0
|
|
56
|
-
fields.each_codepoint do |codepoint|
|
|
57
|
-
case codepoint
|
|
58
|
-
when COMMA_CODEPOINT
|
|
59
|
-
attribute = extract_attribute(fields, start_index, end_index)
|
|
60
|
-
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
|
61
|
-
start_index = end_index + 1
|
|
62
|
-
when LPAREN_CODEPOINT
|
|
63
|
-
attribute = extract_attribute(fields, start_index, end_index)
|
|
64
|
-
if attribute
|
|
65
|
-
attribute_storage = add_attribute(attribute_storage, attribute, {})
|
|
66
|
-
path_stack.push(attribute)
|
|
67
|
-
end
|
|
68
|
-
start_index = end_index + 1
|
|
69
|
-
when RPAREN_CODEPOINT
|
|
70
|
-
attribute = extract_attribute(fields, start_index, end_index)
|
|
71
|
-
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
|
72
|
-
path_stack.pop
|
|
73
|
-
attribute_storage = dig?(result, path_stack)
|
|
74
|
-
start_index = end_index + 1
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
end_index += 1
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
attribute = extract_attribute(fields, start_index, end_index)
|
|
81
|
-
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
|
82
|
-
|
|
83
|
-
result
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
private
|
|
87
|
-
|
|
88
|
-
def extract_attribute(fields, start_index, end_index)
|
|
89
|
-
attribute = fields[start_index, end_index - start_index]
|
|
90
|
-
attribute.strip!
|
|
91
|
-
attribute.empty? ? nil : attribute.to_sym
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def add_attribute(storage, attribute, nested_attributes = FROZEN_EMPTY_HASH)
|
|
95
|
-
storage[attribute] = nested_attributes
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def dig?(hash, path)
|
|
99
|
-
return hash if !path || path.empty?
|
|
100
|
-
|
|
101
|
-
path.each do |point|
|
|
102
|
-
hash = hash[point]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
hash
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|