params_ready_rails5 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/arel/cte_name.rb +20 -0
- data/lib/params_ready/builder.rb +161 -0
- data/lib/params_ready/error.rb +31 -0
- data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
- data/lib/params_ready/extensions/collection.rb +43 -0
- data/lib/params_ready/extensions/delegation.rb +25 -0
- data/lib/params_ready/extensions/finalizer.rb +26 -0
- data/lib/params_ready/extensions/freezer.rb +49 -0
- data/lib/params_ready/extensions/hash.rb +46 -0
- data/lib/params_ready/extensions/late_init.rb +38 -0
- data/lib/params_ready/extensions/registry.rb +44 -0
- data/lib/params_ready/extensions/undefined.rb +23 -0
- data/lib/params_ready/format.rb +132 -0
- data/lib/params_ready/helpers/arel_builder.rb +68 -0
- data/lib/params_ready/helpers/callable.rb +14 -0
- data/lib/params_ready/helpers/conditional_block.rb +31 -0
- data/lib/params_ready/helpers/find_in_hash.rb +22 -0
- data/lib/params_ready/helpers/interface_definer.rb +48 -0
- data/lib/params_ready/helpers/key_map.rb +176 -0
- data/lib/params_ready/helpers/memo.rb +41 -0
- data/lib/params_ready/helpers/options.rb +107 -0
- data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
- data/lib/params_ready/helpers/parameter_storage_class_methods.rb +63 -0
- data/lib/params_ready/helpers/parameter_user_class_methods.rb +35 -0
- data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
- data/lib/params_ready/helpers/rule.rb +76 -0
- data/lib/params_ready/helpers/storage.rb +30 -0
- data/lib/params_ready/helpers/usage_rule.rb +36 -0
- data/lib/params_ready/input_context.rb +31 -0
- data/lib/params_ready/intent.rb +70 -0
- data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
- data/lib/params_ready/marshaller/builder_module.rb +9 -0
- data/lib/params_ready/marshaller/collection.rb +165 -0
- data/lib/params_ready/marshaller/definition_module.rb +63 -0
- data/lib/params_ready/marshaller/enum_set_marshallers.rb +96 -0
- data/lib/params_ready/marshaller/parameter_module.rb +11 -0
- data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
- data/lib/params_ready/marshaller/struct_marshallers.rb +100 -0
- data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
- data/lib/params_ready/ordering/column.rb +60 -0
- data/lib/params_ready/ordering/ordering.rb +276 -0
- data/lib/params_ready/output_parameters.rb +138 -0
- data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
- data/lib/params_ready/pagination/cursor.rb +171 -0
- data/lib/params_ready/pagination/direction.rb +148 -0
- data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
- data/lib/params_ready/pagination/keysets.rb +70 -0
- data/lib/params_ready/pagination/nulls.rb +31 -0
- data/lib/params_ready/pagination/offset_pagination.rb +130 -0
- data/lib/params_ready/pagination/tendency.rb +28 -0
- data/lib/params_ready/parameter/abstract_struct_parameter.rb +204 -0
- data/lib/params_ready/parameter/array_parameter.rb +197 -0
- data/lib/params_ready/parameter/definition.rb +272 -0
- data/lib/params_ready/parameter/enum_set_parameter.rb +102 -0
- data/lib/params_ready/parameter/parameter.rb +475 -0
- data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
- data/lib/params_ready/parameter/state.rb +132 -0
- data/lib/params_ready/parameter/struct_parameter.rb +64 -0
- data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
- data/lib/params_ready/parameter/value_parameter.rb +186 -0
- data/lib/params_ready/parameter_definer.rb +14 -0
- data/lib/params_ready/parameter_user.rb +35 -0
- data/lib/params_ready/query/array_grouping.rb +68 -0
- data/lib/params_ready/query/custom_predicate.rb +102 -0
- data/lib/params_ready/query/exists_predicate.rb +103 -0
- data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
- data/lib/params_ready/query/grouping.rb +177 -0
- data/lib/params_ready/query/join_clause.rb +87 -0
- data/lib/params_ready/query/nullness_predicate.rb +71 -0
- data/lib/params_ready/query/polymorph_predicate.rb +77 -0
- data/lib/params_ready/query/predicate.rb +203 -0
- data/lib/params_ready/query/predicate_operator.rb +132 -0
- data/lib/params_ready/query/relation.rb +337 -0
- data/lib/params_ready/query/structured_grouping.rb +58 -0
- data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
- data/lib/params_ready/query_context.rb +21 -0
- data/lib/params_ready/restriction.rb +252 -0
- data/lib/params_ready/result.rb +109 -0
- data/lib/params_ready/value/coder.rb +210 -0
- data/lib/params_ready/value/constraint.rb +198 -0
- data/lib/params_ready/value/custom.rb +56 -0
- data/lib/params_ready/value/validator.rb +81 -0
- data/lib/params_ready/version.rb +7 -0
- data/lib/params_ready.rb +28 -0
- metadata +227 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'set'
|
2
|
+
require_relative 'struct_parameter'
|
3
|
+
require_relative 'value_parameter'
|
4
|
+
require_relative '../intent'
|
5
|
+
require_relative '../marshaller/enum_set_marshallers'
|
6
|
+
require_relative '../marshaller/parameter_module'
|
7
|
+
|
8
|
+
module ParamsReady
|
9
|
+
module Parameter
|
10
|
+
class EnumSetParameter < AbstractStructParameter
|
11
|
+
include Marshaller::ParameterModule
|
12
|
+
|
13
|
+
def self.intent_for_set(intent)
|
14
|
+
Intent.new(
|
15
|
+
intent.format.update(
|
16
|
+
omit: [],
|
17
|
+
remap: false
|
18
|
+
),
|
19
|
+
intent.restriction
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def member?(key)
|
24
|
+
raise ParamsReadyError, "Key not defined: '#{key}'" unless definition.has_child? key
|
25
|
+
|
26
|
+
if is_definite?
|
27
|
+
bare_value[key].unwrap == true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class EnumSetParameterBuilder < Builder
|
35
|
+
include Marshaller::BuilderModule
|
36
|
+
|
37
|
+
register :enum_set
|
38
|
+
register_deprecated :hash_set, use: :enum_set
|
39
|
+
|
40
|
+
def self.instance(name, altn: nil, type: :boolean)
|
41
|
+
new EnumSetParameterDefinition.new(name, altn: altn, type: type)
|
42
|
+
end
|
43
|
+
|
44
|
+
def add(input, *args, val: nil, **opts, &block)
|
45
|
+
type = @definition.type
|
46
|
+
definition = self.class.resolve(type, input, *args, **opts, &block)
|
47
|
+
@definition.add_child definition, value: val
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def self.resolve(type, input, *args, **opts, &block)
|
52
|
+
if input.is_a? AbstractDefinition
|
53
|
+
input
|
54
|
+
else
|
55
|
+
define_registered_parameter(type, input, *args, **opts, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class EnumSetParameterDefinition < AbstractStructParameterDefinition
|
61
|
+
attr_reader :type, :values
|
62
|
+
freeze_variable :values
|
63
|
+
name_for_formatter :enum_set
|
64
|
+
parameter_class EnumSetParameter
|
65
|
+
include Marshaller::DefinitionModule[Marshaller::EnumSetMarshallers.collection]
|
66
|
+
|
67
|
+
def initialize(*args, type: :boolean, **opts)
|
68
|
+
@type = type
|
69
|
+
@values = {}
|
70
|
+
super *args, **opts
|
71
|
+
end
|
72
|
+
|
73
|
+
def ensure_canonical(set)
|
74
|
+
raise ParamsReadyError, "Unexpected default type: #{set.class.name}" unless set.is_a?(Set)
|
75
|
+
|
76
|
+
context = Format.instance(:backend)
|
77
|
+
value, _validator = try_canonicalize set, context, nil, freeze: true
|
78
|
+
return value if value.length == set.length
|
79
|
+
|
80
|
+
extra_keys = set.reject do |key|
|
81
|
+
value.key?(key) || value.key?(key.to_s)
|
82
|
+
end.map do |key|
|
83
|
+
"'#{key.to_s}'"
|
84
|
+
end.join(", ")
|
85
|
+
raise ParamsReadyError, "extra elements found -- #{extra_keys}" if extra_keys.length > 0
|
86
|
+
|
87
|
+
value
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_child(child, value:)
|
91
|
+
value = value.nil? ? child.name : value
|
92
|
+
|
93
|
+
if @values.key(value).nil?
|
94
|
+
@values[child.name] = value
|
95
|
+
else
|
96
|
+
raise ParamsReadyError, "Value '#{value}' already taken by '#{@values.key(value)}'"
|
97
|
+
end
|
98
|
+
super child
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,475 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative '../extensions/freezer'
|
3
|
+
require_relative '../error'
|
4
|
+
require_relative '../helpers/memo'
|
5
|
+
require_relative '../helpers/find_in_hash'
|
6
|
+
|
7
|
+
module ParamsReady
|
8
|
+
module Parameter
|
9
|
+
module FromHash
|
10
|
+
def set_from_hash(hash, context: nil, validator: Result.new(name))
|
11
|
+
if no_input?(context)
|
12
|
+
populate(context, validator)
|
13
|
+
else
|
14
|
+
_, input = find_in_hash hash, context
|
15
|
+
set_from_input(input, context, validator)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ComplexParameter
|
21
|
+
def update_child(value, path)
|
22
|
+
child, child_name, child_path = child_for_update(path)
|
23
|
+
changed, updated = child.update_if_applicable(value, child_path)
|
24
|
+
|
25
|
+
if frozen? && !changed
|
26
|
+
[false, self]
|
27
|
+
else
|
28
|
+
clone = updated_clone(child_name, updated)
|
29
|
+
[true, clone]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module DelegatingParameter
|
35
|
+
include ComplexParameter
|
36
|
+
include FromHash
|
37
|
+
|
38
|
+
def self.included(recipient)
|
39
|
+
recipient.freeze_variable :data
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(name, *args)
|
43
|
+
if @data.respond_to?(name)
|
44
|
+
@data.send name, *args
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def respond_to_missing?(name, include_private = false)
|
51
|
+
if @data.respond_to?(name, include_private)
|
52
|
+
true
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_value(input, context = Format.instance(:backend), validator = nil)
|
59
|
+
if self.match?(input)
|
60
|
+
super input.unwrap, context, validator
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def hash
|
67
|
+
[definition, data].hash
|
68
|
+
end
|
69
|
+
|
70
|
+
def ==(other)
|
71
|
+
return false unless self.match?(other)
|
72
|
+
data == other.data
|
73
|
+
end
|
74
|
+
|
75
|
+
alias_method :eql?, :==
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def child_for_update(path)
|
80
|
+
[@data, nil, *path]
|
81
|
+
end
|
82
|
+
|
83
|
+
def updated_clone(_child_name, updated)
|
84
|
+
clone = definition.create
|
85
|
+
clone.instance_variable_set :@data, updated
|
86
|
+
clone.freeze if frozen?
|
87
|
+
clone
|
88
|
+
end
|
89
|
+
|
90
|
+
def set_from_input(input, context, validator)
|
91
|
+
if self.match?(input)
|
92
|
+
super input.unwrap, context, validator
|
93
|
+
else
|
94
|
+
super
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def populate_other(other)
|
99
|
+
data.populate_other(other.data)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class AbstractParameter
|
104
|
+
attr_reader :definition
|
105
|
+
extend Forwardable
|
106
|
+
extend Extensions::Freezer
|
107
|
+
include Extensions::Freezer::InstanceMethods
|
108
|
+
include FromHash
|
109
|
+
|
110
|
+
def_delegators :@definition, :name, :altn, :name_for_formatter
|
111
|
+
|
112
|
+
def self.intent_for_children(method, &block)
|
113
|
+
case method
|
114
|
+
when :restriction
|
115
|
+
raise ParamsReadyError, "Block unexpected for '#{method}' method" unless block.nil?
|
116
|
+
define_method :intent_for_children do |intent|
|
117
|
+
intent.for_children(self)
|
118
|
+
end
|
119
|
+
when :delegate
|
120
|
+
define_method :intent_for_children do |intent|
|
121
|
+
delegate_name, *others = self.instance_eval(&block)
|
122
|
+
intent.delegate(self, delegate_name, *others)
|
123
|
+
end
|
124
|
+
when :pass
|
125
|
+
raise ParamsReadyError, "Block unexpected for '#{method}' method" unless block.nil?
|
126
|
+
define_method :intent_for_children do |intent|
|
127
|
+
intent
|
128
|
+
end
|
129
|
+
else
|
130
|
+
raise ParamsReadyError, "Unimplemented permission method: '#{method}'"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
intent_for_children :pass
|
135
|
+
|
136
|
+
def initialize(definition, **options)
|
137
|
+
raise ParamsReadyError, "Unexpected options: #{options}" unless options.empty?
|
138
|
+
@definition = definition
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_in(value, path)
|
142
|
+
_, updated = update_if_applicable(value, path)
|
143
|
+
updated
|
144
|
+
end
|
145
|
+
|
146
|
+
def update_if_applicable(value, path)
|
147
|
+
if path.empty?
|
148
|
+
update_self(value)
|
149
|
+
elsif respond_to? :update_child
|
150
|
+
update_child(value, path)
|
151
|
+
else
|
152
|
+
raise ParamsReadyError, "Expected path to be terminated in '#{name}'"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def populate(context, validator)
|
157
|
+
return if definition.populator.nil?
|
158
|
+
|
159
|
+
definition.populator.call(context, self)
|
160
|
+
validator
|
161
|
+
rescue => error
|
162
|
+
populator_error = PopulatorError.new(error)
|
163
|
+
if validator.nil?
|
164
|
+
raise populator_error
|
165
|
+
else
|
166
|
+
validator.error! populator_error
|
167
|
+
end
|
168
|
+
validator
|
169
|
+
end
|
170
|
+
|
171
|
+
def match?(other)
|
172
|
+
return false unless other.instance_of?(self.class)
|
173
|
+
definition == other.definition
|
174
|
+
end
|
175
|
+
|
176
|
+
def ==(other)
|
177
|
+
return false unless self.match?(other)
|
178
|
+
|
179
|
+
bare_value == other.bare_value
|
180
|
+
rescue
|
181
|
+
false
|
182
|
+
end
|
183
|
+
|
184
|
+
def to_hash(format = Format.instance(:backend), restriction: nil, data: nil)
|
185
|
+
restriction ||= Restriction.blanket_permission
|
186
|
+
intent = Intent.new(format, restriction, data: data)
|
187
|
+
to_hash_if_eligible(intent) || {}
|
188
|
+
end
|
189
|
+
|
190
|
+
def inspect
|
191
|
+
preserve = Format.instance(:inspect).preserve?(self)
|
192
|
+
content = preserve ? inspect_content : '[FILTERED]'
|
193
|
+
"#{self.class.name.split("::").last} #{self.name}: { #{content} }"
|
194
|
+
end
|
195
|
+
|
196
|
+
def dup
|
197
|
+
clone = definition.create
|
198
|
+
populate_other clone
|
199
|
+
clone
|
200
|
+
end
|
201
|
+
|
202
|
+
protected
|
203
|
+
|
204
|
+
def update_self(value)
|
205
|
+
clone = definition.create
|
206
|
+
clone.set_value value
|
207
|
+
clone.freeze if frozen?
|
208
|
+
[true, clone]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
class Parameter < AbstractParameter
|
213
|
+
def_delegators :@definition,
|
214
|
+
:default, :optional?, :default_defined?, :constraints, :no_output?, :no_input?
|
215
|
+
|
216
|
+
def initialize(definition)
|
217
|
+
@value = Extensions::Undefined
|
218
|
+
super definition
|
219
|
+
end
|
220
|
+
|
221
|
+
def set_value(input, context = Format.instance(:backend), validator = nil)
|
222
|
+
if Extensions::Undefined.value_indefinite?(input)
|
223
|
+
handle_indefinite_input(input, validator)
|
224
|
+
elsif self.match? input
|
225
|
+
@value = input.bare_value
|
226
|
+
else
|
227
|
+
begin
|
228
|
+
value, validator = definition.try_canonicalize(input, context, validator)
|
229
|
+
if validator.nil? || validator.ok?
|
230
|
+
if Extensions::Undefined.value_indefinite?(value)
|
231
|
+
handle_indefinite_input(value, validator)
|
232
|
+
else
|
233
|
+
@value = value
|
234
|
+
end
|
235
|
+
end
|
236
|
+
rescue StandardError => e
|
237
|
+
if validator.nil?
|
238
|
+
raise e
|
239
|
+
else
|
240
|
+
validator.error! e
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
validator
|
245
|
+
end
|
246
|
+
|
247
|
+
def definite_default?
|
248
|
+
default_defined? && !default.nil?
|
249
|
+
end
|
250
|
+
|
251
|
+
def nil_default?
|
252
|
+
default_defined? && default.nil?
|
253
|
+
end
|
254
|
+
|
255
|
+
def is_definite?
|
256
|
+
return true if @value != Extensions::Undefined && !@value.nil?
|
257
|
+
return false if optional? && @value.nil?
|
258
|
+
|
259
|
+
definite_default?
|
260
|
+
end
|
261
|
+
|
262
|
+
def is_default?
|
263
|
+
return false unless default_defined?
|
264
|
+
|
265
|
+
@value == Extensions::Undefined || @value == default
|
266
|
+
end
|
267
|
+
|
268
|
+
def is_nil?
|
269
|
+
return false if is_definite?
|
270
|
+
return true if optional?
|
271
|
+
return true if nil_default?
|
272
|
+
|
273
|
+
false
|
274
|
+
end
|
275
|
+
|
276
|
+
def is_undefined?
|
277
|
+
@value == Extensions::Undefined && allows_undefined?
|
278
|
+
end
|
279
|
+
|
280
|
+
def allows_undefined?
|
281
|
+
return true if optional?
|
282
|
+
|
283
|
+
!default_defined?
|
284
|
+
end
|
285
|
+
|
286
|
+
def eligible_for_output?(intent)
|
287
|
+
intent.preserve?(self)
|
288
|
+
end
|
289
|
+
|
290
|
+
def hash_key(format)
|
291
|
+
format.hash_key(self)
|
292
|
+
end
|
293
|
+
|
294
|
+
def set_from_input(input, context, validator)
|
295
|
+
preprocessed = definition.preprocess(input, context, validator)
|
296
|
+
set_value preprocessed, context, validator
|
297
|
+
definition.postprocess(self, context, validator)
|
298
|
+
validator
|
299
|
+
end
|
300
|
+
|
301
|
+
def to_hash_if_eligible(intent = Intent.instance(:backend))
|
302
|
+
return nil unless eligible_for_output? intent
|
303
|
+
|
304
|
+
formatted = format_self_permitted(intent)
|
305
|
+
wrap_output(formatted, intent)
|
306
|
+
end
|
307
|
+
|
308
|
+
def format_self_permitted(intent)
|
309
|
+
intent = intent_for_children(intent)
|
310
|
+
format(intent)
|
311
|
+
end
|
312
|
+
|
313
|
+
def format(intent)
|
314
|
+
value = memo(intent)
|
315
|
+
return value if value != Extensions::Undefined
|
316
|
+
|
317
|
+
value = marshal(intent)
|
318
|
+
memo!(value, intent)
|
319
|
+
value
|
320
|
+
end
|
321
|
+
|
322
|
+
def memo(intent)
|
323
|
+
return Extensions::Undefined if @memo.nil?
|
324
|
+
|
325
|
+
@memo.cached_value(intent)
|
326
|
+
end
|
327
|
+
|
328
|
+
def memo!(value, intent)
|
329
|
+
return if @memo.nil? || !frozen?
|
330
|
+
|
331
|
+
@memo.cache_value(value, intent)
|
332
|
+
end
|
333
|
+
|
334
|
+
def wrap_output(output, intent)
|
335
|
+
name_or_path = hash_key(intent)
|
336
|
+
if name_or_path.is_a? Array
|
337
|
+
*path, name = name_or_path
|
338
|
+
result = {}
|
339
|
+
Helpers::KeyMap::Mapping::Path.store(name, output, result, path)
|
340
|
+
result
|
341
|
+
else
|
342
|
+
{ name_or_path => output }
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def unwrap
|
347
|
+
format(Intent.instance(:backend))
|
348
|
+
end
|
349
|
+
|
350
|
+
def unwrap_or(*args, &block)
|
351
|
+
ensure_default_present!(*args, &block)
|
352
|
+
|
353
|
+
if is_definite?
|
354
|
+
begin
|
355
|
+
unwrap
|
356
|
+
rescue StandardError => _
|
357
|
+
supply_default(*args, &block)
|
358
|
+
end
|
359
|
+
else
|
360
|
+
supply_default(*args, &block)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def find_in_hash(hash, context)
|
365
|
+
Helpers::FindInHash.find_in_hash hash, hash_key(context)
|
366
|
+
end
|
367
|
+
|
368
|
+
def populate_other(other)
|
369
|
+
raise ParamsReadyError, "Not a matching param: #{other.class.name}" unless match? other
|
370
|
+
return other unless is_definite?
|
371
|
+
|
372
|
+
value = bare_value
|
373
|
+
other.populate_with(value)
|
374
|
+
other
|
375
|
+
end
|
376
|
+
|
377
|
+
def inspect_content
|
378
|
+
@value.inspect
|
379
|
+
end
|
380
|
+
|
381
|
+
freeze_variable :value
|
382
|
+
|
383
|
+
def freeze
|
384
|
+
if definition.memoize? and !frozen?
|
385
|
+
@memo = Helpers::Memo.new(definition.memoize)
|
386
|
+
end
|
387
|
+
init_for_read true
|
388
|
+
super
|
389
|
+
end
|
390
|
+
|
391
|
+
def hash
|
392
|
+
[definition, @value].hash
|
393
|
+
end
|
394
|
+
|
395
|
+
alias_method :eql?, :==
|
396
|
+
|
397
|
+
protected
|
398
|
+
|
399
|
+
def handle_indefinite_input(input, validator)
|
400
|
+
value_missing validator
|
401
|
+
if default_defined?
|
402
|
+
# if value_missing doesn't crash,
|
403
|
+
# and the parameter is optional
|
404
|
+
# it's safe to set to nil or Extensions::Undefined
|
405
|
+
@value = Extensions::Undefined
|
406
|
+
elsif optional?
|
407
|
+
# Clear possible previous state,
|
408
|
+
# will be set to default on read
|
409
|
+
@value = input
|
410
|
+
else
|
411
|
+
raise ParamsReadyError, "Unexpected state for '#{name}' in #handle_indefinite_input" if validator.ok?
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def value_missing(validator = nil)
|
416
|
+
if !nil_allowed?
|
417
|
+
e = ValueMissingError.new self.name
|
418
|
+
if validator
|
419
|
+
validator.error!(e)
|
420
|
+
else
|
421
|
+
raise e
|
422
|
+
end
|
423
|
+
end
|
424
|
+
validator
|
425
|
+
end
|
426
|
+
|
427
|
+
def nil_allowed?
|
428
|
+
optional? || default_defined?
|
429
|
+
end
|
430
|
+
|
431
|
+
def bare_value
|
432
|
+
init_for_read
|
433
|
+
return @value if is_definite?
|
434
|
+
|
435
|
+
value_missing
|
436
|
+
nil
|
437
|
+
end
|
438
|
+
|
439
|
+
def ensure_default_present!(*args, &block)
|
440
|
+
raise ParamsReadyError, 'Single default value expected' if args.length > 1
|
441
|
+
raise ParamsReadyError, 'Supply either default or a block' if args.length == 0 && block.nil?
|
442
|
+
warn 'WARNING: block supersedes default value' if args.length > 0 && block
|
443
|
+
end
|
444
|
+
|
445
|
+
def supply_default(*args, &block)
|
446
|
+
if block.nil?
|
447
|
+
args[0]
|
448
|
+
else
|
449
|
+
block.call
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def init_for_read(to_be_frozen = false)
|
454
|
+
return unless @value == Extensions::Undefined
|
455
|
+
return unless default_defined?
|
456
|
+
|
457
|
+
@value = definition.fetch_default(duplicate: !to_be_frozen)
|
458
|
+
end
|
459
|
+
|
460
|
+
def init_for_write
|
461
|
+
return if is_definite?
|
462
|
+
|
463
|
+
if default_defined? && !default.nil?
|
464
|
+
@value = definition.fetch_default
|
465
|
+
else
|
466
|
+
init_value
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def init_value
|
471
|
+
# NOOP
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|