params_ready_rails5 0.0.7
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/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,204 @@
|
|
1
|
+
require_relative 'parameter'
|
2
|
+
require_relative '../helpers/key_map'
|
3
|
+
require_relative '../marshaller/struct_marshallers'
|
4
|
+
require_relative '../marshaller/builder_module'
|
5
|
+
require_relative '../marshaller/definition_module'
|
6
|
+
|
7
|
+
module ParamsReady
|
8
|
+
module Parameter
|
9
|
+
using Extensions::Hash
|
10
|
+
|
11
|
+
class AbstractStructParameter < Parameter
|
12
|
+
include ComplexParameter
|
13
|
+
|
14
|
+
def_delegators :@definition, :names, :remap?
|
15
|
+
intent_for_children :restriction
|
16
|
+
|
17
|
+
EMPTY_HASH = '0'
|
18
|
+
|
19
|
+
freeze_variable :value do |value|
|
20
|
+
next if value.nil? || value == Extensions::Undefined
|
21
|
+
|
22
|
+
value.values.each do |child|
|
23
|
+
child.freeze
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def []=(name, value)
|
28
|
+
init_for_write
|
29
|
+
c = child(name)
|
30
|
+
c.set_value(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](name)
|
34
|
+
child(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_in_hash(hash, context)
|
38
|
+
found, result = super hash, context
|
39
|
+
|
40
|
+
if !(default_defined? || optional?) && result == Extensions::Undefined
|
41
|
+
# nil value for non-default and non-optional hash means
|
42
|
+
# children may be able to set themselves if they have defaults
|
43
|
+
[true, {}]
|
44
|
+
elsif result == EMPTY_HASH
|
45
|
+
[true, {}]
|
46
|
+
else
|
47
|
+
[found, result]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def wrap_output(output, intent)
|
52
|
+
if (output.nil? || output.empty?) && !default_defined? && !optional?
|
53
|
+
nil
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def for_output(format, restriction: nil, data: nil)
|
60
|
+
restriction ||= Restriction.blanket_permission
|
61
|
+
|
62
|
+
intent = Intent.new(format, restriction, data: data)
|
63
|
+
output = format(intent)
|
64
|
+
return {} if output.nil? || output == EMPTY_HASH
|
65
|
+
output
|
66
|
+
end
|
67
|
+
|
68
|
+
def for_frontend(format = :frontend, restriction: nil, data: nil)
|
69
|
+
for_output(format, restriction: restriction, data: data)
|
70
|
+
end
|
71
|
+
|
72
|
+
def for_model(format = :update, restriction: nil)
|
73
|
+
for_output(format, restriction: restriction)
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def child_for_update(path)
|
79
|
+
child_name, *path = path
|
80
|
+
[self[child_name], child_name, path]
|
81
|
+
end
|
82
|
+
|
83
|
+
def updated_clone(name, updated)
|
84
|
+
clone = definition.create
|
85
|
+
frozen = frozen? || @value&.frozen?
|
86
|
+
clone.populate_with(bare_value, frozen, name => updated)
|
87
|
+
end
|
88
|
+
|
89
|
+
def child(name)
|
90
|
+
return nil if is_nil?
|
91
|
+
|
92
|
+
value = bare_value
|
93
|
+
raise ParamsReadyError, "No such name: #{name}" unless names.key? name
|
94
|
+
if value.key? name
|
95
|
+
value[name]
|
96
|
+
else
|
97
|
+
child = definition.child_definition(name).create
|
98
|
+
raise ParamsReadyError, "Expected definite value for '#{name}' parameter" if child.nil?
|
99
|
+
place(name, child) unless frozen?
|
100
|
+
child
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def populate_with(hash, freeze = false, **replacement)
|
105
|
+
@value = {}
|
106
|
+
names.each_key do |name|
|
107
|
+
incoming = replacement[name] || hash[name]
|
108
|
+
|
109
|
+
own = if freeze && incoming.frozen?
|
110
|
+
incoming
|
111
|
+
else
|
112
|
+
incoming.dup
|
113
|
+
end
|
114
|
+
|
115
|
+
own.freeze if freeze
|
116
|
+
|
117
|
+
place(name, own)
|
118
|
+
end
|
119
|
+
|
120
|
+
self.freeze if freeze
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
def place(name, child)
|
125
|
+
@value[name] = child
|
126
|
+
end
|
127
|
+
|
128
|
+
def init_value
|
129
|
+
@value = names.map do |name, definition|
|
130
|
+
[name, definition.create]
|
131
|
+
end.to_h
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
module AbstractStructParameterBuilder
|
136
|
+
include Marshaller::BuilderModule
|
137
|
+
|
138
|
+
module StructLike
|
139
|
+
def add(input, *args, **opts, &block)
|
140
|
+
definition = self.class.resolve(input, *args, **opts, &block)
|
141
|
+
@definition.add_child definition
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class AbstractStructParameterDefinition < Definition
|
147
|
+
attr_reader :key_map
|
148
|
+
|
149
|
+
def duplicate_value(value)
|
150
|
+
value.values.map do |param|
|
151
|
+
[param.name, param.dup]
|
152
|
+
end.to_h
|
153
|
+
end
|
154
|
+
|
155
|
+
def freeze_value(value)
|
156
|
+
value.values.each(&:freeze)
|
157
|
+
value.freeze
|
158
|
+
end
|
159
|
+
|
160
|
+
attr_reader :names
|
161
|
+
|
162
|
+
def initialize(*args, **options)
|
163
|
+
super *args, **options
|
164
|
+
@key_map = nil
|
165
|
+
@names = {}
|
166
|
+
end
|
167
|
+
|
168
|
+
def child_definition(name)
|
169
|
+
raise ParamsReadyError, "No such name: #{name}" unless names.key? name
|
170
|
+
names[name]
|
171
|
+
end
|
172
|
+
|
173
|
+
def has_child?(name)
|
174
|
+
names.key? name
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_default(value)
|
178
|
+
value = infer_default if value == :inferred
|
179
|
+
super(value)
|
180
|
+
end
|
181
|
+
|
182
|
+
def infer_default
|
183
|
+
names.reduce({}) do |result, pair|
|
184
|
+
child_def = pair[1]
|
185
|
+
unless child_def.default_defined?
|
186
|
+
raise ParamsReadyError, "Can't infer default, child '#{definition.name}' is not optional and has no default" unless child_def.optional?
|
187
|
+
else
|
188
|
+
result[child_def.name] = child_def.default
|
189
|
+
end
|
190
|
+
result
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def add_child(child)
|
195
|
+
raise ParamsReadyError, "Not a parameter definition: '#{child.class.name}'" unless child.is_a?(AbstractDefinition)
|
196
|
+
raise ParamsReadyError, "Name already there: '#{child.name}'" if @names.key?(child.name)
|
197
|
+
raise ParamsReadyError, "Child can't be added after default has been set" if default_defined?
|
198
|
+
@names[child.name] = child
|
199
|
+
end
|
200
|
+
|
201
|
+
freeze_variables :names
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require_relative 'parameter'
|
2
|
+
require_relative 'definition'
|
3
|
+
require_relative 'abstract_struct_parameter'
|
4
|
+
require_relative '../builder'
|
5
|
+
require_relative '../marshaller/array_marshallers'
|
6
|
+
require_relative '../marshaller/builder_module'
|
7
|
+
require_relative '../marshaller/definition_module'
|
8
|
+
require_relative '../marshaller/parameter_module'
|
9
|
+
|
10
|
+
module ParamsReady
|
11
|
+
module Parameter
|
12
|
+
class ArrayParameter < Parameter
|
13
|
+
module ArrayLike
|
14
|
+
include ComplexParameter
|
15
|
+
|
16
|
+
def []=(index, value)
|
17
|
+
init_for_write
|
18
|
+
c = element(index)
|
19
|
+
c.set_value value
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](index)
|
23
|
+
if index == :cnt || index == 'cnt'
|
24
|
+
count = ValueParameterBuilder.instance(:cnt, :integer).build.create
|
25
|
+
count.set_value(self.length)
|
26
|
+
count.freeze
|
27
|
+
count
|
28
|
+
else
|
29
|
+
element(index)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def updated_clone(index, updated_child)
|
36
|
+
clone = definition.create
|
37
|
+
clone.populate_with(bare_value, frozen?, { index => updated_child })
|
38
|
+
clone
|
39
|
+
end
|
40
|
+
|
41
|
+
def child_for_update(path)
|
42
|
+
index, *child_path = path
|
43
|
+
child = element(index)
|
44
|
+
raise ParamsReadyError, "No element at index '#{index}' in '#{name}'" if child.nil?
|
45
|
+
[child, index, child_path]
|
46
|
+
end
|
47
|
+
|
48
|
+
def populate_with(array, freeze = false, replacement = {})
|
49
|
+
@value = []
|
50
|
+
array.each_with_index do |element, index|
|
51
|
+
incoming = replacement[index] || element
|
52
|
+
|
53
|
+
own = if freeze && incoming.frozen?
|
54
|
+
incoming
|
55
|
+
else
|
56
|
+
incoming.dup
|
57
|
+
end
|
58
|
+
|
59
|
+
own.freeze if freeze
|
60
|
+
|
61
|
+
@value << own
|
62
|
+
end
|
63
|
+
|
64
|
+
self.freeze if freeze
|
65
|
+
self
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
include ArrayLike
|
70
|
+
include Marshaller::ParameterModule
|
71
|
+
|
72
|
+
intent_for_children :delegate do
|
73
|
+
definition.prototype.name
|
74
|
+
end
|
75
|
+
|
76
|
+
def_delegators :@definition, :prototype
|
77
|
+
def_delegators :bare_value, :length, :count, :each, :each_with_index, :map, :reduce, :to_a
|
78
|
+
|
79
|
+
freeze_variable :value do |array|
|
80
|
+
array.each(&:freeze)
|
81
|
+
end
|
82
|
+
|
83
|
+
def <<(value)
|
84
|
+
init_for_write
|
85
|
+
c = element(length, for_write: true)
|
86
|
+
c.set_value value
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
def element(index, for_write: false)
|
93
|
+
return nil if is_nil?
|
94
|
+
|
95
|
+
value = bare_value
|
96
|
+
if value.length > index
|
97
|
+
value[index]
|
98
|
+
elsif value.length == index && for_write
|
99
|
+
value << prototype.create
|
100
|
+
value[index]
|
101
|
+
else
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def init_value
|
107
|
+
@value = []
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ArrayParameterBuilder < Builder
|
112
|
+
module ArrayLike
|
113
|
+
def prototype(input, name = nil, *args, altn: nil, **opts, &block)
|
114
|
+
name ||= :element
|
115
|
+
altn ||= :elm
|
116
|
+
definition = self.class.resolve(input, name, *args, altn: altn, **opts, &block)
|
117
|
+
@definition.set_prototype definition
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
include ArrayLike
|
122
|
+
register :array
|
123
|
+
include Marshaller::BuilderModule
|
124
|
+
|
125
|
+
def self.instance(name, altn: nil)
|
126
|
+
new ArrayParameterDefinition.new(name, altn: altn)
|
127
|
+
end
|
128
|
+
|
129
|
+
def compact
|
130
|
+
@definition.set_compact true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class ArrayParameterDefinition < Definition
|
135
|
+
name_for_formatter :array
|
136
|
+
include Marshaller::DefinitionModule[Marshaller::ArrayMarshallers.collection]
|
137
|
+
|
138
|
+
module ArrayLike
|
139
|
+
def duplicate_value(value)
|
140
|
+
value.map do |param|
|
141
|
+
param.dup
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def freeze_value(value)
|
146
|
+
value.each(&:freeze)
|
147
|
+
value.freeze
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
include ArrayLike
|
152
|
+
|
153
|
+
parameter_class ArrayParameter
|
154
|
+
|
155
|
+
def initialize(*args, prototype: nil, **options)
|
156
|
+
raise ParamsReadyError, "Not a definition: #{prototype.class.name}" unless (prototype.is_a?(Definition) || prototype.nil?)
|
157
|
+
@prototype = prototype
|
158
|
+
super *args, **options
|
159
|
+
end
|
160
|
+
|
161
|
+
def set_default(args)
|
162
|
+
raise ParamsReadyError, "Can't set default before prototype has been defined" if @prototype.nil?
|
163
|
+
super
|
164
|
+
end
|
165
|
+
|
166
|
+
late_init :prototype do |prototype|
|
167
|
+
raise ParamsReadyError, "Can't set prototype after default has been set" if default_defined?
|
168
|
+
prototype
|
169
|
+
end
|
170
|
+
|
171
|
+
late_init :compact, obligatory: false, boolean: true, getter: false
|
172
|
+
|
173
|
+
def ensure_canonical(array)
|
174
|
+
raise "Not a canonical value, array expected, got: '#{array.class.name}'" unless array.is_a? Array
|
175
|
+
context = Format.instance(:backend)
|
176
|
+
value, _validator = try_canonicalize(array, context, nil, freeze: true)
|
177
|
+
value
|
178
|
+
end
|
179
|
+
|
180
|
+
def try_canonicalize(value, context, validator = nil, freeze: false)
|
181
|
+
if freeze
|
182
|
+
marshaller = marshallers.instance(Array)
|
183
|
+
marshaller.canonicalize self, value, context, validator, freeze: freeze
|
184
|
+
else
|
185
|
+
super value, context, validator
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def finish
|
190
|
+
if compact? && (prototype&.default_defined?)
|
191
|
+
raise ParamsReadyError, 'Prototype must not be optional nor have default in compact array parameter'
|
192
|
+
end
|
193
|
+
super
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require_relative '../extensions/freezer'
|
2
|
+
require_relative '../extensions/finalizer'
|
3
|
+
require_relative '../error'
|
4
|
+
require_relative '../extensions/class_reader_writer'
|
5
|
+
require_relative '../extensions/collection'
|
6
|
+
require_relative '../extensions/delegation'
|
7
|
+
require_relative '../extensions/late_init'
|
8
|
+
require_relative '../extensions/undefined'
|
9
|
+
require_relative '../input_context'
|
10
|
+
require_relative '../result'
|
11
|
+
require_relative '../helpers/conditional_block'
|
12
|
+
require_relative '../helpers/callable'
|
13
|
+
|
14
|
+
module ParamsReady
|
15
|
+
module Parameter
|
16
|
+
class AbstractDefinition
|
17
|
+
extend Extensions::Freezer
|
18
|
+
include Extensions::Freezer::InstanceMethods
|
19
|
+
extend Extensions::Finalizer
|
20
|
+
include Extensions::Finalizer::InstanceMethods
|
21
|
+
extend Extensions::ClassReaderWriter
|
22
|
+
extend Extensions::LateInit
|
23
|
+
extend Extensions::Collection
|
24
|
+
|
25
|
+
attr_reader :name, :altn
|
26
|
+
|
27
|
+
def parameter_class
|
28
|
+
self.class.parameter_class
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(name, altn: nil)
|
32
|
+
@name = name.to_sym
|
33
|
+
@altn = normalize_alternative_name(altn || name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def normalize_alternative_name(name)
|
37
|
+
if name.is_a? Array
|
38
|
+
name.map(&:to_sym)
|
39
|
+
else
|
40
|
+
name.to_sym
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class_reader_writer :parameter_class
|
45
|
+
collection :helpers, :helper
|
46
|
+
|
47
|
+
def create
|
48
|
+
raise ParamsReadyError, "Can't create '#{name}' using unfrozen definition" unless frozen?
|
49
|
+
instance = parameter_class.new self
|
50
|
+
if @helpers
|
51
|
+
singleton = class << instance; self; end
|
52
|
+
@helpers.each do |(name, block)|
|
53
|
+
if singleton.method_defined? name
|
54
|
+
raise ParamsReadyError, "Helper '#{name}' overrides existing method"
|
55
|
+
end
|
56
|
+
|
57
|
+
singleton.send :define_method, name, &block
|
58
|
+
end
|
59
|
+
end
|
60
|
+
instance
|
61
|
+
end
|
62
|
+
|
63
|
+
def from_hash(hash, context: nil, validator: Result.new(name))
|
64
|
+
context = InputContext.resolve(context)
|
65
|
+
instance = create
|
66
|
+
result = instance.set_from_hash(hash, context: context, validator: validator)
|
67
|
+
[result, instance]
|
68
|
+
end
|
69
|
+
|
70
|
+
def from_input(input, context: nil, validator: nil)
|
71
|
+
validator ||= Result.new(name)
|
72
|
+
context = InputContext.resolve(context)
|
73
|
+
instance = create
|
74
|
+
result = instance.set_from_input(input, context, validator)
|
75
|
+
[result, instance]
|
76
|
+
end
|
77
|
+
|
78
|
+
def finish
|
79
|
+
super
|
80
|
+
freeze
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Definition < AbstractDefinition
|
85
|
+
attr_reader :default
|
86
|
+
|
87
|
+
class_reader_writer :name_for_formatter
|
88
|
+
|
89
|
+
def name_for_formatter
|
90
|
+
self.class.name_for_formatter
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize(
|
94
|
+
*args,
|
95
|
+
default: Extensions::Undefined,
|
96
|
+
optional: false,
|
97
|
+
preprocessor: nil,
|
98
|
+
populator: nil,
|
99
|
+
postprocessor: nil,
|
100
|
+
no_input: nil,
|
101
|
+
no_output: nil,
|
102
|
+
**opts
|
103
|
+
)
|
104
|
+
super *args, **opts
|
105
|
+
@default = Extensions::Undefined
|
106
|
+
@optional = optional
|
107
|
+
@preprocessor = preprocessor
|
108
|
+
@postprocessor = postprocessor
|
109
|
+
@populator = populator
|
110
|
+
@no_input = no_input
|
111
|
+
@no_output = no_output
|
112
|
+
|
113
|
+
set_default(default) unless default == Extensions::Undefined
|
114
|
+
end
|
115
|
+
|
116
|
+
def default_defined?
|
117
|
+
return false unless defined? @default
|
118
|
+
return false if @default == Extensions::Undefined
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
def canonical_default(value)
|
123
|
+
return value if value.nil?
|
124
|
+
ensure_canonical value
|
125
|
+
rescue => e
|
126
|
+
raise ParamsReadyError, "Invalid default: #{e.message}"
|
127
|
+
end
|
128
|
+
|
129
|
+
late_init :populator, getter: true, once: true, obligatory: false
|
130
|
+
late_init :no_input, getter: false, once: false
|
131
|
+
late_init :no_output, getter: false, once: false
|
132
|
+
late_init :memoize, getter: true, obligatory: false
|
133
|
+
|
134
|
+
def memoize?
|
135
|
+
return false if @memoize.nil?
|
136
|
+
|
137
|
+
@memoize > 0
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_preprocessor(rule: nil, &block)
|
141
|
+
raise "Preprocesser already set in '#{name}'" unless @preprocessor.nil?
|
142
|
+
@preprocessor = Helpers::ConditionalBlock.new(rule: rule, &block)
|
143
|
+
end
|
144
|
+
|
145
|
+
def set_postprocessor(rule: nil, &block)
|
146
|
+
raise "Postprocessor already set in '#{name}'" unless @postprocessor.nil?
|
147
|
+
@postprocessor = Helpers::ConditionalBlock.new(rule: rule, &block)
|
148
|
+
end
|
149
|
+
|
150
|
+
def preprocess(input, context, validator)
|
151
|
+
return input if @preprocessor.nil?
|
152
|
+
return input unless @preprocessor.perform?(!context.local?, context.name)
|
153
|
+
@preprocessor.block.call input, context, self
|
154
|
+
rescue => error
|
155
|
+
preprocessor_error = PreprocessorError.new(error)
|
156
|
+
if validator.nil?
|
157
|
+
raise preprocessor_error
|
158
|
+
else
|
159
|
+
validator.error! preprocessor_error
|
160
|
+
Extensions::Undefined
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def postprocess(param, context, validator)
|
165
|
+
return if @postprocessor.nil?
|
166
|
+
return unless @postprocessor.perform?(!context.local?, context.name)
|
167
|
+
@postprocessor.block.call param, context
|
168
|
+
rescue => error
|
169
|
+
postprocessor_error = PostprocessorError.new(error)
|
170
|
+
if validator.nil?
|
171
|
+
raise postprocessor_error
|
172
|
+
else
|
173
|
+
validator.error! postprocessor_error
|
174
|
+
end
|
175
|
+
validator
|
176
|
+
end
|
177
|
+
|
178
|
+
def set_no_input(*arr, rule: nil)
|
179
|
+
@no_input = Helpers::Rule(rule) || true
|
180
|
+
raise ParamsReadyError, "Default not expected: #{arr}" if rule == false
|
181
|
+
|
182
|
+
set_default *arr unless arr.empty?
|
183
|
+
end
|
184
|
+
|
185
|
+
def set_local(*arr, rule: nil)
|
186
|
+
rule = Helpers::Rule(rule)
|
187
|
+
set_no_input(*arr, rule: rule)
|
188
|
+
set_no_output(rule || true)
|
189
|
+
end
|
190
|
+
|
191
|
+
def no_input?(format)
|
192
|
+
restricted_for_format?(@no_input, format)
|
193
|
+
end
|
194
|
+
|
195
|
+
def no_output?(format)
|
196
|
+
restricted_for_format?(@no_output, format)
|
197
|
+
end
|
198
|
+
|
199
|
+
def restricted_for_format?(rule, format)
|
200
|
+
case rule
|
201
|
+
when nil, false
|
202
|
+
false
|
203
|
+
when true
|
204
|
+
!format.local?
|
205
|
+
when Helpers::Rule
|
206
|
+
rule.include?(format.name)
|
207
|
+
else
|
208
|
+
raise ParamsReadyError, "Unexpected rule: #{rule}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
late_init :optional, boolean: true, getter: false, once: false
|
213
|
+
|
214
|
+
late_init :default, once: false, definite: false do |value|
|
215
|
+
next value if value == Extensions::Undefined
|
216
|
+
next value if value.is_a? Helpers::Callable
|
217
|
+
|
218
|
+
canonical = canonical_default(value)
|
219
|
+
next canonical if canonical.nil?
|
220
|
+
|
221
|
+
freeze_value(canonical)
|
222
|
+
end
|
223
|
+
|
224
|
+
def fetch_default(duplicate: true)
|
225
|
+
return Extensions::Undefined unless default_defined?
|
226
|
+
return nil if @default.nil?
|
227
|
+
|
228
|
+
if @default.is_a?(Helpers::Callable)
|
229
|
+
fetch_callable_default
|
230
|
+
else
|
231
|
+
return @default unless duplicate
|
232
|
+
duplicate_value(@default)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def fetch_callable_default
|
237
|
+
value = @default.call
|
238
|
+
value = ensure_canonical(value)
|
239
|
+
duplicate_value(value)
|
240
|
+
rescue StandardError => e
|
241
|
+
raise ParamsReadyError, "Invalid default: #{e.message}"
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
def finish
|
246
|
+
if @populator && !@no_input
|
247
|
+
raise ParamsReadyError, "Populator set for input parameter '#{name}'"
|
248
|
+
end
|
249
|
+
|
250
|
+
if @preprocessor && @no_input == true
|
251
|
+
raise ParamsReadyError, "Preprocessor set for no-input parameter '#{name}'"
|
252
|
+
end
|
253
|
+
|
254
|
+
if @postprocessor && @no_input == true
|
255
|
+
raise ParamsReadyError, "Postprocessor set for no-input parameter '#{name}'"
|
256
|
+
end
|
257
|
+
|
258
|
+
super
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
module DelegatingDefinition
|
263
|
+
def self.[](delegee_name)
|
264
|
+
mod = Module.new
|
265
|
+
Extensions::Delegation.delegate(mod) do
|
266
|
+
instance_variable_get(:"@#{delegee_name}")
|
267
|
+
end
|
268
|
+
mod
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|