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.
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