serega 0.40.0 → 0.41.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/LICENSE.txt +21 -0
- data/README.md +204 -108
- 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 +12 -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 +95 -1
- metadata +13 -16
|
@@ -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/
|
|
@@ -4,14 +4,17 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Validations
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaValidations
|
|
8
9
|
#
|
|
9
10
|
# Validations for attribute params
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
class CheckAttributeParams
|
|
12
14
|
#
|
|
13
15
|
# Validations for attribute params instance methods
|
|
14
16
|
#
|
|
17
|
+
# @private
|
|
15
18
|
module InstanceMethods
|
|
16
19
|
# @return [Symbol] validated attribute name
|
|
17
20
|
attr_reader :name
|
|
@@ -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
|
# Batch loader parameters validators
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
class CheckBatchLoaderParams
|
|
9
11
|
#
|
|
10
12
|
# batch_loader parameters validation instance methods
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
module InstanceMethods
|
|
13
16
|
# @return [Symbol] validated batch_loader name
|
|
14
17
|
attr_reader :name
|
|
@@ -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
|
# Validations of serializer initialization options
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
class CheckInitiateParams
|
|
9
11
|
#
|
|
10
12
|
# Validations of serializer initialization options instance methods
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
module InstanceMethods
|
|
13
16
|
# @return [Hash] validated initialization options
|
|
14
17
|
attr_reader :opts
|
|
@@ -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
|
# Validations of serialization options
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
class CheckSerializeParams
|
|
9
11
|
#
|
|
10
12
|
# Validations of serialization options instance methods
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
module InstanceMethods
|
|
13
16
|
attr_reader :opts
|
|
14
17
|
|
|
@@ -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
|
# Validations that take place when initializing serializer
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
module Initiate
|
|
9
11
|
#
|
|
10
12
|
# Modifiers validation
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
class CheckModifiers
|
|
13
16
|
#
|
|
14
17
|
# Validates provided fields names are existing attributes
|
|
@@ -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
|
# Validations Utilities
|
|
7
8
|
#
|
|
9
|
+
# @private
|
|
8
10
|
module Utils
|
|
9
11
|
#
|
|
10
12
|
# Utility to check all hash keys are allowed
|
|
11
13
|
#
|
|
14
|
+
# @private
|
|
12
15
|
class CheckAllowedKeys
|
|
13
16
|
# Checks hash keys are allowed
|
|
14
17
|
#
|
|
@@ -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 Utils
|
|
6
8
|
#
|
|
7
9
|
# Utility to check hash key value is boolean
|
|
8
10
|
#
|
|
11
|
+
# @private
|
|
9
12
|
class CheckOptIsBool
|
|
10
13
|
# Checks hash key has boolean value
|
|
11
14
|
#
|
|
@@ -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 Utils
|
|
6
8
|
#
|
|
7
9
|
# Utility to check hash key value is String or Symbol
|
|
8
10
|
#
|
|
11
|
+
# @private
|
|
9
12
|
class CheckOptIsStringOrSymbol
|
|
10
13
|
# Checks hash key has String or Symbol value
|
|
11
14
|
#
|
data/lib/serega.rb
CHANGED
|
@@ -6,10 +6,12 @@ require_relative "serega/version"
|
|
|
6
6
|
class Serega
|
|
7
7
|
# Frozen hash
|
|
8
8
|
# @return [Hash] frozen hash
|
|
9
|
+
# @private
|
|
9
10
|
FROZEN_EMPTY_HASH = {}.freeze
|
|
10
11
|
|
|
11
12
|
# Frozen array
|
|
12
13
|
# @return [Array] frozen array
|
|
14
|
+
# @private
|
|
13
15
|
FROZEN_EMPTY_ARRAY = [].freeze
|
|
14
16
|
|
|
15
17
|
# Empty modifiers/serialization options (used when serializing with no opts provided)
|
|
@@ -136,6 +138,7 @@ class Serega
|
|
|
136
138
|
#
|
|
137
139
|
# @return [Boolean] Is plugin used
|
|
138
140
|
#
|
|
141
|
+
# @private
|
|
139
142
|
def plugin_used?(name)
|
|
140
143
|
plugin_name =
|
|
141
144
|
case name
|
|
@@ -151,6 +154,7 @@ class Serega
|
|
|
151
154
|
#
|
|
152
155
|
# @return [Hash] attributes list
|
|
153
156
|
#
|
|
157
|
+
# @private
|
|
154
158
|
def attributes
|
|
155
159
|
@attributes ||= {}
|
|
156
160
|
end
|
|
@@ -160,6 +164,7 @@ class Serega
|
|
|
160
164
|
#
|
|
161
165
|
# @return [Hash] batch loaders list
|
|
162
166
|
#
|
|
167
|
+
# @private
|
|
163
168
|
def batch_loaders
|
|
164
169
|
@batch_loaders ||= {}
|
|
165
170
|
end
|
|
@@ -260,6 +265,63 @@ class Serega
|
|
|
260
265
|
@preload_with = handler
|
|
261
266
|
end
|
|
262
267
|
|
|
268
|
+
#
|
|
269
|
+
# Registers (or returns) the handler that replaces the serialized objects
|
|
270
|
+
# before serialization starts.
|
|
271
|
+
#
|
|
272
|
+
# The handler is called once per serialization with the objects provided to
|
|
273
|
+
# `.call`/`.to_h`/`.to_data` and the serialization context. Its result is
|
|
274
|
+
# serialized instead of the provided objects, which allows to accept ids or
|
|
275
|
+
# other references and load the records in one place.
|
|
276
|
+
#
|
|
277
|
+
# The handler runs before the `:many` option is detected, so it may turn a
|
|
278
|
+
# single object into a collection and back. A provided `:many` serialization
|
|
279
|
+
# option is still used as is.
|
|
280
|
+
#
|
|
281
|
+
# The handler runs only for the serialized objects, and not for objects of
|
|
282
|
+
# nested serializers.
|
|
283
|
+
#
|
|
284
|
+
# @example with a block
|
|
285
|
+
# prepare_initial_objects { |user_ids| User.where(id: user_ids) }
|
|
286
|
+
#
|
|
287
|
+
# @example with a context
|
|
288
|
+
# prepare_initial_objects { |user_ids, ctx| User.where(id: user_ids, account: ctx[:account]) }
|
|
289
|
+
#
|
|
290
|
+
# @example with a keyword context
|
|
291
|
+
# prepare_initial_objects { |user_ids, ctx:| User.where(id: user_ids, account: ctx[:account]) }
|
|
292
|
+
#
|
|
293
|
+
# @example with a callable value
|
|
294
|
+
# prepare_initial_objects UsersLoader
|
|
295
|
+
#
|
|
296
|
+
# @param value [#call, nil] Handler accepting (objects), (objects, context) or (objects, ctx:)
|
|
297
|
+
# @param block [Proc] Handler accepting (objects), (objects, context) or (objects, ctx:)
|
|
298
|
+
#
|
|
299
|
+
# @return [#call, nil] The registered handler
|
|
300
|
+
#
|
|
301
|
+
def prepare_initial_objects(value = nil, &block)
|
|
302
|
+
return @prepare_initial_objects if value.nil? && block.nil?
|
|
303
|
+
raise SeregaError, "prepare_initial_objects accepts a single callable or a block, not both" if value && block
|
|
304
|
+
|
|
305
|
+
handler = value || block
|
|
306
|
+
raise SeregaError, "prepare_initial_objects value must be a Proc or respond to #call" if !handler.is_a?(Proc) && !handler.respond_to?(:call)
|
|
307
|
+
|
|
308
|
+
signature = SeregaUtils::MethodSignature.call(handler, pos_limit: 2, keyword_args: [:ctx])
|
|
309
|
+
raise SeregaError, prepare_initial_objects_signature_error unless %w[1 2 1_ctx].include?(signature)
|
|
310
|
+
|
|
311
|
+
@prepare_initial_objects_signature = signature
|
|
312
|
+
@prepare_initial_objects = handler
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
#
|
|
316
|
+
# Signature of the registered prepare_initial_objects handler
|
|
317
|
+
#
|
|
318
|
+
# @return [String, nil] Handler signature
|
|
319
|
+
#
|
|
320
|
+
# @private
|
|
321
|
+
def prepare_initial_objects_signature
|
|
322
|
+
@prepare_initial_objects_signature
|
|
323
|
+
end
|
|
324
|
+
|
|
263
325
|
#
|
|
264
326
|
# Serializes provided object to Hash
|
|
265
327
|
#
|
|
@@ -381,8 +443,20 @@ class Serega
|
|
|
381
443
|
# Assign same preload handler
|
|
382
444
|
subclass.preload_with(preload_with) if preload_with
|
|
383
445
|
|
|
446
|
+
# Assign same initial objects handler
|
|
447
|
+
subclass.prepare_initial_objects(prepare_initial_objects) if prepare_initial_objects
|
|
448
|
+
|
|
384
449
|
super
|
|
385
450
|
end
|
|
451
|
+
|
|
452
|
+
def prepare_initial_objects_signature_error
|
|
453
|
+
<<~ERR.strip
|
|
454
|
+
prepare_initial_objects handler arguments should have one of this signatures:
|
|
455
|
+
- (objects) # one argument
|
|
456
|
+
- (objects, ctx) # two arguments
|
|
457
|
+
- (objects, ctx:) # one argument and one :ctx keyword argument
|
|
458
|
+
ERR
|
|
459
|
+
end
|
|
386
460
|
end
|
|
387
461
|
|
|
388
462
|
#
|
|
@@ -417,6 +491,7 @@ class Serega
|
|
|
417
491
|
# This plan can be traversed to find serialized attributes and nested attributes.
|
|
418
492
|
#
|
|
419
493
|
# @return [Serega::SeregaPlan] Serialization plan
|
|
494
|
+
# @private
|
|
420
495
|
attr_reader :plan
|
|
421
496
|
|
|
422
497
|
#
|
|
@@ -430,6 +505,8 @@ class Serega
|
|
|
430
505
|
# @return [Hash] Serialization result
|
|
431
506
|
#
|
|
432
507
|
def call(object, opts = nil)
|
|
508
|
+
opts = normalize_serialization_opts(opts)
|
|
509
|
+
object = prepare_objects(object, opts[:context])
|
|
433
510
|
opts = prepare_initial_serialization_opts(object, opts)
|
|
434
511
|
serialize(object, opts)
|
|
435
512
|
end
|
|
@@ -452,6 +529,8 @@ class Serega
|
|
|
452
529
|
# @return [Data] Serialization result
|
|
453
530
|
#
|
|
454
531
|
def to_data(object, opts = nil)
|
|
532
|
+
opts = normalize_serialization_opts(opts)
|
|
533
|
+
object = prepare_objects(object, opts[:context])
|
|
455
534
|
opts = prepare_initial_serialization_opts(object, opts)
|
|
456
535
|
serialized_data = serialize(object, opts)
|
|
457
536
|
self.class::SeregaDataBuilder.call(self, serialized_data)
|
|
@@ -482,11 +561,26 @@ class Serega
|
|
|
482
561
|
SeregaUtils::ToHash.call(value)
|
|
483
562
|
end
|
|
484
563
|
|
|
485
|
-
def
|
|
564
|
+
def normalize_serialization_opts(opts)
|
|
486
565
|
opts = opts ? opts.transform_keys(&:to_sym) : {}
|
|
487
566
|
self.class::CheckSerializeParams.new(opts).validate unless opts.empty?
|
|
488
567
|
|
|
489
568
|
opts[:context] ||= {}
|
|
569
|
+
opts
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def prepare_objects(objects, context)
|
|
573
|
+
handler = self.class.prepare_initial_objects
|
|
574
|
+
return objects unless handler
|
|
575
|
+
|
|
576
|
+
case self.class.prepare_initial_objects_signature
|
|
577
|
+
when "1" then handler.call(objects)
|
|
578
|
+
when "2" then handler.call(objects, context)
|
|
579
|
+
else handler.call(objects, ctx: context) # "1_ctx"
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
def prepare_initial_serialization_opts(object, opts)
|
|
490
584
|
opts[:level_queue] = SeregaEngine::LevelQueue.new
|
|
491
585
|
opts[:many] = SeregaUtils::CollectionDetector.call(object) unless opts.key?(:many)
|
|
492
586
|
opts[:plan] = plan
|
metadata
CHANGED
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: serega
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.41.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Andrey
|
|
7
|
+
- Andrey
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
|
-
description:
|
|
13
|
-
JSON
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
- Multiple ways to solve N+1 problems
|
|
18
|
-
- Built-in presenter
|
|
19
|
-
- No dependencies
|
|
20
|
-
- Plugin system as in Roda or Shrine
|
|
12
|
+
description: Serializes Ruby objects into Hashes, ready for further conversion to
|
|
13
|
+
JSON or other formats, with a simple DSL for selecting fields and solving N+1 queries
|
|
14
|
+
through batch loading. Extendable through a Roda/Shrine-style plugin system, with
|
|
15
|
+
built-in plugins for presenters, formatters, camel_case keys, depth limiting, and
|
|
16
|
+
more. No runtime dependencies.
|
|
21
17
|
email:
|
|
22
|
-
-
|
|
18
|
+
- andreyruby@yandex.ru
|
|
23
19
|
executables: []
|
|
24
20
|
extensions: []
|
|
25
21
|
extra_rdoc_files: []
|
|
26
22
|
files:
|
|
23
|
+
- LICENSE.txt
|
|
27
24
|
- README.md
|
|
28
25
|
- VERSION
|
|
29
26
|
- lib/serega.rb
|
|
@@ -101,13 +98,13 @@ files:
|
|
|
101
98
|
- lib/serega/validations/utils/check_opt_is_hash.rb
|
|
102
99
|
- lib/serega/validations/utils/check_opt_is_string_or_symbol.rb
|
|
103
100
|
- lib/serega/version.rb
|
|
104
|
-
homepage: https://github.com/
|
|
101
|
+
homepage: https://github.com/andreyruby/serega
|
|
105
102
|
licenses:
|
|
106
103
|
- MIT
|
|
107
104
|
metadata:
|
|
108
|
-
source_code_uri: https://github.com/
|
|
105
|
+
source_code_uri: https://github.com/andreyruby/serega
|
|
109
106
|
documentation_uri: https://www.rubydoc.info/gems/serega
|
|
110
|
-
changelog_uri: https://github.com/
|
|
107
|
+
changelog_uri: https://github.com/andreyruby/serega/blob/master/CHANGELOG.md
|
|
111
108
|
rdoc_options: []
|
|
112
109
|
require_paths:
|
|
113
110
|
- lib
|
|
@@ -124,5 +121,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
124
121
|
requirements: []
|
|
125
122
|
rubygems_version: 4.0.13
|
|
126
123
|
specification_version: 4
|
|
127
|
-
summary:
|
|
124
|
+
summary: Ruby Serializer
|
|
128
125
|
test_files: []
|