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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/lib/arel/cte_name.rb +20 -0
  3. data/lib/params_ready/builder.rb +161 -0
  4. data/lib/params_ready/error.rb +31 -0
  5. data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
  6. data/lib/params_ready/extensions/collection.rb +43 -0
  7. data/lib/params_ready/extensions/delegation.rb +25 -0
  8. data/lib/params_ready/extensions/finalizer.rb +26 -0
  9. data/lib/params_ready/extensions/freezer.rb +49 -0
  10. data/lib/params_ready/extensions/hash.rb +46 -0
  11. data/lib/params_ready/extensions/late_init.rb +38 -0
  12. data/lib/params_ready/extensions/registry.rb +44 -0
  13. data/lib/params_ready/extensions/undefined.rb +23 -0
  14. data/lib/params_ready/format.rb +132 -0
  15. data/lib/params_ready/helpers/arel_builder.rb +68 -0
  16. data/lib/params_ready/helpers/callable.rb +14 -0
  17. data/lib/params_ready/helpers/conditional_block.rb +31 -0
  18. data/lib/params_ready/helpers/find_in_hash.rb +22 -0
  19. data/lib/params_ready/helpers/interface_definer.rb +48 -0
  20. data/lib/params_ready/helpers/key_map.rb +176 -0
  21. data/lib/params_ready/helpers/memo.rb +41 -0
  22. data/lib/params_ready/helpers/options.rb +107 -0
  23. data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
  24. data/lib/params_ready/helpers/parameter_storage_class_methods.rb +63 -0
  25. data/lib/params_ready/helpers/parameter_user_class_methods.rb +35 -0
  26. data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
  27. data/lib/params_ready/helpers/rule.rb +76 -0
  28. data/lib/params_ready/helpers/storage.rb +30 -0
  29. data/lib/params_ready/helpers/usage_rule.rb +36 -0
  30. data/lib/params_ready/input_context.rb +31 -0
  31. data/lib/params_ready/intent.rb +70 -0
  32. data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
  33. data/lib/params_ready/marshaller/builder_module.rb +9 -0
  34. data/lib/params_ready/marshaller/collection.rb +165 -0
  35. data/lib/params_ready/marshaller/definition_module.rb +63 -0
  36. data/lib/params_ready/marshaller/enum_set_marshallers.rb +96 -0
  37. data/lib/params_ready/marshaller/parameter_module.rb +11 -0
  38. data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
  39. data/lib/params_ready/marshaller/struct_marshallers.rb +100 -0
  40. data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
  41. data/lib/params_ready/ordering/column.rb +60 -0
  42. data/lib/params_ready/ordering/ordering.rb +276 -0
  43. data/lib/params_ready/output_parameters.rb +138 -0
  44. data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
  45. data/lib/params_ready/pagination/cursor.rb +171 -0
  46. data/lib/params_ready/pagination/direction.rb +148 -0
  47. data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
  48. data/lib/params_ready/pagination/keysets.rb +70 -0
  49. data/lib/params_ready/pagination/nulls.rb +31 -0
  50. data/lib/params_ready/pagination/offset_pagination.rb +130 -0
  51. data/lib/params_ready/pagination/tendency.rb +28 -0
  52. data/lib/params_ready/parameter/abstract_struct_parameter.rb +204 -0
  53. data/lib/params_ready/parameter/array_parameter.rb +197 -0
  54. data/lib/params_ready/parameter/definition.rb +272 -0
  55. data/lib/params_ready/parameter/enum_set_parameter.rb +102 -0
  56. data/lib/params_ready/parameter/parameter.rb +475 -0
  57. data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
  58. data/lib/params_ready/parameter/state.rb +132 -0
  59. data/lib/params_ready/parameter/struct_parameter.rb +64 -0
  60. data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
  61. data/lib/params_ready/parameter/value_parameter.rb +186 -0
  62. data/lib/params_ready/parameter_definer.rb +14 -0
  63. data/lib/params_ready/parameter_user.rb +35 -0
  64. data/lib/params_ready/query/array_grouping.rb +68 -0
  65. data/lib/params_ready/query/custom_predicate.rb +102 -0
  66. data/lib/params_ready/query/exists_predicate.rb +103 -0
  67. data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
  68. data/lib/params_ready/query/grouping.rb +177 -0
  69. data/lib/params_ready/query/join_clause.rb +87 -0
  70. data/lib/params_ready/query/nullness_predicate.rb +71 -0
  71. data/lib/params_ready/query/polymorph_predicate.rb +77 -0
  72. data/lib/params_ready/query/predicate.rb +203 -0
  73. data/lib/params_ready/query/predicate_operator.rb +132 -0
  74. data/lib/params_ready/query/relation.rb +337 -0
  75. data/lib/params_ready/query/structured_grouping.rb +58 -0
  76. data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
  77. data/lib/params_ready/query_context.rb +21 -0
  78. data/lib/params_ready/restriction.rb +252 -0
  79. data/lib/params_ready/result.rb +109 -0
  80. data/lib/params_ready/value/coder.rb +210 -0
  81. data/lib/params_ready/value/constraint.rb +198 -0
  82. data/lib/params_ready/value/custom.rb +56 -0
  83. data/lib/params_ready/value/validator.rb +81 -0
  84. data/lib/params_ready/version.rb +7 -0
  85. data/lib/params_ready.rb +28 -0
  86. 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