trailblazer-activity-dsl-linear 1.0.0 → 1.2.0

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -3
  3. data/CHANGES.md +100 -0
  4. data/Gemfile +7 -4
  5. data/Rakefile +1 -1
  6. data/lib/trailblazer/activity/dsl/linear/feature/merge.rb +2 -2
  7. data/lib/trailblazer/activity/dsl/linear/feature/patch.rb +9 -5
  8. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/dsl.rb +241 -156
  9. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/runtime.rb +276 -0
  10. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping.rb +70 -226
  11. data/lib/trailblazer/activity/dsl/linear/helper/path.rb +37 -18
  12. data/lib/trailblazer/activity/dsl/linear/helper.rb +38 -17
  13. data/lib/trailblazer/activity/dsl/linear/normalizer/extensions.rb +63 -0
  14. data/lib/trailblazer/activity/dsl/linear/normalizer/inherit.rb +90 -0
  15. data/lib/trailblazer/activity/dsl/linear/normalizer/output_tuples.rb +160 -0
  16. data/lib/trailblazer/activity/dsl/linear/normalizer/terminus.rb +26 -29
  17. data/lib/trailblazer/activity/dsl/linear/normalizer.rb +99 -160
  18. data/lib/trailblazer/activity/dsl/linear/sequence/builder.rb +3 -2
  19. data/lib/trailblazer/activity/dsl/linear/sequence/compiler.rb +21 -17
  20. data/lib/trailblazer/activity/dsl/linear/sequence/search.rb +2 -8
  21. data/lib/trailblazer/activity/dsl/linear/strategy.rb +56 -17
  22. data/lib/trailblazer/activity/dsl/linear/version.rb +1 -1
  23. data/lib/trailblazer/activity/dsl/linear.rb +13 -1
  24. data/lib/trailblazer/activity/fast_track.rb +96 -67
  25. data/lib/trailblazer/activity/path.rb +35 -53
  26. data/lib/trailblazer/activity/railway.rb +63 -65
  27. data/trailblazer-activity-dsl-linear.gemspec +8 -8
  28. metadata +27 -18
  29. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/inherit.rb +0 -38
@@ -10,44 +10,19 @@ module Trailblazer
10
10
  module DSL
11
11
  module_function
12
12
 
13
- # Compute pipeline for {:input} option.
14
- def pipe_for_mono_input(input: [], inject: [], in_filters: [], output: [], **)
15
- has_input = Array(input).any?
16
- has_mono_options = has_input || Array(inject).any? || Array(output).any? # :input, :inject and :output are "mono options".
17
- has_composable_options = in_filters.any? # DISCUSS: why are we not testing Inject()?
18
-
19
- if has_mono_options && has_composable_options
20
- warn "[Trailblazer] You are mixing `:input` and `In() => ...`. `In()` and Inject () options are ignored and `:input` wins: #{input} #{inject} #{output} <> #{in_filters} / "
21
- end
22
-
23
- pipeline = initial_input_pipeline(add_default_ctx: !has_input)
24
- pipeline = add_steps_for_input_option(pipeline, input: input)
25
- pipeline = add_steps_for_inject_option(pipeline, inject: inject)
26
-
27
- return pipeline, has_mono_options, has_composable_options
28
- end
29
-
30
13
  # Compute pipeline for In() and Inject().
31
- # We allow to inject {:initial_input_pipeline} here in order to skip creating a new input pipeline and instead
32
- # use the inherit one.
33
- def pipe_for_composable_input(in_filters: [], inject_filters: [], initial_input_pipeline: initial_input_pipeline_for(in_filters), **)
34
- inject_filters = DSL::Inject.filters_for_injects(inject_filters) # {Inject() => ...} the pure user input gets translated into AddVariable aggregate steps.
35
- in_filters = DSL::Tuple.filters_from_options(in_filters)
36
-
37
- # With only injections defined, we do not filter out anything, we use the original ctx
38
- # and _add_ defaulting for injected variables.
39
- pipeline = add_filter_steps(initial_input_pipeline, in_filters)
40
- pipeline = add_filter_steps(pipeline, inject_filters, path_prefix: "inject")
14
+ def pipe_for_composable_input(in_filters: [], initial_input_pipeline: initial_input_pipeline_for(in_filters), **)
15
+ in_filters = DSL::Tuple.filters_from_options(in_filters)
16
+ _pipeline = add_filter_steps(initial_input_pipeline, in_filters)
41
17
  end
42
18
 
43
19
  # initial pipleline depending on whether or not we got any In() filters.
44
20
  def initial_input_pipeline_for(in_filters)
45
- is_inject_only = Array(in_filters).empty?
21
+ is_inject_only = in_filters.find { |k, v| k.is_a?(VariableMapping::DSL::In) }.nil?
46
22
 
47
23
  initial_input_pipeline(add_default_ctx: is_inject_only)
48
24
  end
49
25
 
50
-
51
26
  # Adds the default_ctx step as per option {:add_default_ctx}
52
27
  def initial_input_pipeline(add_default_ctx: false)
53
28
  # No In() or {:input}. Use default ctx, which is the original ctxx.
@@ -55,11 +30,10 @@ module Trailblazer
55
30
  default_ctx_row =
56
31
  add_default_ctx ? Activity::TaskWrap::Pipeline.Row(*default_input_ctx_config) : nil
57
32
 
58
- pipe = Activity::TaskWrap::Pipeline.new(
33
+ Activity::TaskWrap::Pipeline.new(
59
34
  [
60
- Activity::TaskWrap::Pipeline.Row("input.init_hash", VariableMapping.method(:initial_aggregate)), # very first step
61
35
  default_ctx_row,
62
- Activity::TaskWrap::Pipeline.Row("input.scope", VariableMapping.method(:scope)), # last step
36
+ Activity::TaskWrap::Pipeline.Row("input.scope", VariableMapping.method(:scope)), # last step
63
37
  ].compact
64
38
  )
65
39
  end
@@ -68,38 +42,14 @@ module Trailblazer
68
42
  ["input.default_input", VariableMapping.method(:default_input_ctx)]
69
43
  end
70
44
 
71
- # Handle {:input} and {:inject} option, the "old" interface.
45
+ # Handle {:input} and {:inject} option, the "old" interface.
72
46
  def add_steps_for_input_option(pipeline, input:)
73
- tuple = DSL.In(name: ":input") # simulate {In() => input}
47
+ tuple = DSL.In() # simulate {In() => input}
74
48
  input_filter = DSL::Tuple.filters_from_options([[tuple, input]])
75
49
 
76
50
  add_filter_steps(pipeline, input_filter)
77
51
  end
78
52
 
79
-
80
- def pipe_for_mono_output(output_with_outer_ctx: false, output: [], out_filters: [], **)
81
- # No Out(), no {:output} will result in a default_output_ctx step.
82
- has_output = Array(output).any?
83
- has_mono_options = has_output
84
- has_composable_options = Array(out_filters).any?
85
-
86
- if has_mono_options && has_composable_options
87
- warn "[Trailblazer] You are mixing `:output` and `Out() => ...`. `Out()` options are ignored and `:output` wins."
88
- end
89
-
90
- pipeline = initial_output_pipeline(add_default_ctx: !has_output)
91
- pipeline = add_steps_for_output_option(pipeline, output: output, output_with_outer_ctx: output_with_outer_ctx)
92
-
93
- return pipeline, has_mono_options, has_composable_options
94
- end
95
-
96
- def add_steps_for_output_option(pipeline, output:, output_with_outer_ctx:)
97
- tuple = DSL.Out(name: ":output", with_outer_ctx: output_with_outer_ctx) # simulate {Out() => output}
98
- output_filter = DSL::Tuple.filters_from_options([[tuple, output]])
99
-
100
- add_filter_steps(pipeline, output_filter, prepend_to: "output.merge_with_original", path_prefix: "output")
101
- end
102
-
103
53
  def pipe_for_composable_output(out_filters: [], initial_output_pipeline: initial_output_pipeline(add_default_ctx: Array(out_filters).empty?), **)
104
54
  out_filters = DSL::Tuple.filters_from_options(out_filters)
105
55
 
@@ -112,7 +62,6 @@ module Trailblazer
112
62
 
113
63
  Activity::TaskWrap::Pipeline.new(
114
64
  [
115
- Activity::TaskWrap::Pipeline.Row("output.init_hash", VariableMapping.method(:initial_aggregate)), # very first step
116
65
  default_ctx_row,
117
66
  Activity::TaskWrap::Pipeline.Row("output.merge_with_original", VariableMapping.method(:merge_with_original)), # last step
118
67
  ].compact
@@ -123,14 +72,6 @@ module Trailblazer
123
72
  ["output.default_output", VariableMapping.method(:default_output_ctx)]
124
73
  end
125
74
 
126
- def add_steps_for_inject_option(pipeline, inject:)
127
- injects = inject.collect { |name| name.is_a?(Symbol) ? [DSL.Inject(), [name]] : [DSL.Inject(), name] }
128
-
129
- tuples = DSL::Inject.filters_for_injects(injects) # DISCUSS: should we add passthrough/defaulting here at Inject()-time?
130
-
131
- add_filter_steps(pipeline, tuples, path_prefix: "inject")
132
- end
133
-
134
75
  def add_filter_steps(pipeline, rows, prepend_to: "input.scope", path_prefix: "input")
135
76
  rows = add_variables_steps_for_filters(rows, path_prefix: path_prefix)
136
77
 
@@ -141,53 +82,14 @@ module Trailblazer
141
82
  Activity::Adds.apply_adds(pipeline, adds)
142
83
  end
143
84
 
144
- # Returns array of step rows ("sequence").
85
+ # Returns array of step rows ("sequence").
145
86
  # @param filters [Array] List of {Filter} objects
146
87
  def add_variables_steps_for_filters(filters, path_prefix:)
147
88
  filters.collect do |filter|
148
- ["#{path_prefix}.add_variables.#{filter.name}", filter.aggregate_step] # FIXME: config name sucks, of course, if we want to allow inserting etc.
149
- end
150
- end
151
-
152
-
153
- # Filter code
154
- # Converting user options to callable filters.
155
-
156
- # @param [Array, Hash, Proc] User option coming from the DSL, like {[:model]}
157
- #
158
- # Returns a "filter interface" callable that's invoked in {AddVariables}:
159
- # filter.(new_ctx, ..., keyword_arguments: new_ctx.to_hash, **circuit_options)
160
- def self.build_filter(user_filter)
161
- Trailblazer::Option(filter_for(user_filter))
162
- end
163
-
164
- # Convert a user option such as {[:model]} to a filter.
165
- #
166
- # Returns a filter proc to be called in an Option.
167
- # @private
168
- def self.filter_for(filter)
169
- if filter.is_a?(::Array) || filter.is_a?(::Hash)
170
- filter_from_dsl(filter)
171
- else
172
- filter
89
+ ["#{path_prefix}.add_variables.#{filter.name}", filter] # FIXME: config name sucks, of course, if we want to allow inserting etc.
173
90
  end
174
91
  end
175
92
 
176
- # The returned filter compiles a new hash for Scoped/Unscoped that only contains
177
- # the desired i/o variables.
178
- #
179
- # Filter expects a "filter interface" {(ctx, **)}.
180
- def self.filter_from_dsl(map)
181
- hsh = DSL.hash_for(map)
182
-
183
- ->(incoming_ctx, **kwargs) { Hash[hsh.collect { |from_name, to_name| [to_name, incoming_ctx[from_name]] }] }
184
- end
185
-
186
- def self.hash_for(ary)
187
- return ary if ary.instance_of?(::Hash)
188
- Hash[ary.collect { |name| [name, name] }]
189
- end
190
-
191
93
  # Keeps user's DSL configuration for a particular io-pipe step.
192
94
  # Implements the interface for the actual I/O code and is DSL code happening in the normalizer.
193
95
  # The actual I/O code expects {DSL::In} and {DSL::Out} objects to generate the two io-pipes.
@@ -195,84 +97,267 @@ module Trailblazer
195
97
  # If a user needs to inject their own private iop step they can create this data structure with desired values here.
196
98
  # This is also the reason why a lot of options computation such as {:with_outer_ctx} happens here and not in the IO code.
197
99
 
198
- class Tuple < Struct.new(:name, :add_variables_class, :filter_builder, :insert_args)
199
- def self.filters_from_options(tuples_to_user_filters)
200
- tuples_to_user_filters.collect { |tuple, user_filter| tuple.(user_filter) }
100
+ class Tuple
101
+ def initialize(variable_name, add_variables_class, filters_builder, add_variables_class_for_callable = nil, insert_args: nil, **options)
102
+ @options =
103
+ {
104
+ variable_name: variable_name,
105
+ add_variables_class: add_variables_class,
106
+ filters_builder: filters_builder,
107
+ insert_args: insert_args,
108
+
109
+ add_variables_class_for_callable: add_variables_class_for_callable,
110
+
111
+ **options
112
+ }
201
113
  end
202
114
 
115
+ def to_h
116
+ @options
117
+ end
118
+
119
+ def self.filters_from_options(tuples_to_user_filters)
120
+ tuples_to_user_filters.flat_map { |tuple, user_filter| tuple.(user_filter) }
121
+ end
203
122
 
204
123
  # @return [Filter] Filter instance that keeps {name} and {aggregate_step}.
205
124
  def call(user_filter)
206
- filter = filter_builder.(user_filter)
207
- aggregate_step = add_variables_class.new(filter, user_filter)
208
-
209
- VariableMapping::Filter.new(aggregate_step, filter, name, add_variables_class)
125
+ @options[:filters_builder].(user_filter, **to_h)
210
126
  end
211
127
  end # TODO: implement {:insert_args}
212
128
 
213
129
  # In, Out and Inject are objects instantiated when using the DSL, for instance {In() => [:model]}.
214
- class In < Tuple; end
215
- class Out < Tuple; end
130
+ class In < Tuple
131
+ class FiltersBuilder
132
+ def self.call(user_filter, add_variables_class:, add_variables_class_for_callable:, type: :In, **options)
133
+ # In()/Out() => {:user => :current_user}
134
+ if user_filter.is_a?(Hash)
135
+ # For In(): build {SetVariable} filters.
136
+ # For Out(): build {SetVariable::Output} filters.
137
+ return Filter.build_filters_for_hash(user_filter, add_variables_class: add_variables_class) do |options, from_name, to_name|
138
+ options.merge(
139
+ name: Filter.name_for(type, "#{from_name.inspect}>#{to_name.inspect}"),
140
+ read_name: from_name,
141
+ write_name: to_name,
142
+ )
143
+ end
144
+ end
145
+
146
+ # In()/Out() => [:current_user]
147
+ if user_filter.is_a?(Array)
148
+ user_filter = Filter.hash_for(user_filter)
149
+
150
+ return Filter.build_filters_for_hash(user_filter, add_variables_class: add_variables_class) do |options, from_name, _|
151
+ options.merge(
152
+ name: Filter.name_for(type, from_name.inspect),
153
+ write_name: from_name,
154
+ read_name: from_name,
155
+ )
156
+ end
157
+ end
158
+
159
+ # callable, producing a hash!
160
+ build_for_option(
161
+ user_filter,
162
+ name: Filter.name_for(type, user_filter.object_id, :add_variables),
163
+ write_name: nil,
164
+ read_name: nil,
165
+ add_variables_class: add_variables_class_for_callable, # for example, {AddVariables::Output}
166
+ **options
167
+ )
168
+ # TODO: remove {add_variables_class_for_callable} and make everything SetVariable.
169
+ end # call
170
+
171
+ # Simply invoke user's filter.
172
+ # Use this for filters without condition and default.
173
+ def self.build_for_option(user_filter, **options)
174
+ filter = Activity::Circuit.Step(user_filter, option: true)
175
+
176
+ [
177
+ Filter.build(
178
+ filter: filter,
179
+ user_filter: user_filter,
180
+ **options
181
+ )
182
+ ]
183
+ end
184
+ end
185
+ end # In
186
+
187
+ class Out < Tuple
188
+ class FiltersBuilder
189
+ def self.call(user_filter, with_outer_ctx:, **options)
190
+ if with_outer_ctx
191
+ callable = user_filter # FIXME: :instance_method
192
+ call_method = callable.respond_to?(:arity) ? callable : callable.method(:call)
193
+
194
+ options =
195
+ # TODO: remove {if} and only leave {else}.
196
+ if call_method.arity == 3
197
+ Activity::Deprecate.warn Linear::Deprecate.dsl_caller_location,
198
+ "The positional argument `outer_ctx` is deprecated, please use the `:outer_ctx` keyword argument.\n#{VariableMapping.deprecation_link}"
199
+
200
+ options.merge(
201
+ filter: Trailblazer::Option(user_filter),
202
+ add_variables_class_for_callable: AddVariables::Output::WithOuterContext_Deprecated, # old positional arg
203
+ )
204
+ else
205
+ options.merge(
206
+ add_variables_class_for_callable: AddVariables::Output::WithOuterContext,
207
+ )
208
+ end
209
+ end
210
+
211
+ In::FiltersBuilder.(user_filter, type: :Out, **options)
212
+ end
213
+ end
214
+ end # Out
216
215
 
217
- def self.In(name: rand, add_variables_class: AddVariables, filter_builder: method(:build_filter))
218
- In.new(name, add_variables_class, filter_builder)
216
+ def self.In(variable_name = nil, add_variables_class: SetVariable, filter_builder: In::FiltersBuilder, add_variables_class_for_callable: AddVariables)
217
+ In.new(variable_name, add_variables_class, filter_builder, add_variables_class_for_callable)
219
218
  end
220
219
 
221
220
  # Builder for a DSL Output() object.
222
- def self.Out(name: rand, add_variables_class: AddVariables::Output, with_outer_ctx: false, delete: false, filter_builder: method(:build_filter), read_from_aggregate: false)
223
- add_variables_class = AddVariables::Output::WithOuterContext if with_outer_ctx
224
- add_variables_class = AddVariables::Output::Delete if delete
225
- filter_builder = ->(user_filter) { user_filter } if delete
226
- add_variables_class = AddVariables::ReadFromAggregate if read_from_aggregate
227
-
228
- Out.new(name, add_variables_class, filter_builder)
221
+ def self.Out(variable_name = nil, add_variables_class: SetVariable::Output, with_outer_ctx: false, delete: false, filter_builder: Out::FiltersBuilder, read_from_aggregate: false, add_variables_class_for_callable: AddVariables::Output)
222
+ add_variables_class = SetVariable::Output::Delete if delete
223
+ add_variables_class = SetVariable::ReadFromAggregate if read_from_aggregate
224
+
225
+ Out.new(
226
+ variable_name,
227
+ add_variables_class,
228
+ filter_builder,
229
+ add_variables_class_for_callable,
230
+ with_outer_ctx: with_outer_ctx,
231
+ )
229
232
  end
230
233
 
231
- def self.Inject()
232
- Inject.new
234
+ # Used in the DSL by you.
235
+ def self.Inject(variable_name = nil, override: false, **)
236
+ Inject.new(
237
+ variable_name,
238
+ nil, # add_variables_class # DISCUSS: do we really want that here?
239
+ Inject::FiltersBuilder,
240
+ nil,
241
+ override: override,
242
+ )
233
243
  end
234
244
 
235
245
  # This class is supposed to hold configuration options for Inject().
236
- class Inject
237
- # Translate the raw input of the user to {In} tuples
238
- # @return Array of VariableMapping::Filter
239
- def self.filters_for_injects(injects)
240
- injects.collect do |inject, user_filter| # iterate all {Inject() => user_filter} calls
241
- DSL::Inject.compute_filters_for_inject(inject, user_filter)
242
- end.flatten(1)
243
- end
246
+ class Inject < Tuple
247
+ class FiltersBuilder
248
+ # Called via {Tuple#call}
249
+ def self.call(user_filter, add_variables_class:, variable_name:, **options)
250
+ # Build {SetVariable::Default}
251
+ if user_filter.is_a?(Hash) # TODO: deprecate in favor if {Inject(:variable_name)}!
252
+ return Filter.build_filters_for_hash(user_filter, add_variables_class: SetVariable::Default) do |options, from_name, user_proc|
253
+ options_with_condition_for_defaulted(
254
+ **options,
255
+ user_filter: user_proc,
256
+ write_name: from_name,
257
+ read_name: from_name,
258
+ )
259
+ end
260
+ end
261
+
262
+ # Build {SetVariable::Conditioned}
263
+ if user_filter.is_a?(Array)
264
+ user_filter = Filter.hash_for(user_filter)
265
+
266
+ return Filter.build_filters_for_hash(user_filter, add_variables_class: SetVariable::Conditioned) do |options, from_name, _|
267
+ options_with_condition(
268
+ **options,
269
+ write_name: from_name,
270
+ read_name: from_name,
271
+ user_filter: user_filter, # FIXME: this is not really helpful, it's something like [:field, :injects]
272
+ )
273
+ end
274
+ end
275
+
276
+ if options[:override]
277
+ return In::FiltersBuilder.build_for_option(
278
+ user_filter,
279
+ name: Filter.name_for(:Inject, variable_name, :add_variables),
280
+ write_name: variable_name,
281
+ read_name: nil,
282
+ add_variables_class: SetVariable,
283
+ **options
284
+ )
285
+ end
286
+
287
+ # Build {SetVariable::Default}
288
+ # {user_filter} is one of the following
289
+ # :instance_method
290
+ options = options_with_condition_for_defaulted(
291
+ **options,
292
+ write_name: variable_name,
293
+ read_name: variable_name,
294
+ user_filter: user_filter,
295
+ )
296
+
297
+ [
298
+ Filter.build_for_reading(add_variables_class: SetVariable::Default, **options)
299
+ ]
300
+ end # call
301
+
302
+ def self.options_with_condition(user_filter:, write_name:, name_specifier: nil, **options)
303
+ {
304
+ name: Filter.name_for(:Inject, write_name.inspect, name_specifier),
305
+ **options,
306
+ condition: VariablePresent.new(variable_name: write_name),
307
+ write_name: write_name,
308
+ user_filter: user_filter,
309
+ }
310
+ end
244
311
 
245
- # Compute {In} tuples from the user's DSL input.
246
- # We simply use AddVariables but use our own {inject_filter} which checks if the particular
247
- # variable is already present in the incoming ctx.
248
- def self.compute_filters_for_inject(inject, user_filter) # {user_filter} either [:current_user, :model] or {model: ->{}}
249
- return filters_for_array(inject, user_filter) if user_filter.is_a?(Array)
250
- filters_for_hash_of_callables(inject, user_filter)
312
+ def self.options_with_condition_for_defaulted(user_filter:, **options)
313
+ default_filter = Activity::Circuit.Step(user_filter, option: true) # this is passed into {SetVariable.new}.
314
+
315
+ options_with_condition(
316
+ **options,
317
+ user_filter: user_filter,
318
+ name_specifier: :default,
319
+ default_filter: default_filter,
320
+ )
321
+ end
322
+ end # FiltersBuilder
323
+ end # Inject
324
+
325
+ # DISCUSS: generic, again
326
+ module Filter
327
+ def self.build(add_variables_class:, **options)
328
+ add_variables_class.new(
329
+ **options,
330
+ )
251
331
  end
252
332
 
253
- # [:model, :current_user]
254
- def self.filters_for_array(inject, user_filter)
255
- user_filter.collect do |name|
256
- inject_filter = ->(original_ctx, **) { original_ctx.key?(name) ? {name => original_ctx[name]} : {} } # FIXME: make me an {Inject::} method.
333
+ def self.build_for_reading(read_name:, **options)
334
+ circuit_step_filter = VariableFromCtx.new(variable_name: read_name) # Activity::Circuit.Step(filter, option: true) # this is passed into {SetVariable.new}.
257
335
 
258
- filter_for(inject, inject_filter, name, "passthrough")
259
- end
336
+ build(
337
+ filter: circuit_step_filter,
338
+ **options
339
+ )
260
340
  end
261
341
 
262
- # {model: ->(*) { snippet }}
263
- def self.filters_for_hash_of_callables(inject, user_filter)
264
- user_filter.collect do |name, defaulting_filter|
265
- inject_filter = ->(original_ctx, **kws) { original_ctx.key?(name) ? {name => original_ctx[name]} : {name => defaulting_filter.(original_ctx, **kws)} }
342
+ def self.build_filters_for_hash(user_filter, **options)
343
+ user_filter.collect do |from_name, to_name|
344
+ options = yield(options, from_name, to_name)
266
345
 
267
- filter_for(inject, inject_filter, name, "defaulting_callable")
346
+ Filter.build_for_reading(
347
+ user_filter: user_filter,
348
+ **options,
349
+ )
268
350
  end
269
351
  end
270
352
 
271
- def self.filter_for(inject, inject_filter, name, type)
272
- DSL.In(name: "#{type}.#{name.inspect}", add_variables_class: AddVariables).(inject_filter)
353
+ def self.hash_for(ary)
354
+ ary.collect { |name| [name, name] }.to_h
273
355
  end
274
- end
275
356
 
357
+ def self.name_for(type, name, specifier = nil)
358
+ [type, specifier].compact.join(".") + "{#{name}}"
359
+ end
360
+ end # Filter
276
361
  end # DSL
277
362
  end
278
363
  end