params_ready 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/arel/cte_name.rb +20 -0
  3. data/lib/params_ready.rb +36 -0
  4. data/lib/params_ready/builder.rb +140 -0
  5. data/lib/params_ready/error.rb +31 -0
  6. data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
  7. data/lib/params_ready/extensions/collection.rb +43 -0
  8. data/lib/params_ready/extensions/delegation.rb +25 -0
  9. data/lib/params_ready/extensions/finalizer.rb +26 -0
  10. data/lib/params_ready/extensions/freezer.rb +49 -0
  11. data/lib/params_ready/extensions/hash.rb +46 -0
  12. data/lib/params_ready/extensions/late_init.rb +38 -0
  13. data/lib/params_ready/extensions/registry.rb +44 -0
  14. data/lib/params_ready/extensions/undefined.rb +15 -0
  15. data/lib/params_ready/format.rb +130 -0
  16. data/lib/params_ready/helpers/arel_builder.rb +68 -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/key_map.rb +176 -0
  20. data/lib/params_ready/helpers/memo.rb +42 -0
  21. data/lib/params_ready/helpers/options.rb +39 -0
  22. data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
  23. data/lib/params_ready/helpers/parameter_storage_class_methods.rb +36 -0
  24. data/lib/params_ready/helpers/parameter_user_class_methods.rb +31 -0
  25. data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
  26. data/lib/params_ready/helpers/rule.rb +57 -0
  27. data/lib/params_ready/helpers/storage.rb +30 -0
  28. data/lib/params_ready/helpers/usage_rule.rb +18 -0
  29. data/lib/params_ready/input_context.rb +31 -0
  30. data/lib/params_ready/intent.rb +70 -0
  31. data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
  32. data/lib/params_ready/marshaller/builder_module.rb +9 -0
  33. data/lib/params_ready/marshaller/collection.rb +165 -0
  34. data/lib/params_ready/marshaller/definition_module.rb +63 -0
  35. data/lib/params_ready/marshaller/hash_marshallers.rb +100 -0
  36. data/lib/params_ready/marshaller/hash_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/tuple_marshallers.rb +103 -0
  40. data/lib/params_ready/ordering/column.rb +60 -0
  41. data/lib/params_ready/ordering/ordering.rb +276 -0
  42. data/lib/params_ready/output_parameters.rb +127 -0
  43. data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
  44. data/lib/params_ready/pagination/cursor.rb +171 -0
  45. data/lib/params_ready/pagination/direction.rb +148 -0
  46. data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
  47. data/lib/params_ready/pagination/keysets.rb +70 -0
  48. data/lib/params_ready/pagination/nulls.rb +31 -0
  49. data/lib/params_ready/pagination/offset_pagination.rb +130 -0
  50. data/lib/params_ready/pagination/tendency.rb +28 -0
  51. data/lib/params_ready/parameter/abstract_hash_parameter.rb +204 -0
  52. data/lib/params_ready/parameter/array_parameter.rb +197 -0
  53. data/lib/params_ready/parameter/definition.rb +264 -0
  54. data/lib/params_ready/parameter/hash_parameter.rb +63 -0
  55. data/lib/params_ready/parameter/hash_set_parameter.rb +101 -0
  56. data/lib/params_ready/parameter/parameter.rb +456 -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/tuple_parameter.rb +152 -0
  60. data/lib/params_ready/parameter/value_parameter.rb +182 -0
  61. data/lib/params_ready/parameter_definer.rb +14 -0
  62. data/lib/params_ready/parameter_user.rb +43 -0
  63. data/lib/params_ready/query/array_grouping.rb +68 -0
  64. data/lib/params_ready/query/custom_predicate.rb +102 -0
  65. data/lib/params_ready/query/exists_predicate.rb +103 -0
  66. data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
  67. data/lib/params_ready/query/grouping.rb +177 -0
  68. data/lib/params_ready/query/join_clause.rb +87 -0
  69. data/lib/params_ready/query/nullness_predicate.rb +71 -0
  70. data/lib/params_ready/query/polymorph_predicate.rb +77 -0
  71. data/lib/params_ready/query/predicate.rb +203 -0
  72. data/lib/params_ready/query/predicate_operator.rb +132 -0
  73. data/lib/params_ready/query/relation.rb +337 -0
  74. data/lib/params_ready/query/structured_grouping.rb +58 -0
  75. data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
  76. data/lib/params_ready/query_context.rb +21 -0
  77. data/lib/params_ready/restriction.rb +252 -0
  78. data/lib/params_ready/result.rb +109 -0
  79. data/lib/params_ready/value/coder.rb +181 -0
  80. data/lib/params_ready/value/constraint.rb +198 -0
  81. data/lib/params_ready/value/custom.rb +56 -0
  82. data/lib/params_ready/value/validator.rb +68 -0
  83. metadata +181 -0
@@ -0,0 +1,28 @@
1
+ module ParamsReady
2
+ module Pagination
3
+ module Tendency
4
+ def non_nullable_predicate(column, value, nested)
5
+ if_equal = column.eq(value).and(nested)
6
+ grouping = Arel::Nodes::Grouping.new(if_equal)
7
+ comparison = comparison_predicate(column, value)
8
+ grouping.or(comparison)
9
+ end
10
+
11
+ module Growing
12
+ extend Tendency
13
+
14
+ def self.comparison_predicate(column, value)
15
+ column.gt(value)
16
+ end
17
+ end
18
+
19
+ module Falling
20
+ extend Tendency
21
+
22
+ def self.comparison_predicate(column, value)
23
+ column.lt(value)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,204 @@
1
+ require_relative 'parameter'
2
+ require_relative '../helpers/key_map'
3
+ require_relative '../marshaller/hash_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 AbstractHashParameter < 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 = :attributes, 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 AbstractHashParameterBuilder
136
+ include Marshaller::BuilderModule
137
+
138
+ module HashLike
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 AbstractHashParameterDefinition < 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_hash_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, :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,264 @@
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
+
13
+ module ParamsReady
14
+ module Parameter
15
+ class AbstractDefinition
16
+ extend Extensions::Freezer
17
+ include Extensions::Freezer::InstanceMethods
18
+ extend Extensions::Finalizer
19
+ include Extensions::Finalizer::InstanceMethods
20
+ extend Extensions::ClassReaderWriter
21
+ extend Extensions::LateInit
22
+ extend Extensions::Collection
23
+
24
+ attr_reader :name, :altn
25
+
26
+ def parameter_class
27
+ self.class.parameter_class
28
+ end
29
+
30
+ def initialize(name, altn: nil)
31
+ @name = name.to_sym
32
+ @altn = normalize_alternative_name(altn || name)
33
+ end
34
+
35
+ def normalize_alternative_name(name)
36
+ if name.is_a? Array
37
+ name.map(&:to_sym)
38
+ else
39
+ name.to_sym
40
+ end
41
+ end
42
+
43
+ class_reader_writer :parameter_class
44
+ collection :helpers, :helper
45
+
46
+ def create
47
+ raise ParamsReadyError, "Can't create '#{name}' using unfrozen definition" unless frozen?
48
+ instance = parameter_class.new self
49
+ if @helpers
50
+ singleton = class << instance; self; end
51
+ @helpers.each do |(name, block)|
52
+ if singleton.method_defined? name
53
+ raise ParamsReadyError, "Helper '#{name}' overrides existing method"
54
+ end
55
+
56
+ singleton.send :define_method, name, &block
57
+ end
58
+ end
59
+ instance
60
+ end
61
+
62
+ def from_hash(hash, context: nil, validator: Result.new(name))
63
+ context = InputContext.resolve(context)
64
+ instance = create
65
+ result = instance.set_from_hash(hash, context: context, validator: validator)
66
+ [result, instance]
67
+ end
68
+
69
+ def from_input(input, context: nil, validator: nil)
70
+ validator ||= Result.new(name)
71
+ context = InputContext.resolve(context)
72
+ instance = create
73
+ result = instance.set_from_input(input, context, validator)
74
+ [result, instance]
75
+ end
76
+
77
+ def finish
78
+ super
79
+ freeze
80
+ end
81
+ end
82
+
83
+ class Definition < AbstractDefinition
84
+ attr_reader :default
85
+
86
+ class_reader_writer :name_for_formatter
87
+
88
+ def name_for_formatter
89
+ self.class.name_for_formatter
90
+ end
91
+
92
+ def initialize(
93
+ *args,
94
+ default: Extensions::Undefined,
95
+ optional: false,
96
+ preprocessor: nil,
97
+ populator: nil,
98
+ postprocessor: nil,
99
+ local: false,
100
+ no_output: nil,
101
+ **opts
102
+ )
103
+ super *args, **opts
104
+ @default = Extensions::Undefined
105
+ @optional = optional
106
+ @preprocessor = preprocessor
107
+ @postprocessor = postprocessor
108
+ @populator = populator
109
+ @local = local
110
+ @no_output = no_output
111
+
112
+ set_default(default) unless default == Extensions::Undefined
113
+ end
114
+
115
+ def default_defined?
116
+ return false unless defined? @default
117
+ return false if @default == Extensions::Undefined
118
+ true
119
+ end
120
+
121
+ def canonical_default(value)
122
+ return value if value.nil?
123
+ ensure_canonical value
124
+ rescue => e
125
+ raise ParamsReadyError, "Invalid default: #{e.message}"
126
+ end
127
+
128
+ late_init :populator, getter: true, once: true, obligatory: false
129
+ late_init :no_output, getter: false, once: false
130
+ late_init :memoize, getter: true, obligatory: false
131
+
132
+ def memoize?
133
+ return false if @memoize.nil?
134
+
135
+ @memoize > 0
136
+ end
137
+
138
+ def set_preprocessor(rule: nil, &block)
139
+ raise "Preprocesser already set in '#{name}'" unless @preprocessor.nil?
140
+ @preprocessor = Helpers::ConditionalBlock.new(rule: rule, &block)
141
+ end
142
+
143
+ def set_postprocessor(rule: nil, &block)
144
+ raise "Postprocessor already set in '#{name}'" unless @postprocessor.nil?
145
+ @postprocessor = Helpers::ConditionalBlock.new(rule: rule, &block)
146
+ end
147
+
148
+ def preprocess(input, context, validator)
149
+ return input if @preprocessor.nil?
150
+ return input unless @preprocessor.perform?(!context.local?, context.name)
151
+ @preprocessor.block.call input, context, self
152
+ rescue => error
153
+ preprocessor_error = PreprocessorError.new(error)
154
+ if validator.nil?
155
+ raise preprocessor_error
156
+ else
157
+ validator.error! preprocessor_error
158
+ Extensions::Undefined
159
+ end
160
+ end
161
+
162
+ def postprocess(param, context, validator)
163
+ return if @postprocessor.nil?
164
+ return unless @postprocessor.perform?(!context.local?, context.name)
165
+ @postprocessor.block.call param, context
166
+ rescue => error
167
+ postprocessor_error = PostprocessorError.new(error)
168
+ if validator.nil?
169
+ raise postprocessor_error
170
+ else
171
+ validator.error! postprocessor_error
172
+ end
173
+ validator
174
+ end
175
+
176
+ def set_local(*arr, rule: nil)
177
+ if rule.nil?
178
+ @local = true
179
+ else
180
+ @local = Helpers::Rule(rule)
181
+ end
182
+ set_default *arr unless arr.empty?
183
+ end
184
+
185
+ def local?(format)
186
+ case @local
187
+ when nil, false
188
+ false
189
+ when true
190
+ !format.local?
191
+ when Helpers::Rule
192
+ @local.include? format.name
193
+ else
194
+ raise ParamsReadyError, "Unexpected rule: #{@local}"
195
+ end
196
+ end
197
+
198
+ def no_output?(format)
199
+ case @no_output
200
+ when nil, false
201
+ return local?(format)
202
+ when true
203
+ return !format.local?
204
+ when Helpers::Rule
205
+ @no_output.include? format.name
206
+ else
207
+ raise ParamsReadyError, "Unexpected option: '#{@no_output}'"
208
+ end
209
+ end
210
+
211
+ late_init :optional, boolean: true, getter: false, once: false do |value|
212
+ next value if value == false
213
+ raise ParamsReadyError, "Optional parameter can't have default" if default_defined?
214
+
215
+ value
216
+ end
217
+
218
+ late_init :default, once: false, definite: false do |value|
219
+ next value if value == Extensions::Undefined
220
+
221
+ raise ParamsReadyError, "Optional parameter can't have default" if optional?
222
+
223
+ canonical = canonical_default(value)
224
+ next canonical if canonical.nil?
225
+
226
+ freeze_value(canonical)
227
+ end
228
+
229
+ def duplicate_default
230
+ return Extensions::Undefined unless default_defined?
231
+ return nil if @default.nil?
232
+
233
+ duplicate_value(@default)
234
+ end
235
+
236
+
237
+ def finish
238
+ if @populator && !@local
239
+ raise ParamsReadyError, "Populator set for non-local parameter '#{name}'"
240
+ end
241
+
242
+ if @preprocessor && @local
243
+ raise ParamsReadyError, "Preprocessor set for local parameter '#{name}'"
244
+ end
245
+
246
+ if @postprocessor && @local
247
+ raise ParamsReadyError, "Postprocessor set for local parameter '#{name}'"
248
+ end
249
+
250
+ super
251
+ end
252
+ end
253
+
254
+ module DelegatingDefinition
255
+ def self.[](delegee_name)
256
+ mod = Module.new
257
+ Extensions::Delegation.delegate(mod) do
258
+ instance_variable_get(:"@#{delegee_name}")
259
+ end
260
+ mod
261
+ end
262
+ end
263
+ end
264
+ end