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