trailblazer-activity-dsl-linear 1.0.0 → 1.1.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.
- 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
|