serega 0.9.0 → 0.10.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 +17 -0
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +9 -1
- data/lib/serega/config.rb +16 -0
- data/lib/serega/object_serializer.rb +8 -0
- data/lib/serega/plugins/batch/batch.rb +2 -5
- data/lib/serega/plugins/batch/lib/loader.rb +3 -0
- data/lib/serega/plugins/if/if.rb +0 -13
- data/lib/serega/plugins/metadata/meta_attribute.rb +10 -2
- data/lib/serega/plugins/metadata/metadata.rb +15 -13
- data/lib/serega/plugins/metadata/validations/check_path.rb +10 -17
- data/lib/serega/plugins/preloads/preloads.rb +2 -0
- data/lib/serega/plugins/presenter/presenter.rb +10 -8
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +46 -57
- data/lib/serega/plugins/string_modifiers/string_modifiers.rb +3 -7
- data/lib/serega/utils/enum_deep_dup.rb +2 -2
- data/lib/serega/validations/attribute/check_name.rb +8 -21
- data/lib/serega/validations/check_attribute_params.rb +10 -1
- data/lib/serega.rb +72 -48
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a94d74dd45c74e499cd1a3abec082d8776019538b67bf24fc840512271adb6b
|
4
|
+
data.tar.gz: a22bc547e6ac94b0988e2cfef2af31ad659beb53058a90159e7f46f6470c3390
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d89c6180d4af0273eee6dd6179a0ac6f0157409f07ae6c18985941ecd8971bd17eb8b547a764d97afd12cdc08e565cb8749e9d9e0a70d8ab8add5dbad3e349db
|
7
|
+
data.tar.gz: 4cd808491f38a469ac705f6884007a3d71cead7f12d8e9730ec8c15ee1da97cb2d0d7503aafc0925a5bf41c7b660f7aa71a62da6fda295e713b62114ee83842a
|
data/README.md
CHANGED
@@ -111,6 +111,23 @@ class UserSerializer < Serega
|
|
111
111
|
end
|
112
112
|
```
|
113
113
|
|
114
|
+
---
|
115
|
+
|
116
|
+
⚠️ Attribute names are checked to include only "a-z", "A-Z", "0-9", "_", "-", "~" characters.
|
117
|
+
We have this check as:
|
118
|
+
- Attributes names can be used in URL without encoding.
|
119
|
+
- Plugin [string_modifiers][string_modifiers] already uses "," and "()" as attribute names delimeters.
|
120
|
+
- We are protected from errors when added some non-english character looking as english.
|
121
|
+
|
122
|
+
This names check can be disabled globally or per-serializer via:
|
123
|
+
```ruby
|
124
|
+
Serega.config.check_attribute_name = false
|
125
|
+
|
126
|
+
class SomeSerializer < Serega
|
127
|
+
config.check_attribute_name = false
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
114
131
|
### Serializing
|
115
132
|
|
116
133
|
We can serialize objects using class methods `.to_h`, `.to_json`, `.as_json` and same instance methods `#to_h`, `#to_json`, `#as_json`.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|
data/lib/serega/attribute.rb
CHANGED
@@ -51,6 +51,10 @@ class Serega
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# Shows current opts[:hide] option
|
54
|
+
#
|
55
|
+
# Patched in:
|
56
|
+
# - plugin :preloads (returns true by default if config option auto_hide_attribute_with_preloads is enabled)
|
57
|
+
#
|
54
58
|
# @return [Boolean, nil] Attribute :hide option value
|
55
59
|
def hide
|
56
60
|
opts[:hide]
|
@@ -82,7 +86,11 @@ class Serega
|
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
|
-
# Returns final block
|
89
|
+
# Returns final block used to find attribute value
|
90
|
+
#
|
91
|
+
# Patched in:
|
92
|
+
# - plugin :formatters (wraps resulted block in formatter block and formats :const values)
|
93
|
+
#
|
86
94
|
# @return [Proc] Proc to find attribute value
|
87
95
|
def value_block
|
88
96
|
return @value_block if instance_variable_defined?(:@value_block)
|
data/lib/serega/config.rb
CHANGED
@@ -17,6 +17,7 @@ class Serega
|
|
17
17
|
initiate_keys: %i[only with except check_initiate_params].freeze,
|
18
18
|
attribute_keys: %i[key value serializer many hide const delegate].freeze,
|
19
19
|
serialize_keys: %i[context many].freeze,
|
20
|
+
check_attribute_name: true,
|
20
21
|
check_initiate_params: true,
|
21
22
|
max_cached_map_per_serializer_count: 0,
|
22
23
|
to_json: (SeregaJSON.adapter == :oj) ? SeregaJSON::OjDump : SeregaJSON::JSONDump,
|
@@ -102,6 +103,21 @@ class Serega
|
|
102
103
|
opts[:max_cached_map_per_serializer_count] = value
|
103
104
|
end
|
104
105
|
|
106
|
+
# Returns whether attributes names check is disabled
|
107
|
+
def check_attribute_name
|
108
|
+
opts.fetch(:check_attribute_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Sets :check_attribute_name config option
|
112
|
+
#
|
113
|
+
# @param value [Boolean] Set :check_attribute_name config option
|
114
|
+
#
|
115
|
+
# @return [Boolean] New :check_attribute_name config option
|
116
|
+
def check_attribute_name=(value)
|
117
|
+
raise SeregaError, "Must have boolean value, #{value.inspect} provided" if (value != true) && (value != false)
|
118
|
+
opts[:check_attribute_name] = value
|
119
|
+
end
|
120
|
+
|
105
121
|
# Returns current `to_json` adapter
|
106
122
|
# @return [#call] Callable that used to construct JSON
|
107
123
|
def to_json
|
@@ -41,22 +41,30 @@ class Serega
|
|
41
41
|
object.map { |obj| serialize_object(obj) }
|
42
42
|
end
|
43
43
|
|
44
|
+
# Patched in:
|
45
|
+
# - plugin :presenter (makes presenter_object and serializes it)
|
44
46
|
def serialize_object(object)
|
45
47
|
points.each_with_object({}) do |point, container|
|
46
48
|
serialize_point(object, point, container)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
# Patched in:
|
53
|
+
# - plugin :if (conditionally skips serializing this point)
|
50
54
|
def serialize_point(object, point, container)
|
51
55
|
attach_value(object, point, container)
|
52
56
|
end
|
53
57
|
|
58
|
+
# Patched in:
|
59
|
+
# - plugin :batch (remembers key for batch loading values instead of attaching)
|
54
60
|
def attach_value(object, point, container)
|
55
61
|
value = point.value(object, context)
|
56
62
|
final_value = final_value(value, point)
|
57
63
|
attach_final_value(final_value, point, container)
|
58
64
|
end
|
59
65
|
|
66
|
+
# Patched in:
|
67
|
+
# - plugin :if (conditionally skips attaching)
|
60
68
|
def attach_final_value(final_value, point, container)
|
61
69
|
container[point.name] = final_value
|
62
70
|
end
|
@@ -262,12 +262,9 @@ class Serega
|
|
262
262
|
|
263
263
|
def attach_value(object, point, container)
|
264
264
|
batch = point.batch
|
265
|
+
return super unless batch
|
265
266
|
|
266
|
-
|
267
|
-
remember_key_for_batch_loading(batch, object, point, container)
|
268
|
-
else
|
269
|
-
super
|
270
|
-
end
|
267
|
+
remember_key_for_batch_loading(batch, object, point, container)
|
271
268
|
end
|
272
269
|
|
273
270
|
def remember_key_for_batch_loading(batch, object, point, container)
|
data/lib/serega/plugins/if/if.rb
CHANGED
@@ -66,19 +66,6 @@ class Serega
|
|
66
66
|
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
67
67
|
end
|
68
68
|
|
69
|
-
# Checks requirements and loads additional plugins
|
70
|
-
#
|
71
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
72
|
-
# @param opts [Hash] loaded plugins opts
|
73
|
-
#
|
74
|
-
# @return [void]
|
75
|
-
#
|
76
|
-
def self.before_load_plugin(serializer_class, **opts)
|
77
|
-
if serializer_class.plugin_used?(:batch)
|
78
|
-
raise SeregaError, "Plugin `#{plugin_name}` must be loaded before `batch`"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
69
|
#
|
83
70
|
# Adds config options and runs other callbacks after plugin was loaded
|
84
71
|
#
|
@@ -60,10 +60,18 @@ class Serega
|
|
60
60
|
private
|
61
61
|
|
62
62
|
def check(path, opts, block)
|
63
|
-
CheckPath.call(path)
|
64
|
-
CheckOpts.call(opts,
|
63
|
+
CheckPath.call(path) if check_attribute_name
|
64
|
+
CheckOpts.call(opts, attribute_keys)
|
65
65
|
CheckBlock.call(block)
|
66
66
|
end
|
67
|
+
|
68
|
+
def attribute_keys
|
69
|
+
self.class.serializer_class.config.metadata.attribute_keys
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_attribute_name
|
73
|
+
self.class.serializer_class.config.check_attribute_name
|
74
|
+
end
|
67
75
|
end
|
68
76
|
|
69
77
|
extend Serega::SeregaHelpers::SerializerClassHelper
|
@@ -130,19 +130,6 @@ class Serega
|
|
130
130
|
# @see Serega::SeregaConfig
|
131
131
|
#
|
132
132
|
module ClassMethods
|
133
|
-
private def inherited(subclass)
|
134
|
-
super
|
135
|
-
|
136
|
-
meta_attribute_class = Class.new(self::MetaAttribute)
|
137
|
-
meta_attribute_class.serializer_class = subclass
|
138
|
-
subclass.const_set(:MetaAttribute, meta_attribute_class)
|
139
|
-
|
140
|
-
# Assign same metadata attributes
|
141
|
-
meta_attributes.each_value do |attr|
|
142
|
-
subclass.meta_attribute(*attr.path, **attr.opts, &attr.block)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
133
|
#
|
147
134
|
# List of added metadata attributes
|
148
135
|
#
|
@@ -165,6 +152,21 @@ class Serega
|
|
165
152
|
attribute = self::MetaAttribute.new(path: path, opts: opts, block: block)
|
166
153
|
meta_attributes[attribute.name] = attribute
|
167
154
|
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def inherited(subclass)
|
159
|
+
super
|
160
|
+
|
161
|
+
meta_attribute_class = Class.new(self::MetaAttribute)
|
162
|
+
meta_attribute_class.serializer_class = subclass
|
163
|
+
subclass.const_set(:MetaAttribute, meta_attribute_class)
|
164
|
+
|
165
|
+
# Assign same metadata attributes
|
166
|
+
meta_attributes.each_value do |attr|
|
167
|
+
subclass.meta_attribute(*attr.path, **attr.opts, &attr.block)
|
168
|
+
end
|
169
|
+
end
|
168
170
|
end
|
169
171
|
|
170
172
|
#
|
@@ -8,16 +8,15 @@ class Serega
|
|
8
8
|
# Validator for meta_attribute :path parameter
|
9
9
|
#
|
10
10
|
class CheckPath
|
11
|
-
|
12
|
-
|
11
|
+
# Regexp for valid path
|
12
|
+
FORMAT = /\A[\w~-]+\z/
|
13
13
|
|
14
|
-
private_constant :
|
14
|
+
private_constant :FORMAT
|
15
15
|
|
16
16
|
class << self
|
17
17
|
#
|
18
|
-
# Checks allowed characters
|
19
|
-
#
|
20
|
-
# Minus and low line "-", "_" also allowed except as the first or last character.
|
18
|
+
# Checks allowed characters.
|
19
|
+
# Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~".
|
21
20
|
#
|
22
21
|
# @param path [Array<String, Symbol>] Metadata attribute path names
|
23
22
|
#
|
@@ -33,20 +32,14 @@ class Serega
|
|
33
32
|
def check_name(name)
|
34
33
|
name = name.to_s
|
35
34
|
|
36
|
-
|
37
|
-
case name.size
|
38
|
-
when 0 then false
|
39
|
-
when 1 then name.match?(FORMAT_ONE_CHAR)
|
40
|
-
else name.match?(FORMAT_MANY_CHARS)
|
41
|
-
end
|
42
|
-
|
43
|
-
return if valid
|
44
|
-
|
45
|
-
raise SeregaError, message(name)
|
35
|
+
raise SeregaError, message(name) unless FORMAT.match?(name)
|
46
36
|
end
|
47
37
|
|
48
38
|
def message(name)
|
49
|
-
|
39
|
+
<<~MESSAGE.tr("\n", "")
|
40
|
+
Invalid metadata path #{name.inspect}.
|
41
|
+
Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~"
|
42
|
+
MESSAGE
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
@@ -235,6 +235,8 @@ class Serega
|
|
235
235
|
@auto_hide_attribute_with_preloads = auto && !preloads.nil? && (preloads != false) && (preloads != {})
|
236
236
|
end
|
237
237
|
|
238
|
+
# Patched in:
|
239
|
+
# - plugin :batch (extension :preloads - skips auto preloads when batch option provided)
|
238
240
|
def get_preloads
|
239
241
|
preloads_provided = opts.key?(:preload)
|
240
242
|
preloads =
|
@@ -80,14 +80,6 @@ class Serega
|
|
80
80
|
# @see Serega
|
81
81
|
#
|
82
82
|
module ClassMethods
|
83
|
-
private def inherited(subclass)
|
84
|
-
super
|
85
|
-
|
86
|
-
presenter_class = Class.new(self::Presenter)
|
87
|
-
presenter_class.serializer_class = subclass
|
88
|
-
subclass.const_set(:Presenter, presenter_class)
|
89
|
-
end
|
90
|
-
|
91
83
|
# Overrides {Serega::ClassMethods#attribute} method, additionally adds method
|
92
84
|
# to Presenter to not hit {Serega::SeregaPlugins::Presenter::Presenter#method_missing}
|
93
85
|
# @see Serega::ClassMethods#attribute
|
@@ -96,6 +88,16 @@ class Serega
|
|
96
88
|
self::Presenter.def_delegator(:__getobj__, attribute.key) unless attribute.block
|
97
89
|
end
|
98
90
|
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def inherited(subclass)
|
95
|
+
super
|
96
|
+
|
97
|
+
presenter_class = Class.new(self::Presenter)
|
98
|
+
presenter_class.serializer_class = subclass
|
99
|
+
subclass.const_set(:Presenter, presenter_class)
|
100
|
+
end
|
99
101
|
end
|
100
102
|
|
101
103
|
#
|
@@ -25,72 +25,61 @@ class Serega
|
|
25
25
|
# Modifiers parser
|
26
26
|
#
|
27
27
|
class ParseStringModifiers
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
class << self
|
29
|
+
#
|
30
|
+
# Parses string modifiers
|
31
|
+
#
|
32
|
+
# @param fields [String]
|
33
|
+
#
|
34
|
+
# @return [Hash] parsed modifiers in form of nested hash
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# parse("user") => { user: {} }
|
38
|
+
# parse("user(id)") => { user: { id: {} } }
|
39
|
+
# parse("user(id,name)") => { user: { id: {}, name: {} } }
|
40
|
+
# parse("user,comments") => { user: {}, comments: {} }
|
41
|
+
# parse("user(comments(text))") => { user: { comments: { text: {} } } }
|
42
|
+
def parse(fields)
|
43
|
+
res = {}
|
44
|
+
attribute = +""
|
45
|
+
char = +""
|
46
|
+
path_stack = nil
|
47
|
+
fields = StringIO.new(fields)
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# parse("user(id,name)") => { user: { id: {}, name: {} } }
|
52
|
-
# parse("user,comments") => { user: {}, comments: {} }
|
53
|
-
# parse("user(comments(text))") => { user: { comments: { text: {} } } }
|
54
|
-
def parse(fields)
|
55
|
-
res = {}
|
56
|
-
attribute = +""
|
57
|
-
char = +""
|
58
|
-
path_stack = nil
|
59
|
-
fields = StringIO.new(fields)
|
60
|
-
|
61
|
-
while fields.read(1, char)
|
62
|
-
case char
|
63
|
-
when ","
|
64
|
-
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
65
|
-
when ")"
|
66
|
-
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
67
|
-
path_stack&.pop
|
68
|
-
when "("
|
69
|
-
name = add_attribute(res, path_stack, attribute, {})
|
70
|
-
(path_stack ||= []).push(name) if name
|
71
|
-
else
|
72
|
-
attribute.insert(-1, char)
|
49
|
+
while fields.read(1, char)
|
50
|
+
case char
|
51
|
+
when ","
|
52
|
+
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
53
|
+
when ")"
|
54
|
+
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
55
|
+
path_stack&.pop
|
56
|
+
when "("
|
57
|
+
name = add_attribute(res, path_stack, attribute, {})
|
58
|
+
(path_stack ||= []).push(name) if name
|
59
|
+
else
|
60
|
+
attribute.insert(-1, char)
|
61
|
+
end
|
73
62
|
end
|
74
|
-
end
|
75
63
|
|
76
|
-
|
64
|
+
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
77
65
|
|
78
|
-
|
79
|
-
|
66
|
+
res
|
67
|
+
end
|
80
68
|
|
81
|
-
|
69
|
+
private
|
82
70
|
|
83
|
-
|
84
|
-
|
85
|
-
|
71
|
+
def add_attribute(res, path_stack, attribute, nested_attributes = FROZEN_EMPTY_HASH)
|
72
|
+
attribute.strip!
|
73
|
+
return if attribute.empty?
|
86
74
|
|
87
|
-
|
88
|
-
|
75
|
+
name = attribute.to_sym
|
76
|
+
attribute.clear
|
89
77
|
|
90
|
-
|
91
|
-
|
78
|
+
current_attrs = (!path_stack || path_stack.empty?) ? res : res.dig(*path_stack)
|
79
|
+
current_attrs[name] = nested_attributes
|
92
80
|
|
93
|
-
|
81
|
+
name
|
82
|
+
end
|
94
83
|
end
|
95
84
|
end
|
96
85
|
end
|
@@ -29,14 +29,10 @@ class Serega
|
|
29
29
|
module InstanceMethods
|
30
30
|
private
|
31
31
|
|
32
|
-
def
|
33
|
-
|
34
|
-
opts.each_with_object({}) do |(key, value), obj|
|
35
|
-
value = ParseStringModifiers.call(value) if (key == :only) || (key == :except) || (key == :with)
|
36
|
-
obj[key] = value
|
37
|
-
end
|
32
|
+
def parse_modifier(value)
|
33
|
+
return ParseStringModifiers.parse(value) if value.is_a?(String)
|
38
34
|
|
39
|
-
super
|
35
|
+
super
|
40
36
|
end
|
41
37
|
end
|
42
38
|
end
|
@@ -38,8 +38,8 @@ class Serega
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def dup_array_values(duplicate_data)
|
41
|
-
duplicate_data.
|
42
|
-
|
41
|
+
duplicate_data.map! do |value|
|
42
|
+
value.is_a?(Enumerable) ? call(value) : value
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -7,19 +7,13 @@ class Serega
|
|
7
7
|
# Attribute `name` parameter validator
|
8
8
|
#
|
9
9
|
class CheckName
|
10
|
-
# Regexp for valid
|
11
|
-
|
12
|
-
|
13
|
-
# Regexp for valid multi-chars attribute name
|
14
|
-
FORMAT_MANY_CHARS = /\A[a-zA-Z0-9][a-zA-Z0-9_-]*?[a-zA-Z0-9]\z/ # allow '-' and '_' in the middle
|
15
|
-
|
16
|
-
private_constant :FORMAT_ONE_CHAR, :FORMAT_MANY_CHARS
|
10
|
+
# Regexp for valid attribute name
|
11
|
+
FORMAT = /\A[\w~-]+\z/
|
17
12
|
|
18
13
|
class << self
|
19
14
|
#
|
20
15
|
# Checks allowed characters.
|
21
|
-
#
|
22
|
-
# Minus and low line "-", "_" also allowed except as the first or last character.
|
16
|
+
# Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~".
|
23
17
|
#
|
24
18
|
# @param name [String, Symbol] Attribute name
|
25
19
|
#
|
@@ -28,23 +22,16 @@ class Serega
|
|
28
22
|
#
|
29
23
|
def call(name)
|
30
24
|
name = SeregaUtils::SymbolName.call(name)
|
31
|
-
|
32
|
-
valid =
|
33
|
-
case name.size
|
34
|
-
when 0 then false
|
35
|
-
when 1 then name.match?(FORMAT_ONE_CHAR)
|
36
|
-
else name.match?(FORMAT_MANY_CHARS)
|
37
|
-
end
|
38
|
-
|
39
|
-
return if valid
|
40
|
-
|
41
|
-
raise SeregaError, message(name)
|
25
|
+
raise SeregaError, message(name) unless FORMAT.match?(name)
|
42
26
|
end
|
43
27
|
|
44
28
|
private
|
45
29
|
|
46
30
|
def message(name)
|
47
|
-
|
31
|
+
<<~MESSAGE.tr("\n", "")
|
32
|
+
Invalid attribute name = #{name.inspect}.
|
33
|
+
Allowed characters: "a-z", "A-Z", "0-9", "_", "-", "~"
|
34
|
+
MESSAGE
|
48
35
|
end
|
49
36
|
end
|
50
37
|
end
|
@@ -41,7 +41,7 @@ class Serega
|
|
41
41
|
# Validates attribute params
|
42
42
|
#
|
43
43
|
def validate
|
44
|
-
check_name
|
44
|
+
check_name if check_attribute_name
|
45
45
|
check_opts
|
46
46
|
check_block
|
47
47
|
end
|
@@ -52,6 +52,11 @@ class Serega
|
|
52
52
|
Attribute::CheckName.call(name)
|
53
53
|
end
|
54
54
|
|
55
|
+
# Patched in:
|
56
|
+
# - plugin :batch (checks :batch option)
|
57
|
+
# - plugin :context_metadata (checks context metadata option which is :meta by default)
|
58
|
+
# - plugin :if (checks :if, :if_value, :unless, :unless_value options)
|
59
|
+
# - plugin :preloads (checks :preload option)
|
55
60
|
def check_opts
|
56
61
|
Utils::CheckAllowedKeys.call(opts, allowed_opts_keys)
|
57
62
|
|
@@ -71,6 +76,10 @@ class Serega
|
|
71
76
|
def allowed_opts_keys
|
72
77
|
self.class.serializer_class.config.attribute_keys
|
73
78
|
end
|
79
|
+
|
80
|
+
def check_attribute_name
|
81
|
+
self.class.serializer_class.config.check_attribute_name
|
82
|
+
end
|
74
83
|
end
|
75
84
|
|
76
85
|
include InstanceMethods
|
data/lib/serega.rb
CHANGED
@@ -70,49 +70,6 @@ class Serega
|
|
70
70
|
# Returns current config
|
71
71
|
# @return [SeregaConfig] current serializer config
|
72
72
|
attr_reader :config
|
73
|
-
|
74
|
-
private def inherited(subclass)
|
75
|
-
config_class = Class.new(self::SeregaConfig)
|
76
|
-
config_class.serializer_class = subclass
|
77
|
-
subclass.const_set(:SeregaConfig, config_class)
|
78
|
-
subclass.instance_variable_set(:@config, subclass::SeregaConfig.new(config.opts))
|
79
|
-
|
80
|
-
attribute_class = Class.new(self::SeregaAttribute)
|
81
|
-
attribute_class.serializer_class = subclass
|
82
|
-
subclass.const_set(:SeregaAttribute, attribute_class)
|
83
|
-
|
84
|
-
map_class = Class.new(self::SeregaMap)
|
85
|
-
map_class.serializer_class = subclass
|
86
|
-
subclass.const_set(:SeregaMap, map_class)
|
87
|
-
|
88
|
-
map_point_class = Class.new(self::SeregaMapPoint)
|
89
|
-
map_point_class.serializer_class = subclass
|
90
|
-
subclass.const_set(:SeregaMapPoint, map_point_class)
|
91
|
-
|
92
|
-
object_serializer_class = Class.new(self::SeregaObjectSerializer)
|
93
|
-
object_serializer_class.serializer_class = subclass
|
94
|
-
subclass.const_set(:SeregaObjectSerializer, object_serializer_class)
|
95
|
-
|
96
|
-
check_attribute_params_class = Class.new(self::CheckAttributeParams)
|
97
|
-
check_attribute_params_class.serializer_class = subclass
|
98
|
-
subclass.const_set(:CheckAttributeParams, check_attribute_params_class)
|
99
|
-
|
100
|
-
check_initiate_params_class = Class.new(self::CheckInitiateParams)
|
101
|
-
check_initiate_params_class.serializer_class = subclass
|
102
|
-
subclass.const_set(:CheckInitiateParams, check_initiate_params_class)
|
103
|
-
|
104
|
-
check_serialize_params_class = Class.new(self::CheckSerializeParams)
|
105
|
-
check_serialize_params_class.serializer_class = subclass
|
106
|
-
subclass.const_set(:CheckSerializeParams, check_serialize_params_class)
|
107
|
-
|
108
|
-
# Assign same attributes
|
109
|
-
attributes.each_value do |attr|
|
110
|
-
subclass.attribute(attr.name, **attr.opts, &attr.block)
|
111
|
-
end
|
112
|
-
|
113
|
-
super
|
114
|
-
end
|
115
|
-
|
116
73
|
#
|
117
74
|
# Enables plugin for current serializer
|
118
75
|
#
|
@@ -170,6 +127,9 @@ class Serega
|
|
170
127
|
#
|
171
128
|
# Adds attribute
|
172
129
|
#
|
130
|
+
# Patched in:
|
131
|
+
# - plugin :presenter (additionally adds method in Presenter class)
|
132
|
+
#
|
173
133
|
# @param name [Symbol] Attribute name. Attribute value will be found by executing `object.<name>`
|
174
134
|
# @param opts [Hash] Options to serialize attribute
|
175
135
|
# @param block [Proc] Custom block to find attribute value. Accepts object and context.
|
@@ -250,6 +210,54 @@ class Serega
|
|
250
210
|
def as_json(object, opts = nil)
|
251
211
|
config.from_json.call(to_json(object, opts))
|
252
212
|
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
# Patched in:
|
217
|
+
# - plugin :batch (defines SeregaBatchLoaders, SeregaBatchLoader)
|
218
|
+
# - plugin :metadata (defines MetaAttribute and copies meta_attributes to subclasses)
|
219
|
+
# - plugin :presenter (defines Presenter)
|
220
|
+
def inherited(subclass)
|
221
|
+
config_class = Class.new(self::SeregaConfig)
|
222
|
+
config_class.serializer_class = subclass
|
223
|
+
subclass.const_set(:SeregaConfig, config_class)
|
224
|
+
subclass.instance_variable_set(:@config, subclass::SeregaConfig.new(config.opts))
|
225
|
+
|
226
|
+
attribute_class = Class.new(self::SeregaAttribute)
|
227
|
+
attribute_class.serializer_class = subclass
|
228
|
+
subclass.const_set(:SeregaAttribute, attribute_class)
|
229
|
+
|
230
|
+
map_class = Class.new(self::SeregaMap)
|
231
|
+
map_class.serializer_class = subclass
|
232
|
+
subclass.const_set(:SeregaMap, map_class)
|
233
|
+
|
234
|
+
map_point_class = Class.new(self::SeregaMapPoint)
|
235
|
+
map_point_class.serializer_class = subclass
|
236
|
+
subclass.const_set(:SeregaMapPoint, map_point_class)
|
237
|
+
|
238
|
+
object_serializer_class = Class.new(self::SeregaObjectSerializer)
|
239
|
+
object_serializer_class.serializer_class = subclass
|
240
|
+
subclass.const_set(:SeregaObjectSerializer, object_serializer_class)
|
241
|
+
|
242
|
+
check_attribute_params_class = Class.new(self::CheckAttributeParams)
|
243
|
+
check_attribute_params_class.serializer_class = subclass
|
244
|
+
subclass.const_set(:CheckAttributeParams, check_attribute_params_class)
|
245
|
+
|
246
|
+
check_initiate_params_class = Class.new(self::CheckInitiateParams)
|
247
|
+
check_initiate_params_class.serializer_class = subclass
|
248
|
+
subclass.const_set(:CheckInitiateParams, check_initiate_params_class)
|
249
|
+
|
250
|
+
check_serialize_params_class = Class.new(self::CheckSerializeParams)
|
251
|
+
check_serialize_params_class.serializer_class = subclass
|
252
|
+
subclass.const_set(:CheckSerializeParams, check_serialize_params_class)
|
253
|
+
|
254
|
+
# Assign same attributes
|
255
|
+
attributes.each_value do |attr|
|
256
|
+
subclass.attribute(attr.name, **attr.opts, &attr.block)
|
257
|
+
end
|
258
|
+
|
259
|
+
super
|
260
|
+
end
|
253
261
|
end
|
254
262
|
|
255
263
|
#
|
@@ -266,7 +274,7 @@ class Serega
|
|
266
274
|
# @option opts [Boolean] :validate Validates provided modifiers (Default is true)
|
267
275
|
#
|
268
276
|
def initialize(opts = nil)
|
269
|
-
@opts = (opts.nil? || opts.empty?) ? FROZEN_EMPTY_HASH :
|
277
|
+
@opts = (opts.nil? || opts.empty?) ? FROZEN_EMPTY_HASH : parse_modifiers(opts)
|
270
278
|
self.class::CheckInitiateParams.new(@opts).validate if opts&.fetch(:check_initiate_params) { config.check_initiate_params }
|
271
279
|
end
|
272
280
|
|
@@ -340,13 +348,29 @@ class Serega
|
|
340
348
|
self.class.config
|
341
349
|
end
|
342
350
|
|
343
|
-
def
|
344
|
-
|
345
|
-
|
346
|
-
|
351
|
+
def parse_modifiers(opts)
|
352
|
+
result = {}
|
353
|
+
|
354
|
+
opts.each do |key, value|
|
355
|
+
value = parse_modifier(value) if (key == :only) || (key == :except) || (key == :with)
|
356
|
+
result[key] = value
|
347
357
|
end
|
358
|
+
|
359
|
+
result
|
360
|
+
end
|
361
|
+
|
362
|
+
# Patched in:
|
363
|
+
# - plugin :string_modifiers (parses string modifiers differently)
|
364
|
+
def parse_modifier(value)
|
365
|
+
SeregaUtils::ToHash.call(value)
|
348
366
|
end
|
349
367
|
|
368
|
+
# Patched in:
|
369
|
+
# - plugin :activerecord_preloads (loads defined :preloads to object)
|
370
|
+
# - plugin :batch (runs serialization of collected batches)
|
371
|
+
# - plugin :root (wraps result `{ root => result }`)
|
372
|
+
# - plugin :context_metadata (adds context metadata to final result)
|
373
|
+
# - plugin :metadata (adds metadata to final result)
|
350
374
|
def serialize(object, opts)
|
351
375
|
self.class::SeregaObjectSerializer
|
352
376
|
.new(**opts, points: map)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serega
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Glushkov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
JSON Serializer
|