trailblazer-macro 2.1.11 → 2.1.12
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 +29 -0
- data/Gemfile +7 -5
- data/lib/trailblazer/macro/each.rb +170 -0
- data/lib/trailblazer/macro/model.rb +4 -5
- data/lib/trailblazer/macro/nested.rb +130 -68
- data/lib/trailblazer/macro/rescue.rb +2 -0
- data/lib/trailblazer/macro/strategy.rb +32 -0
- data/lib/trailblazer/macro/version.rb +1 -1
- data/lib/trailblazer/macro/wrap.rb +72 -65
- data/lib/trailblazer/macro.rb +53 -2
- data/test/docs/autogenerated/operation_each_test.rb +585 -0
- data/test/docs/autogenerated/operation_model_test.rb +263 -0
- data/test/docs/each_test.rb +907 -0
- data/test/docs/macro_test.rb +18 -0
- data/test/docs/model_test.rb +204 -88
- data/test/docs/nested_static_test.rb +730 -0
- data/test/docs/wrap_test.rb +348 -66
- data/test/test_helper.rb +29 -0
- data/trailblazer-macro.gemspec +2 -6
- metadata +21 -58
- data/.rubocop.yml +0 -6
- data/.rubocop_todo.yml +0 -423
- data/test/docs/nested_test.rb +0 -218
- data/test/operation/model_test.rb +0 -89
- data/test/operation/nested_test.rb +0 -98
@@ -1,81 +1,88 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
1
|
module Trailblazer
|
4
2
|
module Macro
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
# TODO: {user_wrap}: rename to {wrap_handler}.
|
4
|
+
def self.Wrap(user_wrap, id: Macro.id_for(user_wrap, macro: :Wrap), &block)
|
5
|
+
user_wrap = Wrap.deprecate_positional_wrap_signature(user_wrap)
|
6
|
+
|
7
|
+
block_activity, outputs = Macro.block_activity_for(nil, &block)
|
8
|
+
|
9
|
+
outputs = Hash[outputs.collect { |output| [output.semantic, output] }] # FIXME: redundant to Subprocess().
|
10
|
+
|
11
|
+
# Since in the user block, you can return Railway.pass! etc, we need to map
|
12
|
+
# those to the actual wrapped block_activity's end.
|
13
|
+
signal_to_output = {
|
14
|
+
Activity::Right => outputs[:success].signal,
|
15
|
+
Activity::Left => outputs[:failure].signal,
|
16
|
+
Activity::FastTrack::PassFast => outputs[:pass_fast].signal,
|
17
|
+
Activity::FastTrack::FailFast => outputs[:fail_fast].signal,
|
18
|
+
true => outputs[:success].signal,
|
19
|
+
false => outputs[:failure].signal,
|
20
|
+
nil => outputs[:failure].signal,
|
21
|
+
}
|
22
|
+
|
23
|
+
state = Declarative::State(
|
24
|
+
# this is important, so we subclass the actually wrapped activity when {Wrap} is subclassed.
|
25
|
+
block_activity: [block_activity, {copy: Trailblazer::Declarative::State.method(:subclass)}],
|
26
|
+
user_wrap: [user_wrap, {}], # DISCUSS: we could even allow the wrap_handler to be patchable.
|
27
|
+
signal_to_output: [signal_to_output, {}],
|
28
|
+
)
|
29
|
+
|
30
|
+
task = Class.new(Wrap) do
|
31
|
+
extend Macro::Strategy::State # now, the Wrap subclass can inherit its state and copy the {block_activity}.
|
32
|
+
initialize!(state)
|
33
|
+
end
|
34
|
+
# DISCUSS: unfortunately, Ruby doesn't allow to set this during {Class.new}.
|
12
35
|
|
13
|
-
{
|
36
|
+
{
|
37
|
+
task: task,
|
38
|
+
id: id,
|
39
|
+
outputs: outputs,
|
40
|
+
}
|
14
41
|
end
|
15
42
|
|
16
|
-
|
43
|
+
# Wrap exposes {#inherited} which will also copy the block activity.
|
44
|
+
# Currently, this is only used for patching (as it will try to subclass Wrap).
|
45
|
+
class Wrap < Macro::Strategy # TODO: it would be cool to have Activity::Interface and Strategy::Interface
|
17
46
|
# behaves like an operation so it plays with Nested and simply calls the operation in the user-provided block.
|
18
|
-
class Wrapped
|
19
|
-
|
20
|
-
|
47
|
+
# class Wrapped
|
48
|
+
# @private
|
49
|
+
def self.deprecate_positional_wrap_signature(user_wrap)
|
50
|
+
parameters = user_wrap.is_a?(Proc) || user_wrap.is_a?(Method) ? user_wrap.parameters : user_wrap.method(:call).parameters
|
21
51
|
|
22
|
-
|
52
|
+
return user_wrap if parameters[0] == [:req] # means ((ctx, flow_options), *, &block), "new style"
|
23
53
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
54
|
+
->((ctx, flow_options), **circuit_options, &block) do
|
55
|
+
warn "[Trailblazer] Wrap handlers have a new signature: ((ctx), *, &block) XXX"
|
56
|
+
user_wrap.(ctx, &block)
|
28
57
|
end
|
58
|
+
end
|
29
59
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
60
|
+
def self.call((ctx, flow_options), **circuit_options)
|
61
|
+
# since yield is called without arguments, we need to pull default params from here. Oh ... tricky.
|
62
|
+
block_calling_wrapped = ->(args=[ctx, flow_options], kwargs=circuit_options) {
|
63
|
+
Activity::Circuit::Runner.(block_activity, args, **kwargs)
|
64
|
+
}
|
65
|
+
|
66
|
+
# call the user's Wrap {} block in the operation.
|
67
|
+
# This will invoke block_calling_wrapped above if the user block yields.
|
68
|
+
returned = @state.get(:user_wrap).([ctx, flow_options], **circuit_options, &block_calling_wrapped)
|
69
|
+
|
70
|
+
# {returned} can be
|
71
|
+
# 1. {circuit interface return} from the begin block, because the wrapped OP passed
|
72
|
+
# 2. {task interface return} because the user block returns "customized" signals, true of fale
|
73
|
+
|
74
|
+
if returned.is_a?(Array) # 1. {circuit interface return}, new style.
|
75
|
+
signal, (ctx, flow_options) = returned
|
76
|
+
else # 2. {task interface return}, only a signal (or true/false)
|
77
|
+
# TODO: deprecate this?
|
78
|
+
signal = returned
|
47
79
|
end
|
48
80
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}
|
81
|
+
# If there's no mapping, use the original {signal} .
|
82
|
+
# This usually means signal is a terminus or a custom signal.
|
83
|
+
signal = @state.get(:signal_to_output).fetch(signal, signal)
|
53
84
|
|
54
|
-
|
55
|
-
# This will invoke block_calling_wrapped above if the user block yields.
|
56
|
-
returned = @user_wrap.([ctx, flow_options], **circuit_options, &block_calling_wrapped)
|
57
|
-
|
58
|
-
# {returned} can be
|
59
|
-
# 1. {circuit interface return} from the begin block, because the wrapped OP passed
|
60
|
-
# 2. {task interface return} because the user block returns "customized" signals, true of fale
|
61
|
-
|
62
|
-
if returned.is_a?(Array) # 1. {circuit interface return}, new style.
|
63
|
-
signal, (ctx, flow_options) = returned
|
64
|
-
else # 2. {task interface return}, only a signal (or true/false)
|
65
|
-
# TODO: deprecate this?
|
66
|
-
signal = returned
|
67
|
-
end
|
68
|
-
|
69
|
-
# Use the original {signal} if there's no mapping.
|
70
|
-
# This usually means signal is an End instance or a custom signal.
|
71
|
-
signal = @signal_to_output.fetch(signal, signal)
|
72
|
-
|
73
|
-
return signal, [ctx, flow_options]
|
74
|
-
end
|
75
|
-
|
76
|
-
def call_wrapped_activity((ctx, flow_options), **circuit_options)
|
77
|
-
@operation.to_h[:activity].([ctx, flow_options], **circuit_options) # :exec_context is this instance.
|
78
|
-
end
|
85
|
+
return signal, [ctx, flow_options]
|
79
86
|
end
|
80
87
|
end # Wrap
|
81
88
|
end
|
data/lib/trailblazer/macro.rb
CHANGED
@@ -2,6 +2,7 @@ require "forwardable"
|
|
2
2
|
require "trailblazer/activity/dsl/linear"
|
3
3
|
require "trailblazer/operation" # TODO: remove this dependency
|
4
4
|
|
5
|
+
require "trailblazer/macro/strategy"
|
5
6
|
require "trailblazer/macro/model"
|
6
7
|
require "trailblazer/macro/policy"
|
7
8
|
require "trailblazer/macro/guard"
|
@@ -9,10 +10,60 @@ require "trailblazer/macro/pundit"
|
|
9
10
|
require "trailblazer/macro/nested"
|
10
11
|
require "trailblazer/macro/rescue"
|
11
12
|
require "trailblazer/macro/wrap"
|
13
|
+
require "trailblazer/macro/each"
|
12
14
|
|
13
15
|
module Trailblazer
|
14
16
|
module Macro
|
15
|
-
|
17
|
+
# TaskAdapter::AssignVariable
|
18
|
+
# Run {user_proc} with "step interface" and assign its return value to ctx[@variable_name].
|
19
|
+
# @private
|
20
|
+
# This is experimental.
|
21
|
+
class AssignVariable
|
22
|
+
# name of the ctx variable we want to assign the return_value of {user_proc} to.
|
23
|
+
def initialize(return_value_step, variable_name:)
|
24
|
+
@return_value_step = return_value_step
|
25
|
+
@variable_name = variable_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def call((ctx, flow_options), **circuit_options)
|
29
|
+
return_value, ctx = @return_value_step.([ctx, flow_options], **circuit_options)
|
30
|
+
|
31
|
+
ctx[@variable_name] = return_value
|
32
|
+
|
33
|
+
return return_value, ctx
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.task_adapter_for_decider(decider_with_step_interface, variable_name:)
|
38
|
+
return_value_circuit_step = Activity::Circuit.Step(decider_with_step_interface, option: true)
|
39
|
+
|
40
|
+
assign_task = AssignVariable.new(return_value_circuit_step, variable_name: variable_name)
|
41
|
+
|
42
|
+
Activity::Circuit::TaskAdapter.new(assign_task) # call {assign_task} with circuit-interface, interpret result.
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.block_activity_for(block_activity, &block)
|
46
|
+
return block_activity, block_activity.to_h[:outputs] unless block_given?
|
47
|
+
|
48
|
+
block_activity = Class.new(Activity::FastTrack, &block) # TODO: use Wrap() logic!
|
49
|
+
block_activity.extend Each::Transitive
|
50
|
+
|
51
|
+
return block_activity, block_activity.to_h[:outputs]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.id_for(user_proc, macro:, hint: nil)
|
55
|
+
id =
|
56
|
+
if user_proc.is_a?(Class)
|
57
|
+
user_proc.to_s
|
58
|
+
elsif user_proc.instance_of?(Method)
|
59
|
+
"method(:#{user_proc.name})"
|
60
|
+
else
|
61
|
+
hint || rand(4)
|
62
|
+
end
|
63
|
+
|
64
|
+
"#{macro}/#{id}"
|
65
|
+
end
|
66
|
+
end # Macro
|
16
67
|
|
17
68
|
# All macros sit in the {Trailblazer::Macro} namespace, where we forward calls from
|
18
69
|
# operations and activities to.
|
@@ -23,6 +74,6 @@ module Trailblazer
|
|
23
74
|
# Extending the {Linear::Helper} namespace is the canonical way to import
|
24
75
|
# macros into Railway, FastTrack, Operation, etc.
|
25
76
|
extend Forwardable
|
26
|
-
def_delegators Trailblazer::Macro, :Model, :Nested, :Wrap, :Rescue
|
77
|
+
def_delegators Trailblazer::Macro, :Model, :Nested, :Wrap, :Rescue, :Each
|
27
78
|
end # Helper
|
28
79
|
end
|