serega 0.40.0 → 0.40.1
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 +90 -107
- 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 +10 -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 +6 -0
- metadata +13 -16
|
@@ -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
|
#
|
data/lib/serega/plugins/if/if.rb
CHANGED
|
@@ -3,46 +3,34 @@
|
|
|
3
3
|
class Serega
|
|
4
4
|
module SeregaPlugins
|
|
5
5
|
#
|
|
6
|
-
# Plugin
|
|
7
|
-
# attributes so we can remove attributes from response in various ways.
|
|
6
|
+
# Plugin :if
|
|
8
7
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# Adds `:if`, `:unless`, `:if_value`, `:unless_value` attribute options to
|
|
9
|
+
# conditionally remove attributes from the response.
|
|
11
10
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
11
|
+
# `:if`/`:unless` receive the serialized object and context, and are
|
|
12
|
+
# checked before the attribute value is found. `:if_value`/`:unless_value`
|
|
13
|
+
# receive the already-found value and context, checked after. The latter
|
|
14
|
+
# two cannot be used with the `:serializer` option, since a relationship
|
|
15
|
+
# has no "serialized value" of its own — use `:if`/`:unless` instead.
|
|
14
16
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
+
# See also the plugin-free `:hide` option (README.md#selecting-fields),
|
|
18
|
+
# which hides an attribute unconditionally.
|
|
17
19
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
+
# @example
|
|
21
|
+
# class UserSerializer < Serega
|
|
22
|
+
# attribute :email, if: :active? # if user.active?
|
|
23
|
+
# attribute :email, if: proc { |user, ctx| user == ctx[:current_user] } # using context
|
|
24
|
+
# attribute :email, if: CustomPolicy.method(:view_email?) # any callable
|
|
20
25
|
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# attribute :email, if: proc {|user, ctx| user == ctx[:current_user]} # using context
|
|
26
|
-
# attribute :email, if: CustomPolicy.method(:view_email?) # You can provide own callable object
|
|
27
|
-
#
|
|
28
|
-
# attribute :email, unless: :hidden? # unless user.hidden?
|
|
29
|
-
# attribute :email, unless: proc {|user| user.hidden?} # same
|
|
30
|
-
# attribute :email, unless: proc {|user, context| context[:show_emails]} # using context
|
|
31
|
-
# attribute :email, unless: CustomPolicy.method(:hide_email?) # You can provide own callable object
|
|
32
|
-
#
|
|
33
|
-
# attribute :email, if_value: :present? # if email.present?
|
|
34
|
-
# attribute :email, if_value: proc {|email| email.present?} # same
|
|
35
|
-
# attribute :email, if_value: proc {|email, ctx| ctx[:show_emails]} # using context
|
|
36
|
-
# attribute :email, if_value: CustomPolicy.method(:view_email?) # You can provide own callable object
|
|
37
|
-
#
|
|
38
|
-
# attribute :email, unless_value: :blank? # unless email.blank?
|
|
39
|
-
# attribute :email, unless_value: proc {|email| email.blank?} # same
|
|
40
|
-
# attribute :email, unless_value: proc {|email, context| context[:show_emails]} # using context
|
|
41
|
-
# attribute :email, unless_value: CustomPolicy.method(:hide_email?) # You can provide own callable object
|
|
42
|
-
# end
|
|
26
|
+
# attribute :email, unless: :hidden? # unless user.hidden?
|
|
27
|
+
# attribute :email, if_value: :present? # if email.present?
|
|
28
|
+
# attribute :email, unless_value: :blank? # unless email.blank?
|
|
29
|
+
# end
|
|
43
30
|
#
|
|
44
31
|
module If
|
|
45
32
|
# @return [Symbol] Plugin name
|
|
33
|
+
# @private
|
|
46
34
|
def self.plugin_name
|
|
47
35
|
:if
|
|
48
36
|
end
|
|
@@ -55,6 +43,7 @@ class Serega
|
|
|
55
43
|
#
|
|
56
44
|
# @return [void]
|
|
57
45
|
#
|
|
46
|
+
# @private
|
|
58
47
|
def self.load_plugin(serializer_class, **_opts)
|
|
59
48
|
require_relative "validations/check_opt_if"
|
|
60
49
|
require_relative "validations/check_opt_if_value"
|
|
@@ -77,6 +66,7 @@ class Serega
|
|
|
77
66
|
#
|
|
78
67
|
# @return [void]
|
|
79
68
|
#
|
|
69
|
+
# @private
|
|
80
70
|
def self.after_load_plugin(serializer_class, **opts)
|
|
81
71
|
serializer_class.config.attribute_keys << :if << :if_value << :unless << :unless_value
|
|
82
72
|
end
|
|
@@ -86,6 +76,7 @@ class Serega
|
|
|
86
76
|
#
|
|
87
77
|
# @see SeregaAttributeNormalizer::AttributeInstanceMethods
|
|
88
78
|
#
|
|
79
|
+
# @private
|
|
89
80
|
module AttributeNormalizerInstanceMethods
|
|
90
81
|
#
|
|
91
82
|
# Returns prepared attribute :if_options.
|
|
@@ -135,6 +126,7 @@ class Serega
|
|
|
135
126
|
#
|
|
136
127
|
# Resolves keyword-based conditions for if/unless options
|
|
137
128
|
#
|
|
129
|
+
# @private
|
|
138
130
|
class KeywordConditionResolver
|
|
139
131
|
def initialize(keyword)
|
|
140
132
|
@keyword = keyword
|
|
@@ -156,6 +148,7 @@ class Serega
|
|
|
156
148
|
#
|
|
157
149
|
# @see Serega::SeregaAttribute
|
|
158
150
|
#
|
|
151
|
+
# @private
|
|
159
152
|
module AttributeInstanceMethods
|
|
160
153
|
# @return [Hash] provided :if options
|
|
161
154
|
attr_reader :opt_if
|
|
@@ -177,6 +170,7 @@ class Serega
|
|
|
177
170
|
#
|
|
178
171
|
# @see Serega::SeregaPlanPoint::InstanceMethods
|
|
179
172
|
#
|
|
173
|
+
# @private
|
|
180
174
|
module PlanPointInstanceMethods
|
|
181
175
|
#
|
|
182
176
|
# @return [Boolean] Should we show attribute or not
|
|
@@ -225,6 +219,7 @@ class Serega
|
|
|
225
219
|
#
|
|
226
220
|
# @see Serega::SeregaValidations::CheckAttributeParams
|
|
227
221
|
#
|
|
222
|
+
# @private
|
|
228
223
|
module CheckAttributeParamsInstanceMethods
|
|
229
224
|
private
|
|
230
225
|
|
|
@@ -247,6 +242,7 @@ class Serega
|
|
|
247
242
|
#
|
|
248
243
|
# @see Serega::SeregaDataBuilder
|
|
249
244
|
#
|
|
245
|
+
# @private
|
|
250
246
|
module DataBuilderClassMethods
|
|
251
247
|
private
|
|
252
248
|
|
|
@@ -264,6 +260,7 @@ class Serega
|
|
|
264
260
|
#
|
|
265
261
|
# @see Serega::SeregaObjectSerializer
|
|
266
262
|
#
|
|
263
|
+
# @private
|
|
267
264
|
module ObjectSerializerInstanceMethods
|
|
268
265
|
private
|
|
269
266
|
|