trailblazer-activity-dsl-linear 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +6 -4
- data/.github/workflows/ci_jruby.yml +19 -0
- data/.github/workflows/ci_legacy.yml +19 -0
- data/.github/workflows/ci_truffleruby.yml +19 -0
- data/CHANGES.md +28 -0
- data/Gemfile +3 -3
- data/Rakefile +1 -1
- data/lib/trailblazer/activity/dsl/linear/feature/patch.rb +5 -1
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/dsl.rb +242 -147
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/runtime.rb +278 -0
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping.rb +65 -211
- data/lib/trailblazer/activity/dsl/linear/helper.rb +17 -5
- data/lib/trailblazer/activity/dsl/linear/normalizer/terminus.rb +1 -1
- data/lib/trailblazer/activity/dsl/linear/normalizer.rb +3 -12
- data/lib/trailblazer/activity/dsl/linear/strategy.rb +41 -2
- data/lib/trailblazer/activity/dsl/linear/version.rb +1 -1
- data/lib/trailblazer/activity/dsl/linear.rb +1 -0
- data/lib/trailblazer/activity/fast_track.rb +5 -13
- data/lib/trailblazer/activity/path.rb +13 -24
- data/lib/trailblazer/activity/railway.rb +4 -12
- data/trailblazer-activity-dsl-linear.gemspec +3 -2
- metadata +32 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87302630d03df0e0e40ad7e7b9902744a1b9d7586e157018eab7652c6ad7276c
|
4
|
+
data.tar.gz: 10a821885b6a9e4228a0e04545d28689d28f4d3470f74b5f597f6d9bc1b4dd50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08a071547063505433e4400c7f5e23c8203c72f125397bf71af8402050d728e1e5995fc71f5cd23a8da362c277bedb16a71e9d4f0b5f1c439d96eed82c4589fc'
|
7
|
+
data.tar.gz: 11e54d0175baa4fa338605faf1ac44ef1ef891a763890730c44119a239f11ea2f37497c80156bc2895a11b7b0a6ce58e9349e4a44e49f90c3dc48535ff179b57
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
## This file is managed by Terraform.
|
2
|
+
## Do not modify this file directly, as it may be overwritten.
|
3
|
+
## Please open an issue instead.
|
1
4
|
name: CI
|
2
5
|
on: [push, pull_request]
|
3
6
|
jobs:
|
@@ -5,13 +8,12 @@ jobs:
|
|
5
8
|
strategy:
|
6
9
|
fail-fast: false
|
7
10
|
matrix:
|
8
|
-
|
9
|
-
ruby: [2.5, 2.6, 2.7, '3.0', head, jruby]
|
11
|
+
ruby: [2.7, '3.0', '3.1']
|
10
12
|
runs-on: ubuntu-latest
|
11
13
|
steps:
|
12
|
-
- uses: actions/checkout@
|
14
|
+
- uses: actions/checkout@v3
|
13
15
|
- uses: ruby/setup-ruby@v1
|
14
16
|
with:
|
15
17
|
ruby-version: ${{ matrix.ruby }}
|
16
|
-
bundler-cache: true
|
18
|
+
bundler-cache: true
|
17
19
|
- run: bundle exec rake
|
@@ -0,0 +1,19 @@
|
|
1
|
+
## This file is managed by Terraform.
|
2
|
+
## Do not modify this file directly, as it may be overwritten.
|
3
|
+
## Please open an issue instead.
|
4
|
+
name: CI JRuby
|
5
|
+
on: [push, pull_request]
|
6
|
+
jobs:
|
7
|
+
test:
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
ruby: [jruby, jruby-head]
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v3
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
bundler-cache: true
|
19
|
+
- run: bundle exec rake
|
@@ -0,0 +1,19 @@
|
|
1
|
+
## This file is managed by Terraform.
|
2
|
+
## Do not modify this file directly, as it may be overwritten.
|
3
|
+
## Please open an issue instead.
|
4
|
+
name: CI with EOL ruby versions
|
5
|
+
on: [push, pull_request]
|
6
|
+
jobs:
|
7
|
+
test:
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
ruby: [2.5, 2.6]
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v3
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
bundler-cache: true
|
19
|
+
- run: bundle exec rake
|
@@ -0,0 +1,19 @@
|
|
1
|
+
## This file is managed by Terraform.
|
2
|
+
## Do not modify this file directly, as it may be overwritten.
|
3
|
+
## Please open an issue instead.
|
4
|
+
name: CI TruffleRuby
|
5
|
+
on: [push, pull_request]
|
6
|
+
jobs:
|
7
|
+
test:
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
ruby: [truffleruby, truffleruby-head]
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v3
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
bundler-cache: true
|
19
|
+
- run: bundle exec rake
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
# 1.1.0
|
2
|
+
|
3
|
+
* Use `trailblazer-activity` 0.15.0.
|
4
|
+
* Remove `Path::DSL.OptionsForSequenceBuilder` and move concrete code to `Path::DSL.options_for_sequence_build`
|
5
|
+
which returns a set:
|
6
|
+
|
7
|
+
1. default termini instructions for the concrete strategy
|
8
|
+
2. options specific for this strategy subclass.
|
9
|
+
|
10
|
+
Everything else, such as merging user options, computing and adding termini, etc, now happens in
|
11
|
+
`Strategy::DSL.OptionsForSequenceBuilder`.
|
12
|
+
* Adding `Subprocess(Create, strict: true)` to wire all outputs of `Create` automatically.
|
13
|
+
Each output will be wired to its same named Track(semantic).
|
14
|
+
* Adding `Strategy(termini: )`
|
15
|
+
* For `output:` in combination with `:output_with_outer_ctx`, deprecate the second positional argument and make it
|
16
|
+
the `:outer_ctx` keyword argument instead.
|
17
|
+
* Introduce `Linear.Patch` as the public entry point for patching activities.
|
18
|
+
* Remove `Runtime.initial_aggregate` step for the input and output pipelines which results in slightly better runtime performance and less code.
|
19
|
+
|
20
|
+
## Variable Mapping
|
21
|
+
|
22
|
+
* Simplify the architecture in `VariableMapping`, filters are now added directly into the `Pipeline`.
|
23
|
+
Performance increase from 17k to 25k from 1.0.0 to this version.
|
24
|
+
* Introduce `Inject(:variable)` to supersede the version receiving a big mapping hash.
|
25
|
+
* Add `Inject(:variable, override: true)` to always write a variable to ctx, regardless of its presence.
|
26
|
+
* Fix a bug where `Inject()` would override `In()` filters even though the latter was added latest. This
|
27
|
+
is fixed by treating both filter types equally and in the order they were added by the user (and the macro).
|
28
|
+
|
1
29
|
# 1.0.0
|
2
30
|
|
3
31
|
## Additions
|
data/Gemfile
CHANGED
@@ -5,11 +5,11 @@ gemspec
|
|
5
5
|
|
6
6
|
gem "minitest-line"
|
7
7
|
|
8
|
-
gem "
|
9
|
-
|
10
|
-
gem "trailblazer-developer", path: "../trailblazer-developer"
|
8
|
+
# gem "trailblazer-developer", path: "../trailblazer-developer"
|
11
9
|
# gem "trailblazer-developer", github: "trailblazer/trailblazer-developer"
|
12
10
|
# gem "trailblazer-declarative", path: "../trailblazer-declarative"
|
13
11
|
# gem "trailblazer-activity", path: "../trailblazer-activity"
|
14
12
|
# gem "trailblazer-activity", github: "trailblazer/trailblazer-activity"
|
15
13
|
# gem "trailblazer-activity", path: "../circuit"
|
14
|
+
gem "benchmark-ips"
|
15
|
+
# gem "trailblazer-core-utils", path: "../trailblazer-core-utils"
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
class Trailblazer::Activity
|
2
2
|
module DSL
|
3
3
|
module Linear
|
4
|
+
def self.Patch(activity, instructions)
|
5
|
+
Patch.customize(activity, options: instructions)
|
6
|
+
end
|
7
|
+
|
4
8
|
module Patch
|
5
9
|
# DISCUSS: we could make this a generic DSL option, not just for Subprocess().
|
6
10
|
# Currently, this is called from the Subprocess() helper.
|
@@ -21,7 +25,7 @@ class Trailblazer::Activity
|
|
21
25
|
|
22
26
|
patch =
|
23
27
|
if task_id
|
24
|
-
segment_activity = Introspect::
|
28
|
+
segment_activity = Introspect::TaskMap(activity).find_by_id(task_id).task
|
25
29
|
patched_segment_activity = call(segment_activity, path, customization)
|
26
30
|
|
27
31
|
# Replace the patched subprocess.
|
@@ -10,39 +10,17 @@ 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
14
|
# We allow to inject {:initial_input_pipeline} here in order to skip creating a new input pipeline and instead
|
32
15
|
# use the inherit one.
|
33
|
-
def pipe_for_composable_input(in_filters: [],
|
34
|
-
|
35
|
-
|
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")
|
16
|
+
def pipe_for_composable_input(in_filters: [], initial_input_pipeline: initial_input_pipeline_for(in_filters), **)
|
17
|
+
in_filters = DSL::Tuple.filters_from_options(in_filters)
|
18
|
+
pipeline = add_filter_steps(initial_input_pipeline, in_filters)
|
41
19
|
end
|
42
20
|
|
43
21
|
# initial pipleline depending on whether or not we got any In() filters.
|
44
22
|
def initial_input_pipeline_for(in_filters)
|
45
|
-
is_inject_only =
|
23
|
+
is_inject_only = in_filters.find { |k, v| k.is_a?(VariableMapping::DSL::In) }.nil?
|
46
24
|
|
47
25
|
initial_input_pipeline(add_default_ctx: is_inject_only)
|
48
26
|
end
|
@@ -57,7 +35,6 @@ module Trailblazer
|
|
57
35
|
|
58
36
|
pipe = Activity::TaskWrap::Pipeline.new(
|
59
37
|
[
|
60
|
-
Activity::TaskWrap::Pipeline.Row("input.init_hash", VariableMapping.method(:initial_aggregate)), # very first step
|
61
38
|
default_ctx_row,
|
62
39
|
Activity::TaskWrap::Pipeline.Row("input.scope", VariableMapping.method(:scope)), # last step
|
63
40
|
].compact
|
@@ -70,36 +47,12 @@ module Trailblazer
|
|
70
47
|
|
71
48
|
# Handle {:input} and {:inject} option, the "old" interface.
|
72
49
|
def add_steps_for_input_option(pipeline, input:)
|
73
|
-
tuple = DSL.In(
|
50
|
+
tuple = DSL.In() # simulate {In() => input}
|
74
51
|
input_filter = DSL::Tuple.filters_from_options([[tuple, input]])
|
75
52
|
|
76
53
|
add_filter_steps(pipeline, input_filter)
|
77
54
|
end
|
78
55
|
|
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
56
|
def pipe_for_composable_output(out_filters: [], initial_output_pipeline: initial_output_pipeline(add_default_ctx: Array(out_filters).empty?), **)
|
104
57
|
out_filters = DSL::Tuple.filters_from_options(out_filters)
|
105
58
|
|
@@ -112,7 +65,6 @@ module Trailblazer
|
|
112
65
|
|
113
66
|
Activity::TaskWrap::Pipeline.new(
|
114
67
|
[
|
115
|
-
Activity::TaskWrap::Pipeline.Row("output.init_hash", VariableMapping.method(:initial_aggregate)), # very first step
|
116
68
|
default_ctx_row,
|
117
69
|
Activity::TaskWrap::Pipeline.Row("output.merge_with_original", VariableMapping.method(:merge_with_original)), # last step
|
118
70
|
].compact
|
@@ -123,14 +75,6 @@ module Trailblazer
|
|
123
75
|
["output.default_output", VariableMapping.method(:default_output_ctx)]
|
124
76
|
end
|
125
77
|
|
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
78
|
def add_filter_steps(pipeline, rows, prepend_to: "input.scope", path_prefix: "input")
|
135
79
|
rows = add_variables_steps_for_filters(rows, path_prefix: path_prefix)
|
136
80
|
|
@@ -145,48 +89,10 @@ module Trailblazer
|
|
145
89
|
# @param filters [Array] List of {Filter} objects
|
146
90
|
def add_variables_steps_for_filters(filters, path_prefix:)
|
147
91
|
filters.collect do |filter|
|
148
|
-
["#{path_prefix}.add_variables.#{filter.name}", filter
|
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
|
92
|
+
["#{path_prefix}.add_variables.#{filter.name}", filter] # FIXME: config name sucks, of course, if we want to allow inserting etc.
|
173
93
|
end
|
174
94
|
end
|
175
95
|
|
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
96
|
|
191
97
|
# Keeps user's DSL configuration for a particular io-pipe step.
|
192
98
|
# Implements the interface for the actual I/O code and is DSL code happening in the normalizer.
|
@@ -195,83 +101,272 @@ module Trailblazer
|
|
195
101
|
# If a user needs to inject their own private iop step they can create this data structure with desired values here.
|
196
102
|
# 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
103
|
|
198
|
-
class Tuple
|
199
|
-
def
|
200
|
-
|
104
|
+
class Tuple
|
105
|
+
def initialize(variable_name, add_variables_class, filters_builder, add_variables_class_for_callable=nil, insert_args: nil, **options)
|
106
|
+
@options =
|
107
|
+
{
|
108
|
+
variable_name: variable_name,
|
109
|
+
add_variables_class: add_variables_class,
|
110
|
+
filters_builder: filters_builder,
|
111
|
+
insert_args: insert_args,
|
112
|
+
|
113
|
+
add_variables_class_for_callable: add_variables_class_for_callable,
|
114
|
+
|
115
|
+
**options
|
116
|
+
}
|
201
117
|
end
|
202
118
|
|
119
|
+
def to_h
|
120
|
+
@options
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.filters_from_options(tuples_to_user_filters)
|
124
|
+
tuples_to_user_filters.collect { |tuple, user_filter| tuple.(user_filter) }.flatten(1)
|
125
|
+
end
|
203
126
|
|
204
127
|
# @return [Filter] Filter instance that keeps {name} and {aggregate_step}.
|
205
128
|
def call(user_filter)
|
206
|
-
|
207
|
-
aggregate_step = add_variables_class.new(filter, user_filter)
|
208
|
-
|
209
|
-
VariableMapping::Filter.new(aggregate_step, filter, name, add_variables_class)
|
129
|
+
@options[:filters_builder].(user_filter, **to_h)
|
210
130
|
end
|
211
131
|
end # TODO: implement {:insert_args}
|
212
132
|
|
213
133
|
# In, Out and Inject are objects instantiated when using the DSL, for instance {In() => [:model]}.
|
214
|
-
class In < Tuple
|
215
|
-
|
134
|
+
class In < Tuple
|
135
|
+
class FiltersBuilder
|
136
|
+
def self.call(user_filter, add_variables_class:, add_variables_class_for_callable:, type: :In, **options)
|
137
|
+
# In()/Out() => {:user => :current_user}
|
138
|
+
if user_filter.is_a?(Hash)
|
139
|
+
# For In(): build {SetVariable} filters.
|
140
|
+
# For Out(): build {SetVariable::Output} filters.
|
141
|
+
return Filter.build_filters_for_hash(user_filter, add_variables_class: add_variables_class) do |options, from_name, to_name|
|
142
|
+
options.merge(
|
143
|
+
name: Filter.name_for(type, "#{from_name.inspect}>#{to_name.inspect}"),
|
144
|
+
read_name: from_name,
|
145
|
+
write_name: to_name,
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# In()/Out() => [:current_user]
|
151
|
+
if user_filter.is_a?(Array)
|
152
|
+
user_filter = Filter.hash_for(user_filter)
|
153
|
+
|
154
|
+
return Filter.build_filters_for_hash(user_filter, add_variables_class: add_variables_class) do |options, from_name, _|
|
155
|
+
options.merge(
|
156
|
+
name: Filter.name_for(type, from_name.inspect),
|
157
|
+
write_name: from_name,
|
158
|
+
read_name: from_name,
|
159
|
+
)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# callable, producing a hash!
|
164
|
+
|
165
|
+
return build_for_option(user_filter,
|
166
|
+
name: Filter.name_for(type, user_filter.object_id, :add_variables),
|
167
|
+
write_name: nil,
|
168
|
+
read_name: nil,
|
169
|
+
add_variables_class: add_variables_class_for_callable, # for example, {AddVariables::Output}
|
170
|
+
**options
|
171
|
+
)
|
172
|
+
# TODO: remove {add_variables_class_for_callable} and make everything SetVariable.
|
173
|
+
end # call
|
174
|
+
|
175
|
+
# Simply invoke user's filter.
|
176
|
+
# Use this for filters without condition and default.
|
177
|
+
def self.build_for_option(user_filter, **options)
|
178
|
+
filter = Activity::Circuit.Step(user_filter, option: true)
|
179
|
+
|
180
|
+
[
|
181
|
+
Filter.build(
|
182
|
+
filter: filter,
|
183
|
+
user_filter: user_filter,
|
184
|
+
**options
|
185
|
+
)
|
186
|
+
]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end # In
|
190
|
+
|
191
|
+
class Out < Tuple
|
192
|
+
class FiltersBuilder
|
193
|
+
def self.call(user_filter, with_outer_ctx:, **options)
|
194
|
+
if with_outer_ctx
|
195
|
+
callable = user_filter # FIXME: :instance_method, for fuck's sake.
|
196
|
+
call_method = callable.respond_to?(:arity) ? callable : callable.method(:call)
|
197
|
+
|
198
|
+
options =
|
199
|
+
# TODO: remove {if} and only leave {else}.
|
200
|
+
if call_method.arity == 3
|
201
|
+
index = caller_locations.find_index { |location| location.to_s =~ /recompile_activity_for/ }
|
202
|
+
caller_location = caller_locations[index+2]
|
203
|
+
|
204
|
+
Activity::Deprecate.warn caller_location,
|
205
|
+
"The positional argument `outer_ctx` is deprecated, please use the `:outer_ctx` keyword argument.\n#{VariableMapping.deprecation_link}"
|
206
|
+
|
207
|
+
options.merge(
|
208
|
+
filter: Trailblazer::Option(user_filter),
|
209
|
+
add_variables_class_for_callable: AddVariables::Output::WithOuterContext_Deprecated, # old positional arg
|
210
|
+
)
|
211
|
+
else
|
212
|
+
options.merge(
|
213
|
+
add_variables_class_for_callable: AddVariables::Output::WithOuterContext,
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
In::FiltersBuilder.(user_filter, type: :Out, **options)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end # Out
|
216
222
|
|
217
|
-
def self.In(
|
218
|
-
In.new(
|
223
|
+
def self.In(variable_name = nil, add_variables_class: SetVariable, filter_builder: In::FiltersBuilder, add_variables_class_for_callable: AddVariables)
|
224
|
+
In.new(variable_name, add_variables_class, filter_builder, add_variables_class_for_callable)
|
219
225
|
end
|
220
226
|
|
221
227
|
# Builder for a DSL Output() object.
|
222
|
-
def self.Out(
|
223
|
-
add_variables_class =
|
224
|
-
add_variables_class =
|
225
|
-
|
226
|
-
|
228
|
+
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)
|
229
|
+
add_variables_class = SetVariable::Output::Delete if delete
|
230
|
+
add_variables_class = SetVariable::ReadFromAggregate if read_from_aggregate
|
231
|
+
|
232
|
+
Out.new(
|
233
|
+
variable_name,
|
234
|
+
add_variables_class,
|
235
|
+
filter_builder,
|
236
|
+
add_variables_class_for_callable,
|
227
237
|
|
228
|
-
|
238
|
+
with_outer_ctx: with_outer_ctx,
|
239
|
+
)
|
229
240
|
end
|
230
241
|
|
231
|
-
|
232
|
-
|
242
|
+
# Used in the DSL by you.
|
243
|
+
def self.Inject(variable_name = nil, override: false, **)
|
244
|
+
Inject.new(
|
245
|
+
variable_name,
|
246
|
+
nil, # add_variables_class # DISCUSS: do we really want that here?
|
247
|
+
Inject::FiltersBuilder,
|
248
|
+
nil,
|
249
|
+
override: override,
|
250
|
+
)
|
233
251
|
end
|
234
252
|
|
235
253
|
# This class is supposed to hold configuration options for Inject().
|
236
|
-
class Inject
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
254
|
+
class Inject < Tuple
|
255
|
+
class FiltersBuilder
|
256
|
+
# Called via {Tuple#call}
|
257
|
+
def self.call(user_filter, add_variables_class:, variable_name:, **options)
|
258
|
+
# Build {SetVariable::Default}
|
259
|
+
if user_filter.is_a?(Hash) # TODO: deprecate in favor if {Inject(:variable_name)}!
|
260
|
+
return Filter.build_filters_for_hash(user_filter, add_variables_class: SetVariable::Default) do |options, from_name, user_proc|
|
261
|
+
options_with_condition_for_defaulted(
|
262
|
+
**options,
|
263
|
+
user_filter: user_proc,
|
264
|
+
write_name: from_name,
|
265
|
+
read_name: from_name,
|
266
|
+
)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Build {SetVariable::Conditioned}
|
271
|
+
if user_filter.is_a?(Array)
|
272
|
+
user_filter = Filter.hash_for(user_filter)
|
273
|
+
|
274
|
+
return Filter.build_filters_for_hash(user_filter, add_variables_class: SetVariable::Conditioned) do |options, from_name, _|
|
275
|
+
options_with_condition(
|
276
|
+
**options,
|
277
|
+
write_name: from_name,
|
278
|
+
read_name: from_name,
|
279
|
+
user_filter: user_filter, # FIXME: this is not really helpful, it's something like [:field, :injects]
|
280
|
+
)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
if options[:override]
|
285
|
+
return In::FiltersBuilder.build_for_option(
|
286
|
+
user_filter,
|
287
|
+
name: Filter.name_for(:Inject, variable_name, :add_variables),
|
288
|
+
write_name: variable_name,
|
289
|
+
read_name: nil,
|
290
|
+
add_variables_class: SetVariable,
|
291
|
+
**options
|
292
|
+
)
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
# Build {SetVariable::Default}
|
297
|
+
# {user_filter} is one of the following
|
298
|
+
# :instance_method
|
299
|
+
options = options_with_condition_for_defaulted(
|
300
|
+
**options,
|
301
|
+
write_name: variable_name,
|
302
|
+
read_name: variable_name,
|
303
|
+
user_filter: user_filter,
|
304
|
+
)
|
305
|
+
|
306
|
+
[
|
307
|
+
Filter.build_for_reading(add_variables_class: SetVariable::Default, **options)
|
308
|
+
]
|
309
|
+
end # call
|
310
|
+
|
311
|
+
def self.options_with_condition(user_filter:, write_name:, name_specifier: nil, **options)
|
312
|
+
{
|
313
|
+
name: Filter.name_for(:Inject, write_name.inspect, name_specifier),
|
314
|
+
**options,
|
315
|
+
condition: VariablePresent.new(variable_name: write_name),
|
316
|
+
write_name: write_name,
|
317
|
+
user_filter: user_filter,
|
318
|
+
}
|
319
|
+
end
|
320
|
+
|
321
|
+
def self.options_with_condition_for_defaulted(user_filter:, **options)
|
322
|
+
default_filter = Activity::Circuit.Step(user_filter, option: true) # this is passed into {SetVariable.new}.
|
244
323
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
324
|
+
options_with_condition(
|
325
|
+
**options,
|
326
|
+
user_filter: user_filter,
|
327
|
+
name_specifier: :default,
|
328
|
+
default_filter: default_filter,
|
329
|
+
)
|
330
|
+
end
|
331
|
+
end # FiltersBuilder
|
332
|
+
end # Inject
|
333
|
+
|
334
|
+
# DISCUSS: generic, again
|
335
|
+
module Filter
|
336
|
+
def self.build(add_variables_class:, **options)
|
337
|
+
add_variables_class.new(
|
338
|
+
**options,
|
339
|
+
)
|
251
340
|
end
|
252
341
|
|
253
|
-
|
254
|
-
|
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.
|
342
|
+
def self.build_for_reading(read_name:, **options)
|
343
|
+
circuit_step_filter = VariableFromCtx.new(variable_name: read_name) # Activity::Circuit.Step(filter, option: true) # this is passed into {SetVariable.new}.
|
257
344
|
|
258
|
-
|
259
|
-
|
345
|
+
build(
|
346
|
+
filter: circuit_step_filter,
|
347
|
+
**options
|
348
|
+
)
|
260
349
|
end
|
261
350
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
inject_filter = ->(original_ctx, **kws) { original_ctx.key?(name) ? {name => original_ctx[name]} : {name => defaulting_filter.(original_ctx, **kws)} }
|
351
|
+
def self.build_filters_for_hash(user_filter, **options)
|
352
|
+
return user_filter.collect do |from_name, to_name|
|
353
|
+
options = yield(options, from_name, to_name)
|
266
354
|
|
267
|
-
|
355
|
+
Filter.build_for_reading(
|
356
|
+
user_filter: user_filter,
|
357
|
+
**options,
|
358
|
+
)
|
268
359
|
end
|
269
360
|
end
|
270
361
|
|
271
|
-
def self.
|
272
|
-
|
362
|
+
def self.hash_for(ary)
|
363
|
+
ary.collect { |name| [name, name] }.to_h
|
273
364
|
end
|
274
|
-
|
365
|
+
|
366
|
+
def self.name_for(type, name, specifier=nil)
|
367
|
+
[type, specifier].compact.join(".") + "{#{name}}"
|
368
|
+
end
|
369
|
+
end # Filter
|
275
370
|
|
276
371
|
end # DSL
|
277
372
|
end
|