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
data/lib/serega/data_builder.rb
CHANGED
|
@@ -5,8 +5,10 @@ class Serega
|
|
|
5
5
|
# Builds Data objects from serialized hashes.
|
|
6
6
|
# Used by `#to_data` / `.to_data`.
|
|
7
7
|
#
|
|
8
|
+
# @private
|
|
8
9
|
class SeregaDataBuilder
|
|
9
10
|
# SeregaDataBuilder class methods
|
|
11
|
+
# @private
|
|
10
12
|
module SeregaDataBuilderClassMethods
|
|
11
13
|
#
|
|
12
14
|
# Converts serialized Hash/Array result into a tree of Ruby Data objects
|
data/lib/serega/engine/level.rb
CHANGED
|
@@ -4,6 +4,7 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Batch feature main module
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaEngine
|
|
8
9
|
#
|
|
9
10
|
# One serialization level: all objects serialized under a single plan and the
|
|
@@ -12,6 +13,7 @@ class Serega
|
|
|
12
13
|
# or preload runs once over the whole set. A deeper level (its own plan) loads
|
|
13
14
|
# separately.
|
|
14
15
|
#
|
|
16
|
+
# @private
|
|
15
17
|
class Level
|
|
16
18
|
# @param serializer [SeregaObjectSerializer] serializer that resolves this level
|
|
17
19
|
def initialize(serializer)
|
|
@@ -4,6 +4,7 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Batch feature main module
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaEngine
|
|
8
9
|
#
|
|
9
10
|
# Level-order queue of serialization levels for one serialization run.
|
|
@@ -15,6 +16,7 @@ class Serega
|
|
|
15
16
|
# Processing level-by-level lets a named batch loader and preloads run once per
|
|
16
17
|
# level over all of its objects.
|
|
17
18
|
#
|
|
19
|
+
# @private
|
|
18
20
|
class LevelQueue
|
|
19
21
|
def initialize
|
|
20
22
|
@levels = []
|
data/lib/serega/engine/loader.rb
CHANGED
|
@@ -4,14 +4,17 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Batch feature main module
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaEngine
|
|
8
9
|
#
|
|
9
10
|
# Batch loader
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
class Loader
|
|
12
14
|
#
|
|
13
15
|
# BatchLoader instance methods
|
|
14
16
|
#
|
|
17
|
+
# @private
|
|
15
18
|
module InstanceMethods
|
|
16
19
|
# BatchLoader initial params
|
|
17
20
|
# @return [Hash] BatchLoader initial params
|
|
@@ -4,10 +4,12 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Helpers
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
module SeregaHelpers
|
|
8
9
|
#
|
|
9
10
|
# Stores link to current serializer class
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
module SerializerClassHelper
|
|
12
14
|
# Shows serializer class current class is namespaced under
|
|
13
15
|
# @return [Class<Serega>] Serializer class that current class is namespaced under.
|
|
@@ -9,10 +9,12 @@ class Serega
|
|
|
9
9
|
# which resolves every attribute for every object and enqueues child levels for
|
|
10
10
|
# relations.
|
|
11
11
|
#
|
|
12
|
+
# @private
|
|
12
13
|
class SeregaObjectSerializer
|
|
13
14
|
#
|
|
14
15
|
# SeregaObjectSerializer instance methods
|
|
15
16
|
#
|
|
17
|
+
# @private
|
|
16
18
|
module InstanceMethods
|
|
17
19
|
attr_reader :context, :plan, :many, :opts, :level_queue
|
|
18
20
|
|
data/lib/serega/plan.rb
CHANGED
|
@@ -5,10 +5,12 @@ class Serega
|
|
|
5
5
|
# Constructs plan - list of serialized attributes.
|
|
6
6
|
# We will traverse this plan to construct serialized response.
|
|
7
7
|
#
|
|
8
|
+
# @private
|
|
8
9
|
class SeregaPlan
|
|
9
10
|
#
|
|
10
11
|
# SeregaPlan class methods
|
|
11
12
|
#
|
|
13
|
+
# @private
|
|
12
14
|
module ClassMethods
|
|
13
15
|
#
|
|
14
16
|
# Constructs plan of attributes that should be serialized.
|
|
@@ -68,6 +70,7 @@ class Serega
|
|
|
68
70
|
#
|
|
69
71
|
# SeregaPlan instance methods
|
|
70
72
|
#
|
|
73
|
+
# @private
|
|
71
74
|
module InstanceMethods
|
|
72
75
|
# Parent plan point
|
|
73
76
|
# @return [SeregaPlanPoint, nil]
|
data/lib/serega/plan_point.rb
CHANGED
|
@@ -4,10 +4,12 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Combines attribute and nested attributes
|
|
6
6
|
#
|
|
7
|
+
# @private
|
|
7
8
|
class SeregaPlanPoint
|
|
8
9
|
#
|
|
9
10
|
# SeregaPlanPoint instance methods
|
|
10
11
|
#
|
|
12
|
+
# @private
|
|
11
13
|
module InstanceMethods
|
|
12
14
|
# Link to current plan this point belongs to
|
|
13
15
|
# @return [SeregaAttribute] Current plan
|
|
@@ -12,38 +12,40 @@ class Serega
|
|
|
12
12
|
#
|
|
13
13
|
# @example
|
|
14
14
|
# class AppSerializer < Serega
|
|
15
|
-
# config.
|
|
16
|
-
# config.auto_preload_attributes_with_serializer = true
|
|
17
|
-
# config.hide_by_default = [:preload]
|
|
18
|
-
#
|
|
15
|
+
# config.auto_preload = true
|
|
19
16
|
# plugin :activerecord_preloads
|
|
20
17
|
# end
|
|
21
18
|
#
|
|
22
|
-
# class
|
|
19
|
+
# class AlbumSerializer < AppSerializer
|
|
23
20
|
# # no preloads
|
|
24
|
-
# attribute :
|
|
25
|
-
#
|
|
26
|
-
# # preloads `:user_stats` as auto_preload_attributes_with_delegate option is true
|
|
27
|
-
# attribute :comments_count, delegate: { to: :user_stats }
|
|
21
|
+
# attribute :title
|
|
28
22
|
#
|
|
29
|
-
# # preloads
|
|
30
|
-
# attribute :
|
|
23
|
+
# # preloads :downloads, as manually specified
|
|
24
|
+
# attribute :downloads_count, preload: :downloads, value: proc { |album| album.downloads.count }
|
|
31
25
|
# end
|
|
32
26
|
#
|
|
33
|
-
# class
|
|
27
|
+
# class UserSerializer < AppSerializer
|
|
34
28
|
# # no preloads
|
|
35
|
-
# attribute :
|
|
29
|
+
# attribute :username
|
|
36
30
|
#
|
|
37
|
-
# # preloads :
|
|
38
|
-
# attribute :
|
|
31
|
+
# # preloads :user_stats, as auto_preload is enabled for :delegate attributes
|
|
32
|
+
# attribute :comments_count, delegate: { to: :user_stats }
|
|
33
|
+
#
|
|
34
|
+
# # preloads :albums, as auto_preload is enabled for :serializer attributes
|
|
35
|
+
# attribute :albums, serializer: AlbumSerializer
|
|
39
36
|
# end
|
|
40
37
|
#
|
|
41
|
-
# UserSerializer.to_h(
|
|
38
|
+
# UserSerializer.to_h(users)
|
|
39
|
+
# # 1 query to load :user_stats for all users
|
|
40
|
+
# # + 1 query to load :albums for all users
|
|
41
|
+
# # + 1 query to load :downloads for all albums
|
|
42
|
+
# # = 3 queries total, regardless of how many users/albums are serialized
|
|
42
43
|
#
|
|
43
44
|
module ActiverecordPreloads
|
|
44
45
|
#
|
|
45
46
|
# @return [Symbol] Plugin name
|
|
46
47
|
#
|
|
48
|
+
# @private
|
|
47
49
|
def self.plugin_name
|
|
48
50
|
:activerecord_preloads
|
|
49
51
|
end
|
|
@@ -55,6 +57,7 @@ class Serega
|
|
|
55
57
|
#
|
|
56
58
|
# @return [void]
|
|
57
59
|
#
|
|
60
|
+
# @private
|
|
58
61
|
def self.before_load_plugin(serializer_class, **opts)
|
|
59
62
|
opts.each_key do |key|
|
|
60
63
|
raise SeregaError, "Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. No options are allowed"
|
|
@@ -69,6 +72,7 @@ class Serega
|
|
|
69
72
|
#
|
|
70
73
|
# @return [void]
|
|
71
74
|
#
|
|
75
|
+
# @private
|
|
72
76
|
def self.load_plugin(serializer_class, **_opts)
|
|
73
77
|
require_relative "lib/preloader"
|
|
74
78
|
end
|
|
@@ -81,6 +85,7 @@ class Serega
|
|
|
81
85
|
#
|
|
82
86
|
# @return [void]
|
|
83
87
|
#
|
|
88
|
+
# @private
|
|
84
89
|
def self.after_load_plugin(serializer_class, **_opts)
|
|
85
90
|
serializer_class.preload_with do |objects, preloads|
|
|
86
91
|
Preloader.preload(ActiverecordPreloads.records(serializer_class, objects), preloads)
|
|
@@ -98,6 +103,7 @@ class Serega
|
|
|
98
103
|
#
|
|
99
104
|
# @return [Array] the underlying records
|
|
100
105
|
#
|
|
106
|
+
# @private
|
|
101
107
|
def self.records(serializer_class, objects)
|
|
102
108
|
return objects unless serializer_class.plugin_used?(:presenter)
|
|
103
109
|
return objects unless serializer_class.custom_presenter?
|
|
@@ -4,6 +4,7 @@ class Serega
|
|
|
4
4
|
module SeregaPlugins
|
|
5
5
|
module ActiverecordPreloads
|
|
6
6
|
# Handles preloads for different types of initial records
|
|
7
|
+
# @private
|
|
7
8
|
class Preloader
|
|
8
9
|
class << self
|
|
9
10
|
# Preloads associations to records
|
|
@@ -37,6 +38,7 @@ class Serega
|
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
# Associations loader for prepared records
|
|
41
|
+
# @private
|
|
40
42
|
class Loader
|
|
41
43
|
# :nocov: We can check only one version of activerecord
|
|
42
44
|
|
|
@@ -58,6 +60,7 @@ class Serega
|
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
# Preloader adapter for ActiveRecord object
|
|
63
|
+
# @private
|
|
61
64
|
class ActiverecordObject
|
|
62
65
|
class << self
|
|
63
66
|
#
|
|
@@ -84,6 +87,7 @@ class Serega
|
|
|
84
87
|
end
|
|
85
88
|
|
|
86
89
|
# Preloader adapter for ActiveRecord::Relation
|
|
90
|
+
# @private
|
|
87
91
|
class ActiverecordRelation
|
|
88
92
|
class << self
|
|
89
93
|
#
|
|
@@ -111,6 +115,7 @@ class Serega
|
|
|
111
115
|
end
|
|
112
116
|
|
|
113
117
|
# Preloader adapter for Array of ActiveRecord objects
|
|
118
|
+
# @private
|
|
114
119
|
class ActiverecordArray
|
|
115
120
|
class << self
|
|
116
121
|
#
|
|
@@ -146,6 +151,7 @@ class Serega
|
|
|
146
151
|
end
|
|
147
152
|
|
|
148
153
|
# Preloader adapter for Enumerator with ActiveRecord objects
|
|
154
|
+
# @private
|
|
149
155
|
class ActiverecordEnumerator
|
|
150
156
|
class << self
|
|
151
157
|
#
|
|
@@ -5,21 +5,14 @@ class Serega
|
|
|
5
5
|
#
|
|
6
6
|
# Plugin :camel_case
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# CamelCases every attribute name automatically, replacing `_x` with `X`
|
|
9
|
+
# throughout the string. Runs once, when the attribute is defined, not on
|
|
10
|
+
# every serialization.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# for each attribute: `attribute :firstName, method: first_name`
|
|
12
|
+
# Provide a custom transformation with
|
|
13
|
+
# `plugin :camel_case, transform: ->(name) { name.camelize }`.
|
|
15
14
|
#
|
|
16
|
-
#
|
|
17
|
-
# We use simple regular expression to replace `_x` to `X` for the whole string.
|
|
18
|
-
# You can provide your own callable transformation when defining plugin,
|
|
19
|
-
# for example `plugin :camel_case, transform: ->(name) { name.camelize }`
|
|
20
|
-
#
|
|
21
|
-
# For any attribute camelCase-behavior can be skipped when
|
|
22
|
-
# `camel_case: false` attribute option provided.
|
|
15
|
+
# Skip camelCase for a single attribute with `camel_case: false`.
|
|
23
16
|
#
|
|
24
17
|
# @example Define plugin
|
|
25
18
|
# class AppSerializer < Serega
|
|
@@ -44,6 +37,7 @@ class Serega
|
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
# @return [Symbol] Plugin name
|
|
40
|
+
# @private
|
|
47
41
|
def self.plugin_name
|
|
48
42
|
:camel_case
|
|
49
43
|
end
|
|
@@ -55,6 +49,7 @@ class Serega
|
|
|
55
49
|
#
|
|
56
50
|
# @return [void]
|
|
57
51
|
#
|
|
52
|
+
# @private
|
|
58
53
|
def self.before_load_plugin(serializer_class, **opts)
|
|
59
54
|
allowed_keys = %i[transform]
|
|
60
55
|
opts.each_key do |key|
|
|
@@ -74,6 +69,7 @@ class Serega
|
|
|
74
69
|
#
|
|
75
70
|
# @return [void]
|
|
76
71
|
#
|
|
72
|
+
# @private
|
|
77
73
|
def self.load_plugin(serializer_class, **_opts)
|
|
78
74
|
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
|
79
75
|
serializer_class::SeregaAttributeNormalizer.include(AttributeNormalizerInstanceMethods)
|
|
@@ -88,6 +84,7 @@ class Serega
|
|
|
88
84
|
#
|
|
89
85
|
# @return [void]
|
|
90
86
|
#
|
|
87
|
+
# @private
|
|
91
88
|
def self.after_load_plugin(serializer_class, **opts)
|
|
92
89
|
config = serializer_class.config
|
|
93
90
|
config.opts[:camel_case] = {}
|
|
@@ -113,6 +110,7 @@ class Serega
|
|
|
113
110
|
#
|
|
114
111
|
# @see Serega::SeregaValidations::CheckAttributeParams
|
|
115
112
|
#
|
|
113
|
+
# @private
|
|
116
114
|
module CheckAttributeParamsInstanceMethods
|
|
117
115
|
private
|
|
118
116
|
|
|
@@ -125,6 +123,7 @@ class Serega
|
|
|
125
123
|
#
|
|
126
124
|
# Validator for attribute :camel_case option
|
|
127
125
|
#
|
|
126
|
+
# @private
|
|
128
127
|
class CheckOptCamelCase
|
|
129
128
|
class << self
|
|
130
129
|
#
|
|
@@ -191,6 +190,7 @@ class Serega
|
|
|
191
190
|
#
|
|
192
191
|
# @see SeregaAttributeNormalizer::AttributeInstanceMethods
|
|
193
192
|
#
|
|
193
|
+
# @private
|
|
194
194
|
module AttributeNormalizerInstanceMethods
|
|
195
195
|
private
|
|
196
196
|
|
|
@@ -7,7 +7,8 @@ class Serega
|
|
|
7
7
|
#
|
|
8
8
|
# Depends on: `:root` plugin, that must be loaded first
|
|
9
9
|
#
|
|
10
|
-
#
|
|
10
|
+
# Adds metadata supplied per serialization call (as opposed to `:metadata`,
|
|
11
|
+
# which is defined statically on the serializer).
|
|
11
12
|
#
|
|
12
13
|
# @example
|
|
13
14
|
# class UserSerializer < Serega
|
|
@@ -23,6 +24,7 @@ class Serega
|
|
|
23
24
|
DEFAULT_CONTEXT_METADATA_KEY = :meta
|
|
24
25
|
|
|
25
26
|
# @return [Symbol] Plugin name
|
|
27
|
+
# @private
|
|
26
28
|
def self.plugin_name
|
|
27
29
|
:context_metadata
|
|
28
30
|
end
|
|
@@ -34,6 +36,7 @@ class Serega
|
|
|
34
36
|
#
|
|
35
37
|
# @return [void]
|
|
36
38
|
#
|
|
39
|
+
# @private
|
|
37
40
|
def self.before_load_plugin(serializer_class, **opts)
|
|
38
41
|
allowed_keys = %i[context_metadata_key]
|
|
39
42
|
opts.each_key do |key|
|
|
@@ -57,6 +60,7 @@ class Serega
|
|
|
57
60
|
#
|
|
58
61
|
# @return [void]
|
|
59
62
|
#
|
|
63
|
+
# @private
|
|
60
64
|
def self.load_plugin(serializer_class, **_opts)
|
|
61
65
|
serializer_class.include(InstanceMethods)
|
|
62
66
|
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
|
@@ -71,6 +75,7 @@ class Serega
|
|
|
71
75
|
#
|
|
72
76
|
# @return [void]
|
|
73
77
|
#
|
|
78
|
+
# @private
|
|
74
79
|
def self.after_load_plugin(serializer_class, **opts)
|
|
75
80
|
config = serializer_class.config
|
|
76
81
|
meta_key = opts[:context_metadata_key] || DEFAULT_CONTEXT_METADATA_KEY
|
|
@@ -127,6 +132,7 @@ class Serega
|
|
|
127
132
|
#
|
|
128
133
|
# @see Serega::SeregaValidations::CheckSerializeParams
|
|
129
134
|
#
|
|
135
|
+
# @private
|
|
130
136
|
module CheckSerializeParamsInstanceMethods
|
|
131
137
|
private
|
|
132
138
|
|
|
@@ -143,6 +149,7 @@ class Serega
|
|
|
143
149
|
#
|
|
144
150
|
# @see Serega
|
|
145
151
|
#
|
|
152
|
+
# @private
|
|
146
153
|
module InstanceMethods
|
|
147
154
|
private
|
|
148
155
|
|
|
@@ -5,25 +5,23 @@ class Serega
|
|
|
5
5
|
#
|
|
6
6
|
# Plugin :depth_limit
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
8
|
+
# Guards against malicious queries that serialize too much, or against
|
|
9
|
+
# accidentally serializing objects with cyclic relations.
|
|
10
10
|
#
|
|
11
|
-
# Depth limit is checked when
|
|
12
|
-
# `#new`
|
|
13
|
-
#
|
|
14
|
-
#
|
|
11
|
+
# Depth limit is checked when a serialization plan is built, i.e. when
|
|
12
|
+
# `#new` is called (`SomeSerializer.new(with: params[:with])`) — including
|
|
13
|
+
# internally by every class-level serialization method. Instantiating the
|
|
14
|
+
# serializer early surfaces depth errors sooner.
|
|
15
15
|
#
|
|
16
|
-
#
|
|
16
|
+
# When the limit is exceeded, `Serega::DepthLimitError` is raised;
|
|
17
|
+
# details are available via `Serega::DepthLimitError#details`.
|
|
17
18
|
#
|
|
18
|
-
#
|
|
19
|
-
# Depth limit error details can be found in additional `Serega::DepthLimitError#details` method
|
|
20
|
-
#
|
|
21
|
-
# Limit can be checked or changed with next config options:
|
|
19
|
+
# Limit can be checked or changed with config options:
|
|
22
20
|
#
|
|
23
21
|
# - config.depth_limit.limit
|
|
24
22
|
# - config.depth_limit.limit=
|
|
25
23
|
#
|
|
26
|
-
# There
|
|
24
|
+
# There is no default limit — it must be set when enabling the plugin.
|
|
27
25
|
#
|
|
28
26
|
# @example
|
|
29
27
|
#
|
|
@@ -37,6 +35,7 @@ class Serega
|
|
|
37
35
|
#
|
|
38
36
|
module DepthLimit
|
|
39
37
|
# @return [Symbol] Plugin name
|
|
38
|
+
# @private
|
|
40
39
|
def self.plugin_name
|
|
41
40
|
:depth_limit
|
|
42
41
|
end
|
|
@@ -48,6 +47,7 @@ class Serega
|
|
|
48
47
|
#
|
|
49
48
|
# @return [void]
|
|
50
49
|
#
|
|
50
|
+
# @private
|
|
51
51
|
def self.before_load_plugin(serializer_class, **opts)
|
|
52
52
|
allowed_keys = %i[limit]
|
|
53
53
|
opts.each_key do |key|
|
|
@@ -67,6 +67,7 @@ class Serega
|
|
|
67
67
|
#
|
|
68
68
|
# @return [void]
|
|
69
69
|
#
|
|
70
|
+
# @private
|
|
70
71
|
def self.load_plugin(serializer_class, **_opts)
|
|
71
72
|
serializer_class::SeregaPlan.include(PlanInstanceMethods)
|
|
72
73
|
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
|
@@ -80,6 +81,7 @@ class Serega
|
|
|
80
81
|
#
|
|
81
82
|
# @return [void]
|
|
82
83
|
#
|
|
84
|
+
# @private
|
|
83
85
|
def self.after_load_plugin(serializer_class, **opts)
|
|
84
86
|
config = serializer_class.config
|
|
85
87
|
limit = opts.fetch(:limit) { raise SeregaError, "Please provide :limit option. Example: `plugin :depth_limit, limit: 10`" }
|
|
@@ -137,6 +139,7 @@ class Serega
|
|
|
137
139
|
#
|
|
138
140
|
# @see SeregaPlan
|
|
139
141
|
#
|
|
142
|
+
# @private
|
|
140
143
|
module PlanInstanceMethods
|
|
141
144
|
#
|
|
142
145
|
# Initializes serialization plan
|
|
@@ -5,29 +5,29 @@ class Serega
|
|
|
5
5
|
#
|
|
6
6
|
# Plugin :explicit_many_option
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# Adding this plugin makes it clearer to find if relationship returns array or single object
|
|
8
|
+
# Requires the `:many` option on every relationship attribute (an
|
|
9
|
+
# attribute with the `:serializer` option or a block defining a nested
|
|
10
|
+
# serializer), so it's always explicit whether it returns one object or many.
|
|
13
11
|
#
|
|
14
12
|
# @example
|
|
15
13
|
# class BaseSerializer < Serega
|
|
16
14
|
# plugin :explicit_many_option
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# class UserSerializer < BaseSerializer
|
|
20
|
-
# attribute :name
|
|
15
|
+
# config.base_serializer = self
|
|
21
16
|
# end
|
|
22
17
|
#
|
|
23
18
|
# class PostSerializer < BaseSerializer
|
|
24
19
|
# attribute :text
|
|
25
|
-
#
|
|
20
|
+
#
|
|
21
|
+
# attribute :user, many: false do
|
|
22
|
+
# attribute :name
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
26
25
|
# attribute :comments, serializer: PostSerializer, many: true
|
|
27
26
|
# end
|
|
28
27
|
#
|
|
29
28
|
module ExplicitManyOption
|
|
30
29
|
# @return [Symbol] Plugin name
|
|
30
|
+
# @private
|
|
31
31
|
def self.plugin_name
|
|
32
32
|
:explicit_many_option
|
|
33
33
|
end
|
|
@@ -40,6 +40,7 @@ class Serega
|
|
|
40
40
|
#
|
|
41
41
|
# @return [void]
|
|
42
42
|
#
|
|
43
|
+
# @private
|
|
43
44
|
def self.load_plugin(serializer_class, **_opts)
|
|
44
45
|
require_relative "validations/check_opt_many"
|
|
45
46
|
|
|
@@ -51,6 +52,7 @@ class Serega
|
|
|
51
52
|
#
|
|
52
53
|
# @see Serega::SeregaValidations::CheckAttributeParams
|
|
53
54
|
#
|
|
55
|
+
# @private
|
|
54
56
|
module CheckAttributeParamsInstanceMethods
|
|
55
57
|
private
|
|
56
58
|
|
|
@@ -5,20 +5,19 @@ class Serega
|
|
|
5
5
|
#
|
|
6
6
|
# Plugin :formatters
|
|
7
7
|
#
|
|
8
|
-
#
|
|
8
|
+
# Defines named value formatters once and applies them to any attribute.
|
|
9
9
|
#
|
|
10
|
-
#
|
|
10
|
+
# Use `config.formatters.add()` to register formatters. The `:format`
|
|
11
|
+
# attribute option then accepts a formatter name or a callable directly.
|
|
11
12
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# Formatters can accept up to 2 parameters (formatted object, context)
|
|
13
|
+
# Formatters receive up to 2 parameters: the value and the context.
|
|
15
14
|
#
|
|
16
15
|
# @example
|
|
17
16
|
# class AppSerializer < Serega
|
|
18
17
|
# plugin :formatters, formatters: {
|
|
19
|
-
# iso8601: ->(value) {
|
|
18
|
+
# iso8601: ->(value) { value.iso8601 },
|
|
20
19
|
# on_off: ->(value) { value ? 'ON' : 'OFF' },
|
|
21
|
-
# money: ->(value) { value.round(2) }
|
|
20
|
+
# money: ->(value) { value.round(2) },
|
|
22
21
|
# date: DateTypeFormatter # callable
|
|
23
22
|
# }
|
|
24
23
|
# end
|
|
@@ -26,24 +25,25 @@ class Serega
|
|
|
26
25
|
# class UserSerializer < Serega
|
|
27
26
|
# # Additionally we can add formatters via config in subclasses
|
|
28
27
|
# config.formatters.add(
|
|
29
|
-
# iso8601: ->(value) {
|
|
28
|
+
# iso8601: ->(value) { value.iso8601 },
|
|
30
29
|
# on_off: ->(value) { value ? 'ON' : 'OFF' },
|
|
31
30
|
# money: ->(value) { value.round(2) }
|
|
32
31
|
# )
|
|
33
32
|
#
|
|
34
33
|
# # Using predefined formatter
|
|
35
34
|
# attribute :commission, format: :money
|
|
36
|
-
# attribute :
|
|
35
|
+
# attribute :is_logged_in, format: :on_off
|
|
37
36
|
# attribute :created_at, format: :iso8601
|
|
38
37
|
# attribute :updated_at, format: :iso8601
|
|
39
38
|
#
|
|
40
39
|
# # Using `callable` formatter
|
|
41
|
-
# attribute :score_percent, format:
|
|
40
|
+
# attribute :score_percent, format: PercentFormatter # callable class
|
|
42
41
|
# attribute :score_percent, format: proc { |percent| "#{percent.round(2)}%" }
|
|
43
42
|
# end
|
|
44
43
|
#
|
|
45
44
|
module Formatters
|
|
46
45
|
# @return [Symbol] Plugin name
|
|
46
|
+
# @private
|
|
47
47
|
def self.plugin_name
|
|
48
48
|
:formatters
|
|
49
49
|
end
|
|
@@ -55,6 +55,7 @@ class Serega
|
|
|
55
55
|
#
|
|
56
56
|
# @return [void]
|
|
57
57
|
#
|
|
58
|
+
# @private
|
|
58
59
|
def self.before_load_plugin(serializer_class, **opts)
|
|
59
60
|
allowed_keys = %i[formatters]
|
|
60
61
|
opts.each_key do |key|
|
|
@@ -74,6 +75,7 @@ class Serega
|
|
|
74
75
|
#
|
|
75
76
|
# @return [void]
|
|
76
77
|
#
|
|
78
|
+
# @private
|
|
77
79
|
def self.load_plugin(serializer_class, **_opts)
|
|
78
80
|
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
|
79
81
|
serializer_class::SeregaAttributeNormalizer.include(AttributeNormalizerInstanceMethods)
|
|
@@ -89,6 +91,7 @@ class Serega
|
|
|
89
91
|
#
|
|
90
92
|
# @return [void]
|
|
91
93
|
#
|
|
94
|
+
# @private
|
|
92
95
|
def self.after_load_plugin(serializer_class, **opts)
|
|
93
96
|
config = serializer_class.config
|
|
94
97
|
config.opts[:formatters] = {}
|
|
@@ -141,6 +144,7 @@ class Serega
|
|
|
141
144
|
#
|
|
142
145
|
# @see Serega::SeregaValidations::CheckAttributeParams
|
|
143
146
|
#
|
|
147
|
+
# @private
|
|
144
148
|
module CheckAttributeParamsInstanceMethods
|
|
145
149
|
private
|
|
146
150
|
|
|
@@ -156,6 +160,7 @@ class Serega
|
|
|
156
160
|
#
|
|
157
161
|
# @see SeregaAttributeNormalizer
|
|
158
162
|
#
|
|
163
|
+
# @private
|
|
159
164
|
module AttributeNormalizerInstanceMethods
|
|
160
165
|
# Block or callable instance that will format attribute values
|
|
161
166
|
# @return [Proc, #call, nil] Block or callable instance that will format attribute values
|
|
@@ -194,6 +199,7 @@ class Serega
|
|
|
194
199
|
#
|
|
195
200
|
# @see SeregaAttribute
|
|
196
201
|
#
|
|
202
|
+
# @private
|
|
197
203
|
module AttributeInstanceMethods
|
|
198
204
|
#
|
|
199
205
|
# Returns formatted attribute value
|
|
@@ -229,6 +235,7 @@ class Serega
|
|
|
229
235
|
#
|
|
230
236
|
# Validator for attribute :format option
|
|
231
237
|
#
|
|
238
|
+
# @private
|
|
232
239
|
class CheckOptFormat
|
|
233
240
|
class << self
|
|
234
241
|
#
|
|
@@ -265,6 +272,7 @@ class Serega
|
|
|
265
272
|
#
|
|
266
273
|
# Validator for formatters defined as config options or directly as attribute :format option
|
|
267
274
|
#
|
|
275
|
+
# @private
|
|
268
276
|
class CheckFormatter
|
|
269
277
|
class << self
|
|
270
278
|
#
|