serega 0.21.0 → 0.30.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 +113 -229
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +31 -3
- data/lib/serega/attribute_normalizer.rb +143 -42
- data/lib/serega/batch/attribute_loader.rb +70 -0
- data/lib/serega/batch/attribute_loaders.rb +59 -0
- data/lib/serega/batch/auto_resolver.rb +24 -0
- data/lib/serega/batch/auto_resolver_factory.rb +48 -0
- data/lib/serega/batch/loader.rb +67 -0
- data/lib/serega/config.rb +59 -1
- data/lib/serega/object_serializer.rb +11 -9
- data/lib/serega/plan.rb +16 -0
- data/lib/serega/plan_point.rb +31 -5
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +25 -13
- data/lib/serega/plugins/activerecord_preloads/lib/active_record_objects.rb +31 -0
- data/lib/serega/plugins/camel_case/camel_case.rb +1 -1
- data/lib/serega/plugins/formatters/formatters.rb +79 -22
- data/lib/serega/plugins/if/if.rb +41 -22
- data/lib/serega/plugins/if/validations/check_opt_if.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +27 -6
- data/lib/serega/plugins/metadata/meta_attribute.rb +9 -10
- data/lib/serega/plugins/metadata/validations/check_block.rb +2 -4
- data/lib/serega/plugins/metadata/validations/check_opt_value.rb +2 -3
- data/lib/serega/plugins/presenter/presenter.rb +1 -1
- data/lib/serega/utils/format_user_preloads.rb +58 -0
- data/lib/serega/utils/method_signature.rb +89 -0
- data/lib/serega/utils/preload_paths.rb +53 -0
- data/lib/serega/utils/preloads_constructor.rb +77 -0
- data/lib/serega/validations/attribute/check_block.rb +38 -6
- data/lib/serega/validations/attribute/check_opt_batch.rb +101 -0
- data/lib/serega/validations/attribute/check_opt_const.rb +1 -0
- data/lib/serega/validations/attribute/check_opt_delegate.rb +1 -0
- data/lib/serega/validations/attribute/check_opt_method.rb +1 -0
- data/lib/serega/{plugins/preloads/validations → validations/attribute}/check_opt_preload.rb +2 -2
- data/lib/serega/{plugins/preloads/validations → validations/attribute}/check_opt_preload_path.rb +3 -3
- data/lib/serega/validations/attribute/check_opt_value.rb +35 -9
- data/lib/serega/validations/check_attribute_params.rb +3 -2
- data/lib/serega/validations/check_batch_loader_params.rb +80 -0
- data/lib/serega/validations/initiate/check_modifiers.rb +1 -1
- data/lib/serega.rb +98 -7
- metadata +17 -37
- data/lib/serega/plugins/batch/batch.rb +0 -168
- data/lib/serega/plugins/batch/lib/batch_config.rb +0 -77
- data/lib/serega/plugins/batch/lib/loader.rb +0 -113
- data/lib/serega/plugins/batch/lib/loaders.rb +0 -45
- data/lib/serega/plugins/batch/lib/modules/attribute.rb +0 -26
- data/lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb +0 -78
- data/lib/serega/plugins/batch/lib/modules/check_attribute_params.rb +0 -22
- data/lib/serega/plugins/batch/lib/modules/config.rb +0 -23
- data/lib/serega/plugins/batch/lib/modules/object_serializer.rb +0 -46
- data/lib/serega/plugins/batch/lib/modules/plan_point.rb +0 -22
- data/lib/serega/plugins/batch/lib/plugins_extensions/activerecord_preloads.rb +0 -43
- data/lib/serega/plugins/batch/lib/plugins_extensions/formatters.rb +0 -54
- data/lib/serega/plugins/batch/lib/plugins_extensions/if.rb +0 -31
- data/lib/serega/plugins/batch/lib/plugins_extensions/preloads.rb +0 -34
- data/lib/serega/plugins/batch/lib/validations/check_batch_opt_id_method.rb +0 -43
- data/lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb +0 -59
- data/lib/serega/plugins/batch/lib/validations/check_opt_batch.rb +0 -62
- data/lib/serega/plugins/preloads/lib/format_user_preloads.rb +0 -60
- data/lib/serega/plugins/preloads/lib/modules/attribute.rb +0 -28
- data/lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb +0 -99
- data/lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb +0 -22
- data/lib/serega/plugins/preloads/lib/modules/config.rb +0 -19
- data/lib/serega/plugins/preloads/lib/modules/plan_point.rb +0 -41
- data/lib/serega/plugins/preloads/lib/preload_paths.rb +0 -53
- data/lib/serega/plugins/preloads/lib/preloads_config.rb +0 -62
- data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +0 -79
- data/lib/serega/plugins/preloads/preloads.rb +0 -162
- data/lib/serega/utils/params_count.rb +0 -50
- data/lib/serega/validations/utils/check_extra_keyword_arg.rb +0 -33
data/lib/serega/plan_point.rb
CHANGED
@@ -25,6 +25,14 @@ class Serega
|
|
25
25
|
# @return [Hash] Attributes to serialize
|
26
26
|
attr_reader :modifiers
|
27
27
|
|
28
|
+
# Shows preloads for nested attributes
|
29
|
+
# @return [Hash] preloads for nested attributes
|
30
|
+
attr_reader :preloads
|
31
|
+
|
32
|
+
# Shows preloads_path for current attribute
|
33
|
+
# @return [Array<Symbol>, nil] preloads path for current attribute
|
34
|
+
attr_reader :preloads_path
|
35
|
+
|
28
36
|
#
|
29
37
|
# Initializes plan point
|
30
38
|
#
|
@@ -46,8 +54,8 @@ class Serega
|
|
46
54
|
|
47
55
|
# Attribute `value`
|
48
56
|
# @see SeregaAttribute::AttributeInstanceMethods#value
|
49
|
-
def value(obj, ctx)
|
50
|
-
attribute.value(obj, ctx)
|
57
|
+
def value(obj, ctx, batches: nil)
|
58
|
+
attribute.value(obj, ctx, batches: batches)
|
51
59
|
end
|
52
60
|
|
53
61
|
# Attribute `name`
|
@@ -68,6 +76,16 @@ class Serega
|
|
68
76
|
attribute.serializer
|
69
77
|
end
|
70
78
|
|
79
|
+
def batch?
|
80
|
+
!attribute.batch_loaders.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
# Attribute `batch_loaders`
|
84
|
+
# @see SeregaAttribute::AttributeInstanceMethods#batch_loaders
|
85
|
+
def batch_loaders
|
86
|
+
attribute.batch_loaders
|
87
|
+
end
|
88
|
+
|
71
89
|
#
|
72
90
|
# @return [SeregaObjectSerializer] object serializer for child plan
|
73
91
|
#
|
@@ -77,11 +95,11 @@ class Serega
|
|
77
95
|
|
78
96
|
private
|
79
97
|
|
80
|
-
# Patched in:
|
81
|
-
# - plugin :batch (prepares @batch)
|
82
|
-
# - plugin :preloads (prepares @preloads and @preloads_path)
|
83
98
|
def set_normalized_vars
|
84
99
|
@child_plan = prepare_child_plan
|
100
|
+
@preloads = prepare_preloads
|
101
|
+
@preloads_path = prepare_preloads_path
|
102
|
+
plan.mark_as_has_batch_points if batch?
|
85
103
|
end
|
86
104
|
|
87
105
|
def prepare_child_plan
|
@@ -91,6 +109,14 @@ class Serega
|
|
91
109
|
|
92
110
|
serializer::SeregaPlan.new(self, fields)
|
93
111
|
end
|
112
|
+
|
113
|
+
def prepare_preloads
|
114
|
+
SeregaUtils::PreloadsConstructor.call(child_plan)
|
115
|
+
end
|
116
|
+
|
117
|
+
def prepare_preloads_path
|
118
|
+
attribute.preloads_path
|
119
|
+
end
|
94
120
|
end
|
95
121
|
|
96
122
|
extend SeregaHelpers::SerializerClassHelper
|
@@ -4,7 +4,6 @@ class Serega
|
|
4
4
|
module SeregaPlugins
|
5
5
|
#
|
6
6
|
# Plugin :activerecord_preloads
|
7
|
-
# (depends on :preloads plugin, that must be loaded first)
|
8
7
|
#
|
9
8
|
# Automatically preloads associations to serialized objects
|
10
9
|
#
|
@@ -14,10 +13,9 @@ class Serega
|
|
14
13
|
#
|
15
14
|
# @example
|
16
15
|
# class AppSerializer < Serega
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# auto_hide_attributes_with_preload: true
|
16
|
+
# config.auto_preload_attributes_with_delegate = true
|
17
|
+
# config.auto_preload_attributes_with_serializer = true
|
18
|
+
# config.auto_hide_attributes_with_preload = true
|
21
19
|
#
|
22
20
|
# plugin :activerecord_preloads
|
23
21
|
# end
|
@@ -62,14 +60,6 @@ class Serega
|
|
62
60
|
opts.each_key do |key|
|
63
61
|
raise SeregaError, "Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. No options are allowed"
|
64
62
|
end
|
65
|
-
|
66
|
-
unless serializer_class.plugin_used?(:preloads)
|
67
|
-
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded after the :preloads plugin. Please load the :preloads plugin first"
|
68
|
-
end
|
69
|
-
|
70
|
-
if serializer_class.plugin_used?(:batch)
|
71
|
-
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded before the :batch plugin"
|
72
|
-
end
|
73
63
|
end
|
74
64
|
|
75
65
|
#
|
@@ -82,8 +72,30 @@ class Serega
|
|
82
72
|
#
|
83
73
|
def self.load_plugin(serializer_class, **_opts)
|
84
74
|
require_relative "lib/preloader"
|
75
|
+
require_relative "lib/active_record_objects"
|
85
76
|
|
86
77
|
serializer_class.include(InstanceMethods)
|
78
|
+
serializer_class::SeregaBatchAttributeLoader.include(BatchAttributeLoaderInstanceMethods)
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Overrides SeregaBatch::AttributeLoader class instance methods
|
83
|
+
#
|
84
|
+
module BatchAttributeLoaderInstanceMethods
|
85
|
+
private
|
86
|
+
|
87
|
+
# Preloads associations to batch-generated data
|
88
|
+
def load_one(serializer_class, batch_loader_name, context)
|
89
|
+
batch_loaded_data = super
|
90
|
+
|
91
|
+
preloads = point.preloads
|
92
|
+
return batch_loaded_data if preloads.empty?
|
93
|
+
|
94
|
+
ar_objects = ActiveRecordObjects.call(batch_loaded_data)
|
95
|
+
Preloader.preload(ar_objects, preloads)
|
96
|
+
|
97
|
+
batch_loaded_data
|
98
|
+
end
|
87
99
|
end
|
88
100
|
|
89
101
|
#
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module ActiverecordPreloads
|
6
|
+
# Detects and returns found ActiveRecord objects
|
7
|
+
class ActiveRecordObjects
|
8
|
+
class << self
|
9
|
+
# Iterates over provided data and selects ActiveRecord objects
|
10
|
+
# @param data [Hash,Array,Object] any data
|
11
|
+
# @return [Array] Found ActiveRecord objects
|
12
|
+
def call(data)
|
13
|
+
res = []
|
14
|
+
extract(data, res)
|
15
|
+
res
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def extract(data, res)
|
21
|
+
case data
|
22
|
+
when ActiveRecord::Base then res << data
|
23
|
+
when Array then data.each { |value| extract(value, res) }
|
24
|
+
when Hash then data.each_value { |value| extract(value, res) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -203,7 +203,7 @@ class Serega
|
|
203
203
|
res = super
|
204
204
|
return res if init_opts[:camel_case] == false
|
205
205
|
|
206
|
-
self.class.serializer_class.config.camel_case.transform.call(res.to_s).to_sym
|
206
|
+
self.class.serializer_class.config.camel_case.transform.call(+res.to_s).to_sym
|
207
207
|
end
|
208
208
|
end
|
209
209
|
end
|
@@ -64,10 +64,6 @@ class Serega
|
|
64
64
|
"Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. Allowed options:\n" \
|
65
65
|
" - :formatters [Hash<Symbol, #call>] - Formatters (names and according callable values)"
|
66
66
|
end
|
67
|
-
|
68
|
-
if serializer_class.plugin_used?(:batch)
|
69
|
-
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded before the :batch plugin"
|
70
|
-
end
|
71
67
|
end
|
72
68
|
|
73
69
|
#
|
@@ -81,6 +77,7 @@ class Serega
|
|
81
77
|
def self.load_plugin(serializer_class, **_opts)
|
82
78
|
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
83
79
|
serializer_class::SeregaAttributeNormalizer.include(AttributeNormalizerInstanceMethods)
|
80
|
+
serializer_class::SeregaAttribute.include(AttributeInstanceMethods)
|
84
81
|
serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
|
85
82
|
end
|
86
83
|
|
@@ -155,7 +152,7 @@ class Serega
|
|
155
152
|
end
|
156
153
|
|
157
154
|
#
|
158
|
-
#
|
155
|
+
# AttributeNormalizer class additional/patched instance methods
|
159
156
|
#
|
160
157
|
# @see SeregaAttributeNormalizer
|
161
158
|
#
|
@@ -163,29 +160,69 @@ class Serega
|
|
163
160
|
# Block or callable instance that will format attribute values
|
164
161
|
# @return [Proc, #call, nil] Block or callable instance that will format attribute values
|
165
162
|
def formatter
|
166
|
-
|
163
|
+
@formatter ||= prepare_formatter
|
164
|
+
end
|
167
165
|
|
168
|
-
|
166
|
+
#
|
167
|
+
# Returns formatter method signature for optimized calling
|
168
|
+
#
|
169
|
+
# @return [String, nil] Formatter signature ("1", "2", "1_ctx") or nil if no formatter
|
170
|
+
#
|
171
|
+
def formatter_signature
|
172
|
+
@formatter_signature ||= prepare_formatter_signature
|
169
173
|
end
|
170
174
|
|
171
175
|
private
|
172
176
|
|
173
|
-
def prepare_value_block
|
174
|
-
return super unless formatter
|
175
|
-
|
176
|
-
# Wrap original block into formatter block
|
177
|
-
proc do |object, context|
|
178
|
-
value = super.call(object, context)
|
179
|
-
formatter.call(value, context)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
177
|
def prepare_formatter
|
184
178
|
formatter = init_opts[:format]
|
185
179
|
return unless formatter
|
186
180
|
|
187
181
|
formatter = self.class.serializer_class.config.formatters.opts.fetch(formatter) if formatter.is_a?(Symbol)
|
188
|
-
|
182
|
+
formatter
|
183
|
+
end
|
184
|
+
|
185
|
+
def prepare_formatter_signature
|
186
|
+
return unless formatter
|
187
|
+
|
188
|
+
SeregaUtils::MethodSignature.call(formatter, pos_limit: 2, keyword_args: [:ctx])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Attribute class additional/patched instance methods
|
194
|
+
#
|
195
|
+
# @see SeregaAttribute
|
196
|
+
#
|
197
|
+
module AttributeInstanceMethods
|
198
|
+
#
|
199
|
+
# Returns formatted attribute value
|
200
|
+
#
|
201
|
+
# @param object [Object] Serialized object
|
202
|
+
# @param context [Hash] Serialization context
|
203
|
+
#
|
204
|
+
# @return [Object] Formatted attribute value
|
205
|
+
#
|
206
|
+
def value(object, context, batches: nil)
|
207
|
+
result = super # `:batches` parameter is needed to find unformatted result
|
208
|
+
return result unless formatter
|
209
|
+
|
210
|
+
case formatter_signature
|
211
|
+
when "1" then formatter.call(result)
|
212
|
+
when "1_ctx" then formatter.call(result, ctx: context)
|
213
|
+
else # "2"
|
214
|
+
formatter.call(result, context)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
attr_reader :formatter, :formatter_signature
|
221
|
+
|
222
|
+
def set_normalized_vars(normalizer)
|
223
|
+
super
|
224
|
+
@formatter = normalizer.formatter
|
225
|
+
@formatter_signature = normalizer.formatter_signature
|
189
226
|
end
|
190
227
|
end
|
191
228
|
|
@@ -241,13 +278,33 @@ class Serega
|
|
241
278
|
def call(formatter_name, formatter)
|
242
279
|
raise Serega::SeregaError, "Option #{formatter_name.inspect} must have callable value" unless formatter.respond_to?(:call)
|
243
280
|
|
244
|
-
|
245
|
-
|
281
|
+
signature = SeregaUtils::MethodSignature.call(formatter, pos_limit: 2, keyword_args: [:ctx])
|
282
|
+
raise SeregaError, signature_error unless valid_signature?(signature)
|
283
|
+
end
|
284
|
+
|
285
|
+
private
|
246
286
|
|
247
|
-
|
248
|
-
|
287
|
+
def valid_signature?(signature)
|
288
|
+
case signature
|
289
|
+
when "1" # (object)
|
290
|
+
true
|
291
|
+
when "2" # (object, context)
|
292
|
+
true
|
293
|
+
when "1_ctx" # (object, :ctx)
|
294
|
+
true
|
295
|
+
else
|
296
|
+
false
|
249
297
|
end
|
250
298
|
end
|
299
|
+
|
300
|
+
def signature_error
|
301
|
+
<<~ERROR.strip
|
302
|
+
Invalid formatter parameters, valid parameters signatures:
|
303
|
+
- (object) # one positional parameter
|
304
|
+
- (object, context) # two positional parameters
|
305
|
+
- (object, :ctx) # one positional parameter and :ctx keyword
|
306
|
+
ERROR
|
307
|
+
end
|
251
308
|
end
|
252
309
|
end
|
253
310
|
end
|
data/lib/serega/plugins/if/if.rb
CHANGED
@@ -50,19 +50,6 @@ class Serega
|
|
50
50
|
:if
|
51
51
|
end
|
52
52
|
|
53
|
-
# Checks requirements to load plugin
|
54
|
-
#
|
55
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
56
|
-
# @param opts [Hash] plugin options
|
57
|
-
#
|
58
|
-
# @return [void]
|
59
|
-
#
|
60
|
-
def self.before_load_plugin(serializer_class, **opts)
|
61
|
-
if serializer_class.plugin_used?(:batch)
|
62
|
-
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded before the :batch plugin"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
53
|
#
|
67
54
|
# Applies plugin code to specific serializer
|
68
55
|
#
|
@@ -116,18 +103,34 @@ class Serega
|
|
116
103
|
}.freeze
|
117
104
|
end
|
118
105
|
|
106
|
+
#
|
107
|
+
# Returns method signatures for all if options for optimized calling
|
108
|
+
#
|
109
|
+
# @return [Hash] Hash with signatures for each if option type
|
110
|
+
#
|
111
|
+
def if_options_signatures
|
112
|
+
@if_options_signatures ||= {
|
113
|
+
if: if_option_signature(:if),
|
114
|
+
unless: if_option_signature(:unless),
|
115
|
+
if_value: if_option_signature(:if_value),
|
116
|
+
unless_value: if_option_signature(:unless_value)
|
117
|
+
}.freeze
|
118
|
+
end
|
119
|
+
|
119
120
|
private
|
120
121
|
|
122
|
+
def if_option_signature(option_name)
|
123
|
+
callable = if_options[option_name]
|
124
|
+
return unless callable
|
125
|
+
|
126
|
+
SeregaUtils::MethodSignature.call(callable, pos_limit: 2, keyword_args: [:ctx])
|
127
|
+
end
|
128
|
+
|
121
129
|
def prepare_if_option(if_option)
|
122
130
|
return unless if_option
|
123
131
|
return proc { |val| val.public_send(if_option) } if if_option.is_a?(Symbol)
|
124
132
|
|
125
|
-
|
126
|
-
case params_count
|
127
|
-
when 0 then proc { if_option.call }
|
128
|
-
when 1 then proc { |obj| if_option.call(obj) }
|
129
|
-
else if_option
|
130
|
-
end
|
133
|
+
if_option
|
131
134
|
end
|
132
135
|
end
|
133
136
|
|
@@ -137,14 +140,18 @@ class Serega
|
|
137
140
|
# @see Serega::SeregaAttribute
|
138
141
|
#
|
139
142
|
module AttributeInstanceMethods
|
140
|
-
# @return provided :if options
|
143
|
+
# @return [Hash] provided :if options
|
141
144
|
attr_reader :opt_if
|
142
145
|
|
146
|
+
# @return [Hash] signatures for provided :if options
|
147
|
+
attr_reader :opt_if_signatures
|
148
|
+
|
143
149
|
private
|
144
150
|
|
145
151
|
def set_normalized_vars(normalizer)
|
146
152
|
super
|
147
153
|
@opt_if = normalizer.if_options
|
154
|
+
@opt_if_signatures = normalizer.if_options_signatures
|
148
155
|
end
|
149
156
|
end
|
150
157
|
|
@@ -177,10 +184,22 @@ class Serega
|
|
177
184
|
opt_unless = attribute.opt_if[opt_unless_name]
|
178
185
|
return true if opt_if.nil? && opt_unless.nil?
|
179
186
|
|
180
|
-
res_if = opt_if ? opt_if
|
181
|
-
res_unless = opt_unless ? !opt_unless
|
187
|
+
res_if = opt_if ? check_condition(opt_if, opt_if_name, obj, ctx) : true
|
188
|
+
res_unless = opt_unless ? !check_condition(opt_unless, opt_unless_name, obj, ctx) : true
|
182
189
|
res_if && res_unless
|
183
190
|
end
|
191
|
+
|
192
|
+
def check_condition(condition, condition_name, object, context)
|
193
|
+
signature = attribute.opt_if_signatures[condition_name]
|
194
|
+
|
195
|
+
case signature
|
196
|
+
when "1" then condition.call(object)
|
197
|
+
when "2" then condition.call(object, context)
|
198
|
+
when "1_ctx" then condition.call(object, ctx: context)
|
199
|
+
else # "0"
|
200
|
+
condition.call
|
201
|
+
end
|
202
|
+
end
|
184
203
|
end
|
185
204
|
|
186
205
|
#
|
@@ -29,17 +29,38 @@ class Serega
|
|
29
29
|
return if value.is_a?(Symbol)
|
30
30
|
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if params_count > 2
|
36
|
-
raise SeregaError, "Option :if value should have up to 2 parameters (object, context)"
|
37
|
-
end
|
32
|
+
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
33
|
+
raise SeregaError, signature_error unless valid_signature?(signature)
|
38
34
|
end
|
39
35
|
|
40
36
|
def must_be_callable
|
41
37
|
"Invalid attribute option :if. It must be a Symbol, a Proc or respond to :call"
|
42
38
|
end
|
39
|
+
|
40
|
+
def valid_signature?(signature)
|
41
|
+
case signature
|
42
|
+
when "0" # no parameters
|
43
|
+
true
|
44
|
+
when "1" # (object)
|
45
|
+
true
|
46
|
+
when "2" # (object, context)
|
47
|
+
true
|
48
|
+
when "1_ctx" # (object, :ctx)
|
49
|
+
true
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def signature_error
|
56
|
+
<<~ERROR.strip
|
57
|
+
Invalid attribute option :if parameters, valid parameters signatures:
|
58
|
+
- () # no parameters
|
59
|
+
- (object) # one positional parameter
|
60
|
+
- (object, context) # two positional parameters
|
61
|
+
- (object, :ctx) # one positional parameter and :ctx keyword
|
62
|
+
ERROR
|
63
|
+
end
|
43
64
|
end
|
44
65
|
end
|
45
66
|
end
|
@@ -34,17 +34,38 @@ class Serega
|
|
34
34
|
return if value.is_a?(Symbol)
|
35
35
|
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if params_count > 2
|
41
|
-
raise SeregaError, "Option :if_value value should have up to 2 parameters (value, context)"
|
42
|
-
end
|
37
|
+
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
38
|
+
raise SeregaError, signature_error unless valid_signature?(signature)
|
43
39
|
end
|
44
40
|
|
45
41
|
def must_be_callable
|
46
42
|
"Invalid attribute option :if_value. It must be a Symbol, a Proc or respond to :call"
|
47
43
|
end
|
44
|
+
|
45
|
+
def valid_signature?(signature)
|
46
|
+
case signature
|
47
|
+
when "0" # no parameters
|
48
|
+
true
|
49
|
+
when "1" # (value)
|
50
|
+
true
|
51
|
+
when "2" # (value, context)
|
52
|
+
true
|
53
|
+
when "1_ctx" # (value, :ctx)
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def signature_error
|
61
|
+
<<~ERROR.strip
|
62
|
+
Invalid attribute option :if_value parameters, valid parameters signatures:
|
63
|
+
- () # no parameters
|
64
|
+
- (value) # one positional parameter
|
65
|
+
- (value, context) # two positional parameters
|
66
|
+
- (value, :ctx) # one positional parameter and :ctx keyword
|
67
|
+
ERROR
|
68
|
+
end
|
48
69
|
end
|
49
70
|
end
|
50
71
|
end
|
@@ -29,17 +29,38 @@ class Serega
|
|
29
29
|
return if value.is_a?(Symbol)
|
30
30
|
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if params_count > 2
|
36
|
-
raise SeregaError, "Option :unless value should have up to 2 parameters (object, context)"
|
37
|
-
end
|
32
|
+
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
33
|
+
raise SeregaError, signature_error unless valid_signature?(signature)
|
38
34
|
end
|
39
35
|
|
40
36
|
def must_be_callable
|
41
37
|
"Invalid attribute option :unless. It must be a Symbol, a Proc or respond to :call"
|
42
38
|
end
|
39
|
+
|
40
|
+
def valid_signature?(signature)
|
41
|
+
case signature
|
42
|
+
when "0" # no parameters
|
43
|
+
true
|
44
|
+
when "1" # (object)
|
45
|
+
true
|
46
|
+
when "2" # (object, context)
|
47
|
+
true
|
48
|
+
when "1_ctx" # (object, :ctx)
|
49
|
+
true
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def signature_error
|
56
|
+
<<~ERROR.strip
|
57
|
+
Invalid attribute option :unless parameters, valid parameters signatures:
|
58
|
+
- () # no parameters
|
59
|
+
- (object) # one positional parameter
|
60
|
+
- (object, context) # two positional parameters
|
61
|
+
- (object, :ctx) # one positional parameter and :ctx keyword
|
62
|
+
ERROR
|
63
|
+
end
|
43
64
|
end
|
44
65
|
end
|
45
66
|
end
|
@@ -34,17 +34,38 @@ class Serega
|
|
34
34
|
return if value.is_a?(Symbol)
|
35
35
|
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if params_count > 2
|
41
|
-
raise SeregaError, "Option :unless_value value should have up to 2 parameters (value, context)"
|
42
|
-
end
|
37
|
+
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [:ctx])
|
38
|
+
raise SeregaError, signature_error unless valid_signature?(signature)
|
43
39
|
end
|
44
40
|
|
45
41
|
def must_be_callable
|
46
42
|
"Invalid attribute option :unless_value. It must be a Symbol, a Proc or respond to :call"
|
47
43
|
end
|
44
|
+
|
45
|
+
def valid_signature?(signature)
|
46
|
+
case signature
|
47
|
+
when "0" # no parameters
|
48
|
+
true
|
49
|
+
when "1" # (value)
|
50
|
+
true
|
51
|
+
when "2" # (value, context)
|
52
|
+
true
|
53
|
+
when "1_ctx" # (value, :ctx)
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def signature_error
|
61
|
+
<<~ERROR.strip
|
62
|
+
Invalid attribute option :unless_value parameters, valid parameters signatures:
|
63
|
+
- () # no parameters
|
64
|
+
- (value) # one positional parameter
|
65
|
+
- (value, context) # two positional parameters
|
66
|
+
- (value, :ctx) # one positional parameter and :ctx keyword
|
67
|
+
ERROR
|
68
|
+
end
|
48
69
|
end
|
49
70
|
end
|
50
71
|
end
|
@@ -40,6 +40,8 @@ class Serega
|
|
40
40
|
@opts = SeregaUtils::EnumDeepDup.call(opts)
|
41
41
|
@block = block
|
42
42
|
@normalized_block = normalize_block(opts[:value], opts[:const], block)
|
43
|
+
@normalized_block_signature =
|
44
|
+
SeregaUtils::MethodSignature.call(@normalized_block, pos_limit: 2, keyword_args: [])
|
43
45
|
end
|
44
46
|
|
45
47
|
#
|
@@ -51,7 +53,11 @@ class Serega
|
|
51
53
|
# @return [Object] Serialized meta attribute value
|
52
54
|
#
|
53
55
|
def value(object, context)
|
54
|
-
|
56
|
+
case normalized_block_signature
|
57
|
+
when "0" then normalized_block.call
|
58
|
+
when "1" then normalized_block.call(object)
|
59
|
+
else normalized_block.call(object, context)
|
60
|
+
end
|
55
61
|
end
|
56
62
|
|
57
63
|
def hide?(value)
|
@@ -60,19 +66,12 @@ class Serega
|
|
60
66
|
|
61
67
|
private
|
62
68
|
|
63
|
-
attr_reader :normalized_block
|
69
|
+
attr_reader :normalized_block, :normalized_block_signature
|
64
70
|
|
65
71
|
def normalize_block(value, const, block)
|
66
72
|
return proc { const } if const
|
67
73
|
|
68
|
-
|
69
|
-
params_count = SeregaUtils::ParamsCount.call(callable, max_count: 2)
|
70
|
-
|
71
|
-
case params_count
|
72
|
-
when 0 then proc { callable.call }
|
73
|
-
when 1 then proc { |obj| callable.call(obj) }
|
74
|
-
else callable
|
75
|
-
end
|
74
|
+
value || block
|
76
75
|
end
|
77
76
|
|
78
77
|
def check(path, opts, block)
|
@@ -29,10 +29,8 @@ class Serega
|
|
29
29
|
# @return [void]
|
30
30
|
#
|
31
31
|
def call(block)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
raise SeregaError, block_error if params_count > 2
|
32
|
+
signature = SeregaUtils::MethodSignature.call(block, pos_limit: 2, keyword_args: [])
|
33
|
+
raise SeregaError, block_error unless %w[0 1 2].include?(signature)
|
36
34
|
end
|
37
35
|
|
38
36
|
private
|
@@ -36,10 +36,9 @@ class Serega
|
|
36
36
|
def check_value(value)
|
37
37
|
check_value_type(value)
|
38
38
|
|
39
|
-
|
40
|
-
params_count = SeregaUtils::ParamsCount.call(value, max_count: 2)
|
39
|
+
signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: [])
|
41
40
|
|
42
|
-
raise SeregaError, params_count_error
|
41
|
+
raise SeregaError, params_count_error unless %w[0 1 2].include?(signature)
|
43
42
|
end
|
44
43
|
|
45
44
|
def check_value_type(value)
|