serega 0.41.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 +123 -1205
- 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 +106 -145
- 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 -145
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +14 -100
- 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 +108 -0
- 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 +480 -372
- data/sig/serega/plugins.rbs +49 -0
- data/sig/serega.rbs +142 -0
- metadata +43 -39
- 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 -118
- 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/presenter/presenter.rb +0 -242
- 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,242 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "delegate"
|
|
4
|
-
require "forwardable"
|
|
5
|
-
|
|
6
|
-
class Serega
|
|
7
|
-
module SeregaPlugins
|
|
8
|
-
#
|
|
9
|
-
# Plugin :presenter — moves computed attribute logic into a dedicated Presenter class.
|
|
10
|
-
#
|
|
11
|
-
# Presenter inherits from SimpleDelegator:
|
|
12
|
-
# - All methods of the serialized object are available directly inside presenter methods.
|
|
13
|
-
# - Methods not defined on Presenter are resolved via method_missing on the first call
|
|
14
|
-
# and then defined as real delegators, so subsequent calls skip method_missing entirely.
|
|
15
|
-
# - The original object is accessible via __getobj__ (standard SimpleDelegator API).
|
|
16
|
-
# - The serialization context is accessible via the private method __ctx__.
|
|
17
|
-
#
|
|
18
|
-
# The `presenter do ... end` block is evaluated inside the serializer's own
|
|
19
|
-
# Presenter class, so multiple blocks accumulate.
|
|
20
|
-
#
|
|
21
|
-
# @example
|
|
22
|
-
# class UserSerializer < Serega
|
|
23
|
-
# plugin :presenter
|
|
24
|
-
#
|
|
25
|
-
# attribute :name
|
|
26
|
-
# attribute :role
|
|
27
|
-
#
|
|
28
|
-
# presenter do
|
|
29
|
-
# def name
|
|
30
|
-
# [first_name, last_name].compact.join(' ') # first_name/last_name delegated to object
|
|
31
|
-
# end
|
|
32
|
-
#
|
|
33
|
-
# def role
|
|
34
|
-
# id == __ctx__[:current_user_id] ? :self : :other
|
|
35
|
-
# end
|
|
36
|
-
# end
|
|
37
|
-
# end
|
|
38
|
-
#
|
|
39
|
-
module Presenter
|
|
40
|
-
# @return [Symbol] Plugin name
|
|
41
|
-
# @private
|
|
42
|
-
def self.plugin_name
|
|
43
|
-
:presenter
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
# Applies plugin code to specific serializer
|
|
48
|
-
#
|
|
49
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
|
50
|
-
# @param _opts [Hash] Plugin options
|
|
51
|
-
#
|
|
52
|
-
# @return [void]
|
|
53
|
-
#
|
|
54
|
-
# @private
|
|
55
|
-
def self.load_plugin(serializer_class, **_opts)
|
|
56
|
-
serializer_class.extend(ClassMethods)
|
|
57
|
-
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
#
|
|
61
|
-
# Runs callbacks after plugin was attached
|
|
62
|
-
#
|
|
63
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
|
64
|
-
# @param _opts [Hash] Plugin options
|
|
65
|
-
#
|
|
66
|
-
# @return [void]
|
|
67
|
-
#
|
|
68
|
-
# @private
|
|
69
|
-
def self.after_load_plugin(serializer_class, **_opts)
|
|
70
|
-
presenter_class = Class.new(Presenter)
|
|
71
|
-
presenter_class.serializer_class = serializer_class
|
|
72
|
-
serializer_class.const_set(:Presenter, presenter_class)
|
|
73
|
-
|
|
74
|
-
# The presenter's unwrap method returns the serialized object itself,
|
|
75
|
-
# not an association — it must never be auto-preloaded.
|
|
76
|
-
config = serializer_class.config
|
|
77
|
-
config.auto_preload_excluded_methods = config.auto_preload_excluded_methods | [:__getobj__]
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Presenter class
|
|
81
|
-
# @private
|
|
82
|
-
class Presenter < SimpleDelegator
|
|
83
|
-
# Presenter instance methods
|
|
84
|
-
# @private
|
|
85
|
-
module InstanceMethods
|
|
86
|
-
#
|
|
87
|
-
# @param object [Object] Serialized object to wrap
|
|
88
|
-
# @param ctx [Hash, nil] Serialization context
|
|
89
|
-
#
|
|
90
|
-
def initialize(object, ctx = nil)
|
|
91
|
-
super(object)
|
|
92
|
-
@__ctx__ = ctx
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
private
|
|
96
|
-
|
|
97
|
-
attr_reader :__ctx__
|
|
98
|
-
|
|
99
|
-
#
|
|
100
|
-
# Delegates all missing methods to serialized object.
|
|
101
|
-
#
|
|
102
|
-
# Creates delegator method after first #method_missing hit to improve
|
|
103
|
-
# performance of following serializations.
|
|
104
|
-
#
|
|
105
|
-
def method_missing(name, *_args, &_block) # rubocop:disable Style/MissingRespondToMissing -- base SimpleDelegator class has this method
|
|
106
|
-
super.tap do
|
|
107
|
-
self.class.def_delegator :__getobj__, name
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
extend SeregaHelpers::SerializerClassHelper
|
|
113
|
-
extend Forwardable
|
|
114
|
-
include InstanceMethods
|
|
115
|
-
|
|
116
|
-
# Tracks whether user code was added to the Presenter class.
|
|
117
|
-
#
|
|
118
|
-
# These singleton methods are defined after the base class body above,
|
|
119
|
-
# so the plugin's own includes do not mark the base class as modified.
|
|
120
|
-
# Lazy delegators defined by #method_missing do mark the class, but
|
|
121
|
-
# they can appear only on presenters that are already wrapping.
|
|
122
|
-
class << self
|
|
123
|
-
#
|
|
124
|
-
# Checks if this Presenter class (or an inherited one) was extended
|
|
125
|
-
# with custom user code and therefore objects must be wrapped
|
|
126
|
-
#
|
|
127
|
-
# @return [Boolean] whether custom presenter methods were defined
|
|
128
|
-
#
|
|
129
|
-
def modified?
|
|
130
|
-
return true if defined?(@modified)
|
|
131
|
-
return false if equal?(Presenter) # the plugin's base class — the walk stops here
|
|
132
|
-
|
|
133
|
-
superclass.modified?
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Marks the class as modified, then includes the module
|
|
137
|
-
# @return [void]
|
|
138
|
-
def include(*modules)
|
|
139
|
-
@modified = true
|
|
140
|
-
super
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# Marks the class as modified, then prepends the module
|
|
144
|
-
# @return [void]
|
|
145
|
-
def prepend(*modules)
|
|
146
|
-
@modified = true
|
|
147
|
-
super
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
private
|
|
151
|
-
|
|
152
|
-
def method_added(name)
|
|
153
|
-
@modified = true
|
|
154
|
-
super
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
#
|
|
160
|
-
# Serega additional/patched class methods
|
|
161
|
-
#
|
|
162
|
-
# @see Serega
|
|
163
|
-
#
|
|
164
|
-
module ClassMethods
|
|
165
|
-
#
|
|
166
|
-
# Defines presenter methods — evaluates the block inside the
|
|
167
|
-
# serializer's own Presenter class. Multiple blocks accumulate.
|
|
168
|
-
#
|
|
169
|
-
# presenter do
|
|
170
|
-
# def name
|
|
171
|
-
# [first_name, last_name].compact.join(" ")
|
|
172
|
-
# end
|
|
173
|
-
# end
|
|
174
|
-
#
|
|
175
|
-
# @return [void]
|
|
176
|
-
#
|
|
177
|
-
def presenter(&block)
|
|
178
|
-
raise SeregaError, "Provide a block with presenter methods: `presenter do ... end`" unless block
|
|
179
|
-
|
|
180
|
-
self::Presenter.class_exec(&block)
|
|
181
|
-
nil
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
#
|
|
185
|
-
# Checks if the serializer's Presenter class (or an inherited one) was
|
|
186
|
-
# extended with custom user code. When it was not, serialized objects
|
|
187
|
-
# are not wrapped in the Presenter at all.
|
|
188
|
-
#
|
|
189
|
-
# @return [Boolean] whether custom presenter methods were defined
|
|
190
|
-
#
|
|
191
|
-
# @private
|
|
192
|
-
def custom_presenter?
|
|
193
|
-
self::Presenter.modified?
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
private
|
|
197
|
-
|
|
198
|
-
def inherited(subclass)
|
|
199
|
-
super
|
|
200
|
-
|
|
201
|
-
presenter_class = Class.new(self::Presenter)
|
|
202
|
-
presenter_class.serializer_class = subclass
|
|
203
|
-
subclass.const_set(:Presenter, presenter_class)
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
#
|
|
208
|
-
# SeregaObjectSerializer additional/patched class methods
|
|
209
|
-
#
|
|
210
|
-
# @see Serega::SeregaObjectSerializer
|
|
211
|
-
#
|
|
212
|
-
# @private
|
|
213
|
-
module SeregaObjectSerializerInstanceMethods
|
|
214
|
-
# The custom-presenter check is made once per object serializer here
|
|
215
|
-
# and its result is reused for every enqueued chunk of the level.
|
|
216
|
-
def initialize(**opts)
|
|
217
|
-
super
|
|
218
|
-
@wrap_in_presenter = self.class.serializer_class.custom_presenter?
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
private
|
|
222
|
-
|
|
223
|
-
#
|
|
224
|
-
# Wraps each serialized object in Presenter.new(object, ctx) before it is
|
|
225
|
-
# enqueued, so the whole level — value resolution and batch loaders alike —
|
|
226
|
-
# sees presenters. Objects are not wrapped when the Presenter class has
|
|
227
|
-
# no custom methods — such wrapping would only add overhead and break
|
|
228
|
-
# class checks (object.is_a?, Hash === object) without changing anything.
|
|
229
|
-
#
|
|
230
|
-
def enqueue(objects)
|
|
231
|
-
return super unless @wrap_in_presenter
|
|
232
|
-
|
|
233
|
-
presenter = self.class.serializer_class::Presenter
|
|
234
|
-
presenters = objects.map { |object| presenter.new(object, context) }
|
|
235
|
-
super(presenters)
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
register_plugin(Presenter.plugin_name, Presenter)
|
|
241
|
-
end
|
|
242
|
-
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
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
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
|
-
#
|
|
23
|
-
module StringModifiers
|
|
24
|
-
# @return [Symbol] Plugin name
|
|
25
|
-
# @private
|
|
26
|
-
def self.plugin_name
|
|
27
|
-
:string_modifiers
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
# Applies plugin code to specific serializer
|
|
32
|
-
#
|
|
33
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
|
34
|
-
# @param _opts [Hash] Plugin options
|
|
35
|
-
#
|
|
36
|
-
# @return [void]
|
|
37
|
-
#
|
|
38
|
-
# @private
|
|
39
|
-
def self.load_plugin(serializer_class, **_opts)
|
|
40
|
-
serializer_class.include(InstanceMethods)
|
|
41
|
-
require_relative "parse_string_modifiers"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
# Serega additional/patched instance methods
|
|
46
|
-
#
|
|
47
|
-
# @see Serega
|
|
48
|
-
#
|
|
49
|
-
# @private
|
|
50
|
-
module InstanceMethods
|
|
51
|
-
private
|
|
52
|
-
|
|
53
|
-
def parse_modifier(value)
|
|
54
|
-
return ParseStringModifiers.parse(value) if value.is_a?(String)
|
|
55
|
-
|
|
56
|
-
super
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
register_plugin(StringModifiers.plugin_name, StringModifiers)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
# @private
|
|
5
|
-
module SeregaUtils
|
|
6
|
-
#
|
|
7
|
-
# Utility to get frozen string from symbol in any ruby version
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class SymbolName
|
|
11
|
-
class << self
|
|
12
|
-
#
|
|
13
|
-
# Returns frozen string corresponding to provided symbol
|
|
14
|
-
#
|
|
15
|
-
# @param key [Symbol]
|
|
16
|
-
#
|
|
17
|
-
# @return [String] frozen string corresponding to provided symbol
|
|
18
|
-
#
|
|
19
|
-
def call(key)
|
|
20
|
-
key.is_a?(String) ? key : to_frozen_string(key)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
# :nocov:
|
|
26
|
-
if RUBY_VERSION < "3"
|
|
27
|
-
def to_frozen_string(key)
|
|
28
|
-
key.to_s.freeze
|
|
29
|
-
end
|
|
30
|
-
else
|
|
31
|
-
def to_frozen_string(key)
|
|
32
|
-
key.name
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
# :nocov:
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
# @private
|
|
5
|
-
module SeregaValidations
|
|
6
|
-
# @private
|
|
7
|
-
module Attribute
|
|
8
|
-
#
|
|
9
|
-
# Attribute `:const` option validator
|
|
10
|
-
#
|
|
11
|
-
# @private
|
|
12
|
-
class CheckOptConst
|
|
13
|
-
class << self
|
|
14
|
-
#
|
|
15
|
-
# Checks attribute :const option
|
|
16
|
-
#
|
|
17
|
-
# @param opts [Hash] Attribute options
|
|
18
|
-
#
|
|
19
|
-
# @raise [SeregaError] Attribute validation error
|
|
20
|
-
#
|
|
21
|
-
# @return [void]
|
|
22
|
-
#
|
|
23
|
-
def call(opts)
|
|
24
|
-
return unless opts.key?(:const)
|
|
25
|
-
|
|
26
|
-
check_usage_with_other_params(opts)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def check_usage_with_other_params(opts)
|
|
32
|
-
raise SeregaError, "Option :const can not be used together with option :method" if opts.key?(:method)
|
|
33
|
-
raise SeregaError, "Option :const can not be used together with option :value" if opts.key?(:value)
|
|
34
|
-
raise SeregaError, "Option :const can not be used together with option :batch" if opts.key?(:batch)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
# @private
|
|
5
|
-
module SeregaValidations
|
|
6
|
-
#
|
|
7
|
-
# Validations of serializer initialization options
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class CheckInitiateParams
|
|
11
|
-
#
|
|
12
|
-
# Validations of serializer initialization options instance methods
|
|
13
|
-
#
|
|
14
|
-
# @private
|
|
15
|
-
module InstanceMethods
|
|
16
|
-
# @return [Hash] validated initialization options
|
|
17
|
-
attr_reader :opts
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
# Initializes validator for initialization options
|
|
21
|
-
#
|
|
22
|
-
# @param opts [Hash] initialization options
|
|
23
|
-
#
|
|
24
|
-
# @return [void]
|
|
25
|
-
#
|
|
26
|
-
def initialize(opts)
|
|
27
|
-
@opts = opts
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
# Validates initiating params
|
|
32
|
-
#
|
|
33
|
-
def validate
|
|
34
|
-
check_allowed_keys
|
|
35
|
-
check_modifiers
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def check_allowed_keys
|
|
41
|
-
Utils::CheckAllowedKeys.call(opts, serializer_class.config.initiate_keys, :initiate)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def check_modifiers
|
|
45
|
-
Initiate::CheckModifiers.new.call(serializer_class, opts[:only], opts[:with], opts[:except])
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def serializer_class
|
|
49
|
-
self.class.serializer_class
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
include InstanceMethods
|
|
54
|
-
extend Serega::SeregaHelpers::SerializerClassHelper
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class Serega
|
|
4
|
-
# @private
|
|
5
|
-
module SeregaValidations
|
|
6
|
-
#
|
|
7
|
-
# Validations of serialization options
|
|
8
|
-
#
|
|
9
|
-
# @private
|
|
10
|
-
class CheckSerializeParams
|
|
11
|
-
#
|
|
12
|
-
# Validations of serialization options instance methods
|
|
13
|
-
#
|
|
14
|
-
# @private
|
|
15
|
-
module InstanceMethods
|
|
16
|
-
attr_reader :opts
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
# Initializes validator for serialization options
|
|
20
|
-
#
|
|
21
|
-
# @param opts [Hash] serialization options
|
|
22
|
-
#
|
|
23
|
-
# @return [void]
|
|
24
|
-
#
|
|
25
|
-
def initialize(opts)
|
|
26
|
-
@opts = opts
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
# Validates serialization options
|
|
31
|
-
#
|
|
32
|
-
def validate
|
|
33
|
-
check_opts
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def check_opts
|
|
39
|
-
Utils::CheckAllowedKeys.call(opts, serializer_class.config.serialize_keys, :serialize)
|
|
40
|
-
|
|
41
|
-
Utils::CheckOptIsHash.call(opts, :context)
|
|
42
|
-
Utils::CheckOptIsBool.call(opts, :many)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def serializer_class
|
|
46
|
-
self.class.serializer_class
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
include InstanceMethods
|
|
51
|
-
extend Serega::SeregaHelpers::SerializerClassHelper
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|