serega 0.8.2 → 0.9.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 +43 -10
- data/VERSION +1 -1
- data/lib/serega/json/oj.rb +4 -1
- data/lib/serega/map.rb +19 -2
- data/lib/serega/object_serializer.rb +5 -1
- data/lib/serega/plugins/batch/batch.rb +7 -3
- data/lib/serega/plugins/if/if.rb +181 -0
- data/lib/serega/plugins/if/validations/check_opt_if.rb +79 -0
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +84 -0
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +88 -0
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +84 -0
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +6 -2
- data/lib/serega/utils/symbol_name.rb +37 -0
- data/lib/serega/validations/attribute/check_name.rb +1 -1
- data/lib/serega.rb +33 -22
- metadata +9 -4
- data/lib/serega/plugins/hide_nil/hide_nil.rb +0 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b6c3672a4fc40557f4fef3e650de56c84bf23d96defabd3f3f04aa5f273aa90
|
4
|
+
data.tar.gz: 79bcc2c3526b0ae141de69003e0834c94f9b7bade028cbc85bed20c3f3ba1757
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edcc6856f212848b721af517bb0f77695e6e7f2adbc7bb687e4573a62efe84e02266301cc3e70647b7cd8385b96901436ce1ded9446e9712f3884d8d6348c855
|
7
|
+
data.tar.gz: e0fec25bc4471ebbf3b6fbfb1967101af7f8cd7e703cb56eba935fd51bc6de0efe87d802be8257a950648afc633ed3ceb3bfc78f67b3905197ffa0a6e39ada32
|
data/README.md
CHANGED
@@ -20,6 +20,7 @@ It has some great features:
|
|
20
20
|
- Built-in object presenter ([presenter][presenter] plugin)
|
21
21
|
- Adding custom metadata (via [metadata][metadata] or [context_metadata][context_metadata] plugins)
|
22
22
|
- Attributes formatters ([formatters][formatters] plugin)
|
23
|
+
- Conditional attributes ([if][if] plugin)
|
23
24
|
|
24
25
|
## Installation
|
25
26
|
|
@@ -94,9 +95,11 @@ class UserSerializer < Serega
|
|
94
95
|
# It allows to specify associations to preload to attribute value
|
95
96
|
attribute :email, preload: :emails, value: proc { |user| user.emails.find(&:verified?) }
|
96
97
|
|
97
|
-
#
|
98
|
-
#
|
99
|
-
|
98
|
+
# Options `:if`, `:unless`, `:if_value`, `:unless_value` can be specified when enabled `:if` plugin
|
99
|
+
# They hide attribute key and value from response when conditions satisfied
|
100
|
+
# See more usage examples in :if plugin section.
|
101
|
+
attribute :email, if: proc { |user, ctx| user == ctx[:current_user] }
|
102
|
+
attribute :email, if_value: :present?
|
100
103
|
|
101
104
|
# Option `:format` can be specified when enabled `:formatters` plugin
|
102
105
|
# It changes attribute value
|
@@ -600,16 +603,45 @@ PostSerializer.new(with: "user(email)").to_h(post)
|
|
600
603
|
PostSerializer.new(with: {user: %i[email, username]}).to_h(post)
|
601
604
|
```
|
602
605
|
|
603
|
-
### Plugin :
|
606
|
+
### Plugin :if
|
604
607
|
|
605
|
-
|
608
|
+
Plugin adds `:if`, `:unless`, `:if_value`, `:unless_value` options to
|
609
|
+
attributes so we can remove attributes from response in various ways.
|
606
610
|
|
607
|
-
|
608
|
-
|
609
|
-
plugin :hide_nil
|
611
|
+
Use `:if` and `:unless` when you want to hide attributes before finding attribute value,
|
612
|
+
and use `:if_value` and `:unless_value` to hide attributes after we find final value.
|
610
613
|
|
611
|
-
|
612
|
-
|
614
|
+
Options `:if` and `:unless` accept currently serialized object and context as parameters.
|
615
|
+
Options `:if_value` and `:unless_value` accept already found serialized value and context as parameters.
|
616
|
+
|
617
|
+
Options `:if_value` and `:unless_value` cannot be used with :serializer option, as
|
618
|
+
serialized objects have no "serialized value". Use `:if` and `:unless` in this case.
|
619
|
+
|
620
|
+
See also a `:hide` option that is available without any plugins to hide
|
621
|
+
attribute without conditions. Look at [select serialized fields](#selecting-fields) for `:hide` usage examples.
|
622
|
+
|
623
|
+
```ruby
|
624
|
+
class UserSerializer < Serega
|
625
|
+
attribute :email, if: :active? # if user.active?
|
626
|
+
attribute :email, if: proc {|user| user.active?} # same
|
627
|
+
attribute :email, if: proc {|user, ctx| user == ctx[:current_user]} # using context
|
628
|
+
attribute :email, if: CustomPolicy.method(:view_email?) # You can provide own callable object
|
629
|
+
|
630
|
+
attribute :email, unless: :hidden? # unless user.hidden?
|
631
|
+
attribute :email, unless: proc {|user| user.hidden?} # same
|
632
|
+
attribute :email, unless: proc {|user, context| context[:show_emails]} # using context
|
633
|
+
attribute :email, unless: CustomPolicy.method(:hide_email?) # You can provide own callable object
|
634
|
+
|
635
|
+
attribute :email, if_value: :present? # if email.present?
|
636
|
+
attribute :email, if_value: proc {|email| email.present?} # same
|
637
|
+
attribute :email, if_value: proc {|email, ctx| ctx[:show_emails]} # using context
|
638
|
+
attribute :email, if_value: CustomPolicy.method(:view_email?) # You can provide own callable object
|
639
|
+
|
640
|
+
attribute :email, unless_value: :blank? # unless email.blank?
|
641
|
+
attribute :email, unless_value: proc {|email| email.blank?} # same
|
642
|
+
attribute :email, unless_value: proc {|email, context| context[:show_emails]} # using context
|
643
|
+
attribute :email, unless_value: CustomPolicy.method(:hide_email?) # You can provide own callable object
|
644
|
+
end
|
613
645
|
```
|
614
646
|
|
615
647
|
## Errors
|
@@ -648,3 +680,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
648
680
|
[presenter]: #plugin-presenter
|
649
681
|
[root]: #plugin-root
|
650
682
|
[string_modifiers]: #plugin-string_modifiers
|
683
|
+
[if]: #plugin-if
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/lib/serega/json/oj.rb
CHANGED
@@ -6,6 +6,9 @@ class Serega
|
|
6
6
|
# JSON dump adapter for ::Oj
|
7
7
|
#
|
8
8
|
class OjDump
|
9
|
+
# Default Oj serialization options
|
10
|
+
OPTS = {mode: :compat}.freeze
|
11
|
+
|
9
12
|
#
|
10
13
|
# Dumps data to JSON string
|
11
14
|
#
|
@@ -14,7 +17,7 @@ class Serega
|
|
14
17
|
# @return [String] Data serialized to JSON
|
15
18
|
#
|
16
19
|
def self.call(data)
|
17
|
-
::Oj.dump(data,
|
20
|
+
::Oj.dump(data, OPTS)
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
data/lib/serega/map.rb
CHANGED
@@ -35,7 +35,8 @@ class Serega
|
|
35
35
|
|
36
36
|
def cached_map_for(opts, max_cache_size)
|
37
37
|
@cache ||= {}
|
38
|
-
cache_key = opts
|
38
|
+
cache_key = construct_cache_key(opts)
|
39
|
+
|
39
40
|
map = @cache[cache_key] ||= map_for(opts)
|
40
41
|
@cache.shift if @cache.length > max_cache_size
|
41
42
|
map
|
@@ -50,7 +51,8 @@ class Serega
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def construct_map(serializer_class, only:, except:, with:)
|
53
|
-
|
54
|
+
map = []
|
55
|
+
serializer_class.attributes.each do |name, attribute|
|
54
56
|
next unless attribute.visible?(only: only, except: except, with: with)
|
55
57
|
|
56
58
|
nested_points =
|
@@ -65,6 +67,21 @@ class Serega
|
|
65
67
|
|
66
68
|
map << serializer_class::SeregaMapPoint.new(attribute, nested_points)
|
67
69
|
end
|
70
|
+
map
|
71
|
+
end
|
72
|
+
|
73
|
+
def construct_cache_key(opts, cache_key = nil)
|
74
|
+
return nil if opts.empty?
|
75
|
+
|
76
|
+
cache_key ||= +""
|
77
|
+
|
78
|
+
opts.each do |key, nested_opts|
|
79
|
+
cache_key.insert(-1, SeregaUtils::SymbolName.call(key))
|
80
|
+
cache_key.insert(-1, "-")
|
81
|
+
construct_cache_key(nested_opts, cache_key)
|
82
|
+
end
|
83
|
+
|
84
|
+
cache_key
|
68
85
|
end
|
69
86
|
end
|
70
87
|
|
@@ -43,10 +43,14 @@ class Serega
|
|
43
43
|
|
44
44
|
def serialize_object(object)
|
45
45
|
points.each_with_object({}) do |point, container|
|
46
|
-
|
46
|
+
serialize_point(object, point, container)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
def serialize_point(object, point, container)
|
51
|
+
attach_value(object, point, container)
|
52
|
+
end
|
53
|
+
|
50
54
|
def attach_value(object, point, container)
|
51
55
|
value = point.value(object, context)
|
52
56
|
final_value = final_value(value, point)
|
@@ -264,13 +264,17 @@ class Serega
|
|
264
264
|
batch = point.batch
|
265
265
|
|
266
266
|
if batch
|
267
|
-
|
268
|
-
opts[:batch_loaders].get(point, self).remember(key, container)
|
269
|
-
container[point.name] = nil # Reserve attribute place in resulted hash. We will set correct value later
|
267
|
+
remember_key_for_batch_loading(batch, object, point, container)
|
270
268
|
else
|
271
269
|
super
|
272
270
|
end
|
273
271
|
end
|
272
|
+
|
273
|
+
def remember_key_for_batch_loading(batch, object, point, container)
|
274
|
+
key = batch.key.call(object, context)
|
275
|
+
opts[:batch_loaders].get(point, self).remember(key, container)
|
276
|
+
container[point.name] = nil # Reserve attribute place in resulted hash. We will set correct value later
|
277
|
+
end
|
274
278
|
end
|
275
279
|
end
|
276
280
|
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
#
|
6
|
+
# Plugin adds `:if`, `:unless`, `:if_value`, `:unless_value` options to
|
7
|
+
# attributes so we can remove attributes from response in various ways.
|
8
|
+
#
|
9
|
+
# Use `:if` and `:unless` when you want to hide attributes before finding attribute value,
|
10
|
+
# and use `:if_value` and `:unless_value` to hide attributes after we find final value.
|
11
|
+
#
|
12
|
+
# Options `:if` and `:unless` accept currently serialized object and context as parameters.
|
13
|
+
# Options `:if_value` and `:unless_value` accept already found serialized value and context as parameters.
|
14
|
+
#
|
15
|
+
# Options `:if_value` and `:unless_value` cannot be used with :serializer option, as
|
16
|
+
# serialized objects have no "serialized value". Use `:if` and `:unless` in this case.
|
17
|
+
#
|
18
|
+
# See also a `:hide` option that is available without any plugins to hide
|
19
|
+
# attribute without conditions. Look at README.md#selecting-fields for `:hide` usage examples.
|
20
|
+
#
|
21
|
+
# Examples:
|
22
|
+
# class UserSerializer < Serega
|
23
|
+
# attribute :email, if: :active? # if user.active?
|
24
|
+
# attribute :email, if: proc {|user| user.active?} # same
|
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
|
43
|
+
#
|
44
|
+
module If
|
45
|
+
# @return [Symbol] Plugin name
|
46
|
+
def self.plugin_name
|
47
|
+
:if
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Applies plugin code to specific serializer
|
52
|
+
#
|
53
|
+
# @param serializer_class [Class<Serega>] Current serializer class
|
54
|
+
# @param _opts [Hash] Loaded plugins options
|
55
|
+
#
|
56
|
+
# @return [void]
|
57
|
+
#
|
58
|
+
def self.load_plugin(serializer_class, **_opts)
|
59
|
+
require_relative "./validations/check_opt_if"
|
60
|
+
require_relative "./validations/check_opt_if_value"
|
61
|
+
require_relative "./validations/check_opt_unless"
|
62
|
+
require_relative "./validations/check_opt_unless_value"
|
63
|
+
|
64
|
+
serializer_class::SeregaMapPoint.include(MapPointInstanceMethods)
|
65
|
+
serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
|
66
|
+
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
67
|
+
end
|
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
|
+
#
|
83
|
+
# Adds config options and runs other callbacks after plugin was loaded
|
84
|
+
#
|
85
|
+
# @param serializer_class [Class<Serega>] Current serializer class
|
86
|
+
# @param opts [Hash] loaded plugins opts
|
87
|
+
#
|
88
|
+
# @return [void]
|
89
|
+
#
|
90
|
+
def self.after_load_plugin(serializer_class, **opts)
|
91
|
+
serializer_class.config.attribute_keys << :if << :if_value << :unless << :unless_value
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Serega::SeregaMapPoint additional/patched instance methods
|
96
|
+
#
|
97
|
+
# @see Serega::SeregaMapPoint::InstanceMethods
|
98
|
+
#
|
99
|
+
module MapPointInstanceMethods
|
100
|
+
#
|
101
|
+
# @return [Boolean] Should we show attribute or not
|
102
|
+
# Conditions for this checks are specified by :if and :unless attribute options.
|
103
|
+
#
|
104
|
+
def satisfy_if_conditions?(obj, ctx)
|
105
|
+
check_if_unless(obj, ctx, :if, :unless)
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# @return [Boolean] Should we show attribute with specific value or not.
|
110
|
+
# Conditions for this checks are specified by :if_value and :unless_value attribute options.
|
111
|
+
#
|
112
|
+
def satisfy_if_value_conditions?(value, ctx)
|
113
|
+
check_if_unless(value, ctx, :if_value, :unless_value)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def check_if_unless(obj, ctx, opt_if_name, opt_unless_name)
|
119
|
+
opt_if = attribute.opts[opt_if_name]
|
120
|
+
opt_unless = attribute.opts[opt_unless_name]
|
121
|
+
return true if opt_if.nil? && opt_unless.nil?
|
122
|
+
|
123
|
+
res_if =
|
124
|
+
case opt_if
|
125
|
+
when NilClass then true
|
126
|
+
when Symbol then obj.public_send(opt_if)
|
127
|
+
else opt_if.call(obj, ctx)
|
128
|
+
end
|
129
|
+
|
130
|
+
res_unless =
|
131
|
+
case opt_unless
|
132
|
+
when NilClass then true
|
133
|
+
when Symbol then !obj.public_send(opt_unless)
|
134
|
+
else !opt_unless.call(obj, ctx)
|
135
|
+
end
|
136
|
+
|
137
|
+
res_if && res_unless
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Serega::SeregaValidations::CheckAttributeParams additional/patched class methods
|
143
|
+
#
|
144
|
+
# @see Serega::SeregaValidations::CheckAttributeParams
|
145
|
+
#
|
146
|
+
module CheckAttributeParamsInstanceMethods
|
147
|
+
private
|
148
|
+
|
149
|
+
def check_opts
|
150
|
+
super
|
151
|
+
|
152
|
+
CheckOptIf.call(opts)
|
153
|
+
CheckOptUnless.call(opts)
|
154
|
+
CheckOptIfValue.call(opts)
|
155
|
+
CheckOptUnlessValue.call(opts)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# SeregaObjectSerializer additional/patched class methods
|
161
|
+
#
|
162
|
+
# @see Serega::SeregaObjectSerializer
|
163
|
+
#
|
164
|
+
module SeregaObjectSerializerInstanceMethods
|
165
|
+
private
|
166
|
+
|
167
|
+
def serialize_point(object, point, _container)
|
168
|
+
return unless point.satisfy_if_conditions?(object, context)
|
169
|
+
super
|
170
|
+
end
|
171
|
+
|
172
|
+
def attach_final_value(value, point, _container)
|
173
|
+
return unless point.satisfy_if_value_conditions?(value, context)
|
174
|
+
super
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
register_plugin(If.plugin_name, If)
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module If
|
6
|
+
#
|
7
|
+
# Validator for attribute :if option
|
8
|
+
#
|
9
|
+
class CheckOptIf
|
10
|
+
class << self
|
11
|
+
#
|
12
|
+
# Checks attribute :if option that must be [nil, Symbol, Proc, #call]
|
13
|
+
#
|
14
|
+
# @param opts [Hash] Attribute options
|
15
|
+
#
|
16
|
+
# @raise [SeregaError] Attribute validation error
|
17
|
+
#
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
def call(opts)
|
21
|
+
return unless opts.key?(:if)
|
22
|
+
|
23
|
+
check_type(opts[:if])
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def check_type(value)
|
29
|
+
return if value.is_a?(Symbol)
|
30
|
+
|
31
|
+
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
32
|
+
|
33
|
+
if value.is_a?(Proc)
|
34
|
+
check_block(value)
|
35
|
+
else
|
36
|
+
check_callable(value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_block(block)
|
41
|
+
return if valid_parameters?(block, accepted_count: 0..2)
|
42
|
+
|
43
|
+
raise SeregaError, block_parameters_error
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_callable(callable)
|
47
|
+
return if valid_parameters?(callable.method(:call), accepted_count: 2..2)
|
48
|
+
|
49
|
+
raise SeregaError, callable_parameters_error
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid_parameters?(data, accepted_count:)
|
53
|
+
params = data.parameters
|
54
|
+
accepted_count.include?(params.count) && valid_parameters_types?(params)
|
55
|
+
end
|
56
|
+
|
57
|
+
def valid_parameters_types?(params)
|
58
|
+
params.all? do |param|
|
59
|
+
type = param[0]
|
60
|
+
(type == :req) || (type == :opt)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def block_parameters_error
|
65
|
+
"Invalid attribute option :if. When it is a Proc it can have maximum two regular parameters (object, context)"
|
66
|
+
end
|
67
|
+
|
68
|
+
def callable_parameters_error
|
69
|
+
"Invalid attribute option :if. When it is a callable object it must have two regular parameters (object, context)"
|
70
|
+
end
|
71
|
+
|
72
|
+
def must_be_callable
|
73
|
+
"Invalid attribute option :if. It must be a Symbol, a Proc or respond to :call"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module If
|
6
|
+
#
|
7
|
+
# Validator for attribute :if_value option
|
8
|
+
#
|
9
|
+
class CheckOptIfValue
|
10
|
+
class << self
|
11
|
+
#
|
12
|
+
# Checks attribute :if_value option that must be [nil, Symbol, Proc, #call]
|
13
|
+
#
|
14
|
+
# @param opts [Hash] Attribute options
|
15
|
+
#
|
16
|
+
# @raise [SeregaError] Attribute validation error
|
17
|
+
#
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
def call(opts)
|
21
|
+
return unless opts.key?(:if_value)
|
22
|
+
|
23
|
+
check_usage_with_other_params(opts)
|
24
|
+
check_type(opts[:if_value])
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def check_type(value)
|
30
|
+
return if value.is_a?(Symbol)
|
31
|
+
|
32
|
+
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
33
|
+
|
34
|
+
if value.is_a?(Proc)
|
35
|
+
check_block(value)
|
36
|
+
else
|
37
|
+
check_callable(value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_usage_with_other_params(opts)
|
42
|
+
raise SeregaError, "Option :if_value can not be used together with option :serializer" if opts.key?(:serializer)
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_block(block)
|
46
|
+
return if valid_parameters?(block, accepted_count: 0..2)
|
47
|
+
|
48
|
+
raise SeregaError, block_parameters_error
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_callable(callable)
|
52
|
+
return if valid_parameters?(callable.method(:call), accepted_count: 2..2)
|
53
|
+
|
54
|
+
raise SeregaError, callable_parameters_error
|
55
|
+
end
|
56
|
+
|
57
|
+
def valid_parameters?(data, accepted_count:)
|
58
|
+
params = data.parameters
|
59
|
+
accepted_count.include?(params.count) && valid_parameters_types?(params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid_parameters_types?(params)
|
63
|
+
params.all? do |param|
|
64
|
+
type = param[0]
|
65
|
+
(type == :req) || (type == :opt)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def block_parameters_error
|
70
|
+
"Invalid attribute option :if_value. When it is a Proc it can have maximum two regular parameters (object, context)"
|
71
|
+
end
|
72
|
+
|
73
|
+
def callable_parameters_error
|
74
|
+
"Invalid attribute option :if_value. When it is a callable object it must have two regular parameters (object, context)"
|
75
|
+
end
|
76
|
+
|
77
|
+
def must_be_callable
|
78
|
+
"Invalid attribute option :if_value. It must be a Symbol, a Proc or respond to :call"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module If
|
6
|
+
#
|
7
|
+
# Validator for attribute :unless option
|
8
|
+
#
|
9
|
+
class CheckOptUnless
|
10
|
+
class << self
|
11
|
+
#
|
12
|
+
# Checks attribute :unless option that must be [nil, Symbol, Proc, #call]
|
13
|
+
#
|
14
|
+
# @param opts [Hash] Attribute options
|
15
|
+
#
|
16
|
+
# @raise [SeregaError] Attribute validation error
|
17
|
+
#
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
def call(opts)
|
21
|
+
return unless opts.key?(:unless)
|
22
|
+
|
23
|
+
check_type(opts[:unless])
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
#
|
29
|
+
# Checks attribute :unless option
|
30
|
+
#
|
31
|
+
# @param value [nil, Symbol, Proc, #call] Attribute :unless option
|
32
|
+
#
|
33
|
+
# @raise [SeregaError] validation error
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
def check_type(value)
|
38
|
+
return if value.is_a?(Symbol)
|
39
|
+
|
40
|
+
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
41
|
+
|
42
|
+
if value.is_a?(Proc)
|
43
|
+
check_block(value)
|
44
|
+
else
|
45
|
+
check_callable(value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_block(block)
|
50
|
+
return if valid_parameters?(block, accepted_count: 0..2)
|
51
|
+
|
52
|
+
raise SeregaError, block_parameters_error
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_callable(callable)
|
56
|
+
return if valid_parameters?(callable.method(:call), accepted_count: 2..2)
|
57
|
+
|
58
|
+
raise SeregaError, callable_parameters_error
|
59
|
+
end
|
60
|
+
|
61
|
+
def valid_parameters?(data, accepted_count:)
|
62
|
+
params = data.parameters
|
63
|
+
accepted_count.include?(params.count) && valid_parameters_types?(params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid_parameters_types?(params)
|
67
|
+
params.all? do |param|
|
68
|
+
type = param[0]
|
69
|
+
(type == :req) || (type == :opt)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def block_parameters_error
|
74
|
+
"Invalid attribute option :unless. When it is a Proc it can have maximum two regular parameters (object, context)"
|
75
|
+
end
|
76
|
+
|
77
|
+
def callable_parameters_error
|
78
|
+
"Invalid attribute option :unless. When it is a callable object it must have two regular parameters (object, context)"
|
79
|
+
end
|
80
|
+
|
81
|
+
def must_be_callable
|
82
|
+
"Invalid attribute option :unless. It must be a Symbol, a Proc or respond to :call"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module If
|
6
|
+
#
|
7
|
+
# Validator for attribute :unless_value option
|
8
|
+
#
|
9
|
+
class CheckOptUnlessValue
|
10
|
+
class << self
|
11
|
+
#
|
12
|
+
# Checks attribute :unless_value option that must be [nil, Symbol, Proc, #call]
|
13
|
+
#
|
14
|
+
# @param opts [Hash] Attribute options
|
15
|
+
#
|
16
|
+
# @raise [SeregaError] Attribute validation error
|
17
|
+
#
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
def call(opts)
|
21
|
+
return unless opts.key?(:unless_value)
|
22
|
+
|
23
|
+
check_usage_with_other_params(opts)
|
24
|
+
check_type(opts[:unless_value])
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def check_type(value)
|
30
|
+
return if value.is_a?(Symbol)
|
31
|
+
|
32
|
+
raise SeregaError, must_be_callable unless value.respond_to?(:call)
|
33
|
+
|
34
|
+
if value.is_a?(Proc)
|
35
|
+
check_block(value)
|
36
|
+
else
|
37
|
+
check_callable(value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_usage_with_other_params(opts)
|
42
|
+
raise SeregaError, "Option :unless_value can not be used together with option :serializer" if opts.key?(:serializer)
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_block(block)
|
46
|
+
return if valid_parameters?(block, accepted_count: 0..2)
|
47
|
+
|
48
|
+
raise SeregaError, block_parameters_error
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_callable(callable)
|
52
|
+
return if valid_parameters?(callable.method(:call), accepted_count: 2..2)
|
53
|
+
|
54
|
+
raise SeregaError, callable_parameters_error
|
55
|
+
end
|
56
|
+
|
57
|
+
def valid_parameters?(data, accepted_count:)
|
58
|
+
params = data.parameters
|
59
|
+
accepted_count.include?(params.count) && valid_parameters_types?(params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid_parameters_types?(params)
|
63
|
+
params.all? do |param|
|
64
|
+
type = param[0]
|
65
|
+
(type == :req) || (type == :opt)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def block_parameters_error
|
70
|
+
"Invalid attribute option :unless_value. When it is a Proc it can have maximum two regular parameters (object, context)"
|
71
|
+
end
|
72
|
+
|
73
|
+
def callable_parameters_error
|
74
|
+
"Invalid attribute option :unless_value. When it is a callable object it must have two regular parameters (object, context)"
|
75
|
+
end
|
76
|
+
|
77
|
+
def must_be_callable
|
78
|
+
"Invalid attribute option :unless_value. It must be a Symbol, a Proc or respond to :call"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "stringio"
|
4
|
+
|
3
5
|
class Serega
|
4
6
|
module SeregaPlugins
|
5
7
|
#
|
@@ -14,7 +16,7 @@ class Serega
|
|
14
16
|
# PostSerializer.new(only: "id,user(id,username)").to_h(post)
|
15
17
|
# PostSerializer.new(except: "user(username,email)").to_h(post)
|
16
18
|
# PostSerializer.new(with: "user(email)").to_h(post)
|
17
|
-
|
19
|
+
#
|
18
20
|
# # Modifiers can still be provided old way with nested hashes or arrays.
|
19
21
|
# PostSerializer.new(with: {user: %i[email, username]}).to_h(post)
|
20
22
|
#
|
@@ -52,9 +54,11 @@ class Serega
|
|
52
54
|
def parse(fields)
|
53
55
|
res = {}
|
54
56
|
attribute = +""
|
57
|
+
char = +""
|
55
58
|
path_stack = nil
|
59
|
+
fields = StringIO.new(fields)
|
56
60
|
|
57
|
-
fields.
|
61
|
+
while fields.read(1, char)
|
58
62
|
case char
|
59
63
|
when ","
|
60
64
|
add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaUtils
|
5
|
+
#
|
6
|
+
# Utility to get frozen string from symbol in any ruby version
|
7
|
+
#
|
8
|
+
class SymbolName
|
9
|
+
class << self
|
10
|
+
#
|
11
|
+
# Returns frozen string corresponding to provided symbol
|
12
|
+
#
|
13
|
+
# @param key [Symbol]
|
14
|
+
#
|
15
|
+
# @return [String] frozen string corresponding to provided symbol
|
16
|
+
#
|
17
|
+
def call(key)
|
18
|
+
key.is_a?(String) ? key : to_frozen_string(key)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# :nocov:
|
24
|
+
if RUBY_VERSION < "3"
|
25
|
+
def to_frozen_string(key)
|
26
|
+
key.to_s.freeze
|
27
|
+
end
|
28
|
+
else
|
29
|
+
def to_frozen_string(key)
|
30
|
+
key.name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# :nocov:
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/serega.rb
CHANGED
@@ -16,6 +16,7 @@ end
|
|
16
16
|
require_relative "serega/errors"
|
17
17
|
require_relative "serega/helpers/serializer_class_helper"
|
18
18
|
require_relative "serega/utils/enum_deep_dup"
|
19
|
+
require_relative "serega/utils/symbol_name"
|
19
20
|
require_relative "serega/utils/to_hash"
|
20
21
|
require_relative "serega/json/adapter"
|
21
22
|
|
@@ -184,7 +185,7 @@ class Serega
|
|
184
185
|
# Serializes provided object to Hash
|
185
186
|
#
|
186
187
|
# @param object [Object] Serialized object
|
187
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
188
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
188
189
|
# @option opts [Array, Hash, String, Symbol] :only The only attributes to serialize
|
189
190
|
# @option opts [Array, Hash, String, Symbol] :except Attributes to hide
|
190
191
|
# @option opts [Array, Hash, String, Symbol] :with Attributes (usually hidden) to serialize additionally
|
@@ -194,13 +195,23 @@ class Serega
|
|
194
195
|
#
|
195
196
|
# @return [Hash] Serialization result
|
196
197
|
#
|
197
|
-
def call(object, opts =
|
198
|
+
def call(object, opts = nil)
|
199
|
+
opts ||= FROZEN_EMPTY_HASH
|
198
200
|
initiate_keys = config.initiate_keys
|
199
|
-
|
201
|
+
|
202
|
+
if opts.empty?
|
203
|
+
modifiers_opts = FROZEN_EMPTY_HASH
|
204
|
+
serialize_opts = nil
|
205
|
+
else
|
206
|
+
serialize_opts = opts.except(*initiate_keys)
|
207
|
+
modifiers_opts = opts.slice(*initiate_keys)
|
208
|
+
end
|
209
|
+
|
210
|
+
new(modifiers_opts).to_h(object, serialize_opts)
|
200
211
|
end
|
201
212
|
|
202
213
|
# @see #call
|
203
|
-
def to_h(object, opts =
|
214
|
+
def to_h(object, opts = nil)
|
204
215
|
call(object, opts)
|
205
216
|
end
|
206
217
|
|
@@ -208,7 +219,7 @@ class Serega
|
|
208
219
|
# Serializes provided object to JSON string
|
209
220
|
#
|
210
221
|
# @param object [Object] Serialized object
|
211
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
222
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
212
223
|
# @option opts [Array, Hash, String, Symbol] :only The only attributes to serialize
|
213
224
|
# @option opts [Array, Hash, String, Symbol] :except Attributes to hide
|
214
225
|
# @option opts [Array, Hash, String, Symbol] :with Attributes (usually hidden) to serialize additionally
|
@@ -218,16 +229,15 @@ class Serega
|
|
218
229
|
#
|
219
230
|
# @return [String] Serialization result
|
220
231
|
#
|
221
|
-
def to_json(object, opts =
|
222
|
-
|
223
|
-
new(opts.slice(*initiate_keys)).to_json(object, opts.except(*initiate_keys))
|
232
|
+
def to_json(object, opts = nil)
|
233
|
+
config.to_json.call(to_h(object, opts))
|
224
234
|
end
|
225
235
|
|
226
236
|
#
|
227
237
|
# Serializes provided object as JSON
|
228
238
|
#
|
229
239
|
# @param object [Object] Serialized object
|
230
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
240
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
231
241
|
# @option opts [Array, Hash, String, Symbol] :only The only attributes to serialize
|
232
242
|
# @option opts [Array, Hash, String, Symbol] :except Attributes to hide
|
233
243
|
# @option opts [Array, Hash, String, Symbol] :with Attributes (usually hidden) to serialize additionally
|
@@ -237,7 +247,7 @@ class Serega
|
|
237
247
|
#
|
238
248
|
# @return [Hash] Serialization result
|
239
249
|
#
|
240
|
-
def as_json(object, opts =
|
250
|
+
def as_json(object, opts = nil)
|
241
251
|
config.from_json.call(to_json(object, opts))
|
242
252
|
end
|
243
253
|
end
|
@@ -249,36 +259,37 @@ class Serega
|
|
249
259
|
#
|
250
260
|
# Instantiates new Serega class
|
251
261
|
#
|
252
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
262
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
253
263
|
# @option opts [Array, Hash, String, Symbol] :only The only attributes to serialize
|
254
264
|
# @option opts [Array, Hash, String, Symbol] :except Attributes to hide
|
255
265
|
# @option opts [Array, Hash, String, Symbol] :with Attributes (usually hidden) to serialize additionally
|
256
266
|
# @option opts [Boolean] :validate Validates provided modifiers (Default is true)
|
257
267
|
#
|
258
|
-
def initialize(opts =
|
259
|
-
@opts = (opts
|
260
|
-
self.class::CheckInitiateParams.new(@opts).validate if opts
|
268
|
+
def initialize(opts = nil)
|
269
|
+
@opts = (opts.nil? || opts.empty?) ? FROZEN_EMPTY_HASH : prepare_modifiers(opts)
|
270
|
+
self.class::CheckInitiateParams.new(@opts).validate if opts&.fetch(:check_initiate_params) { config.check_initiate_params }
|
261
271
|
end
|
262
272
|
|
263
273
|
#
|
264
274
|
# Serializes provided object to Hash
|
265
275
|
#
|
266
276
|
# @param object [Object] Serialized object
|
267
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
277
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
268
278
|
# @option opts [Hash] :context Serialization context
|
269
279
|
# @option opts [Boolean] :many Set true if provided multiple objects (Default `object.is_a?(Enumerable)`)
|
270
280
|
#
|
271
281
|
# @return [Hash] Serialization result
|
272
282
|
#
|
273
|
-
def call(object, opts =
|
274
|
-
self.class::CheckSerializeParams.new(opts).validate
|
283
|
+
def call(object, opts = nil)
|
284
|
+
self.class::CheckSerializeParams.new(opts).validate if opts&.any?
|
285
|
+
opts ||= {}
|
275
286
|
opts[:context] ||= {}
|
276
287
|
|
277
288
|
serialize(object, opts)
|
278
289
|
end
|
279
290
|
|
280
291
|
# @see #call
|
281
|
-
def to_h(object, opts =
|
292
|
+
def to_h(object, opts = nil)
|
282
293
|
call(object, opts)
|
283
294
|
end
|
284
295
|
|
@@ -286,13 +297,13 @@ class Serega
|
|
286
297
|
# Serializes provided object to JSON string
|
287
298
|
#
|
288
299
|
# @param object [Object] Serialized object
|
289
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
300
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
290
301
|
# @option opts [Hash] :context Serialization context
|
291
302
|
# @option opts [Boolean] :many Set true if provided multiple objects (Default `object.is_a?(Enumerable)`)
|
292
303
|
#
|
293
304
|
# @return [Hash] Serialization result
|
294
305
|
#
|
295
|
-
def to_json(object, opts =
|
306
|
+
def to_json(object, opts = nil)
|
296
307
|
hash = to_h(object, opts)
|
297
308
|
config.to_json.call(hash)
|
298
309
|
end
|
@@ -301,13 +312,13 @@ class Serega
|
|
301
312
|
# Serializes provided object as JSON
|
302
313
|
#
|
303
314
|
# @param object [Object] Serialized object
|
304
|
-
# @param opts [Hash] Serializer modifiers and other instantiating options
|
315
|
+
# @param opts [Hash, nil] Serializer modifiers and other instantiating options
|
305
316
|
# @option opts [Hash] :context Serialization context
|
306
317
|
# @option opts [Boolean] :many Set true if provided multiple objects (Default `object.is_a?(Enumerable)`)
|
307
318
|
#
|
308
319
|
# @return [Hash] Serialization result
|
309
320
|
#
|
310
|
-
def as_json(object, opts =
|
321
|
+
def as_json(object, opts = nil)
|
311
322
|
json = to_json(object, opts)
|
312
323
|
config.from_json.call(json)
|
313
324
|
end
|
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.9.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:
|
11
|
+
date: 2023-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
JSON Serializer
|
@@ -53,7 +53,11 @@ files:
|
|
53
53
|
- lib/serega/plugins/batch/lib/validations/check_opt_batch.rb
|
54
54
|
- lib/serega/plugins/context_metadata/context_metadata.rb
|
55
55
|
- lib/serega/plugins/formatters/formatters.rb
|
56
|
-
- lib/serega/plugins/
|
56
|
+
- lib/serega/plugins/if/if.rb
|
57
|
+
- lib/serega/plugins/if/validations/check_opt_if.rb
|
58
|
+
- lib/serega/plugins/if/validations/check_opt_if_value.rb
|
59
|
+
- lib/serega/plugins/if/validations/check_opt_unless.rb
|
60
|
+
- lib/serega/plugins/if/validations/check_opt_unless_value.rb
|
57
61
|
- lib/serega/plugins/metadata/meta_attribute.rb
|
58
62
|
- lib/serega/plugins/metadata/metadata.rb
|
59
63
|
- lib/serega/plugins/metadata/validations/check_block.rb
|
@@ -73,6 +77,7 @@ files:
|
|
73
77
|
- lib/serega/plugins/string_modifiers/parse_string_modifiers.rb
|
74
78
|
- lib/serega/plugins/string_modifiers/string_modifiers.rb
|
75
79
|
- lib/serega/utils/enum_deep_dup.rb
|
80
|
+
- lib/serega/utils/symbol_name.rb
|
76
81
|
- lib/serega/utils/to_hash.rb
|
77
82
|
- lib/serega/validations/attribute/check_block.rb
|
78
83
|
- lib/serega/validations/attribute/check_name.rb
|
@@ -114,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
119
|
- !ruby/object:Gem::Version
|
115
120
|
version: '0'
|
116
121
|
requirements: []
|
117
|
-
rubygems_version: 3.
|
122
|
+
rubygems_version: 3.4.7
|
118
123
|
signing_key:
|
119
124
|
specification_version: 4
|
120
125
|
summary: JSON Serializer
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Serega
|
4
|
-
module SeregaPlugins
|
5
|
-
#
|
6
|
-
# Plugin adds `:hide_nil` option to attributes to delete them from final result
|
7
|
-
# if value is nil
|
8
|
-
#
|
9
|
-
module HideNil
|
10
|
-
# @return [Symbol] Plugin name
|
11
|
-
def self.plugin_name
|
12
|
-
:hide_nil
|
13
|
-
end
|
14
|
-
|
15
|
-
#
|
16
|
-
# Applies plugin code to specific serializer
|
17
|
-
#
|
18
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
19
|
-
# @param _opts [Hash] Loaded plugins options
|
20
|
-
#
|
21
|
-
# @return [void]
|
22
|
-
#
|
23
|
-
def self.load_plugin(serializer_class, **_opts)
|
24
|
-
serializer_class::SeregaAttribute.include(AttributeInstanceMethods)
|
25
|
-
serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
|
26
|
-
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
# Adds config options and runs other callbacks after plugin was loaded
|
31
|
-
#
|
32
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
33
|
-
# @param opts [Hash] loaded plugins opts
|
34
|
-
#
|
35
|
-
# @return [void]
|
36
|
-
#
|
37
|
-
def self.after_load_plugin(serializer_class, **opts)
|
38
|
-
serializer_class.config.attribute_keys << :hide_nil
|
39
|
-
end
|
40
|
-
|
41
|
-
#
|
42
|
-
# Serega::SeregaAttribute additional/patched instance methods
|
43
|
-
#
|
44
|
-
# @see Serega::SeregaValidations::CheckAttributeParams
|
45
|
-
#
|
46
|
-
module AttributeInstanceMethods
|
47
|
-
# Check hide_nil is specified
|
48
|
-
def hide_nil?
|
49
|
-
!!opts[:hide_nil]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# Serega::SeregaValidations::CheckAttributeParams additional/patched class methods
|
55
|
-
#
|
56
|
-
# @see Serega::SeregaValidations::CheckAttributeParams
|
57
|
-
#
|
58
|
-
module CheckAttributeParamsInstanceMethods
|
59
|
-
private
|
60
|
-
|
61
|
-
def check_opts
|
62
|
-
super
|
63
|
-
CheckOptHideNil.call(opts)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
#
|
68
|
-
# Validator class for :hide_nil attribute option
|
69
|
-
#
|
70
|
-
class CheckOptHideNil
|
71
|
-
#
|
72
|
-
# Checks attribute :hide_nil option
|
73
|
-
#
|
74
|
-
# @param opts [Hash] Attribute options
|
75
|
-
#
|
76
|
-
# @raise [Serega::SeregaError] SeregaError that option has invalid value
|
77
|
-
#
|
78
|
-
# @return [void]
|
79
|
-
#
|
80
|
-
def self.call(opts)
|
81
|
-
return unless opts.key?(:hide_nil)
|
82
|
-
|
83
|
-
value = opts[:hide_nil]
|
84
|
-
return if (value == true) || (value == false)
|
85
|
-
|
86
|
-
raise SeregaError, "Invalid option :hide_nil => #{value.inspect}. Must have a boolean value"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
#
|
91
|
-
# SeregaObjectSerializer additional/patched class methods
|
92
|
-
#
|
93
|
-
# @see Serega::SeregaObjectSerializer
|
94
|
-
#
|
95
|
-
module SeregaObjectSerializerInstanceMethods
|
96
|
-
private
|
97
|
-
|
98
|
-
def attach_final_value(final_value, *)
|
99
|
-
super unless final_value.nil?
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
register_plugin(HideNil.plugin_name, HideNil)
|
105
|
-
end
|
106
|
-
end
|