trailblazer-activity 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop-https---raw-githubusercontent-com-trailblazer-meta-master-rubocop-yml +101 -0
- data/.rubocop.yml +4 -13
- data/.rubocop_todo.yml +474 -476
- data/.travis.yml +3 -2
- data/CHANGES.md +10 -0
- data/Gemfile +5 -4
- data/README.md +2 -0
- data/Rakefile +1 -1
- data/lib/trailblazer/activity.rb +29 -92
- data/lib/trailblazer/activity/circuit.rb +74 -0
- data/lib/trailblazer/activity/config.rb +4 -6
- data/lib/trailblazer/activity/introspect.rb +33 -129
- data/lib/trailblazer/activity/present.rb +14 -39
- data/lib/trailblazer/activity/schema.rb +13 -0
- data/lib/trailblazer/activity/schema/implementation.rb +10 -0
- data/lib/trailblazer/activity/schema/intermediate.rb +94 -0
- data/lib/trailblazer/activity/structures.rb +43 -43
- data/lib/trailblazer/activity/task_wrap.rb +29 -16
- data/lib/trailblazer/activity/task_wrap/call_task.rb +4 -4
- data/lib/trailblazer/activity/task_wrap/inject.rb +37 -0
- data/lib/trailblazer/activity/task_wrap/pipeline.rb +55 -0
- data/lib/trailblazer/activity/task_wrap/runner.rb +10 -19
- data/lib/trailblazer/activity/task_wrap/variable_mapping.rb +25 -97
- data/lib/trailblazer/activity/testing.rb +64 -22
- data/lib/trailblazer/activity/trace.rb +88 -41
- data/lib/trailblazer/activity/version.rb +4 -2
- data/trailblazer-activity.gemspec +5 -9
- metadata +18 -55
- data/lib/trailblazer/activity/dsl/add_task.rb +0 -22
- data/lib/trailblazer/activity/dsl/helper.rb +0 -68
- data/lib/trailblazer/activity/dsl/magnetic.rb +0 -36
- data/lib/trailblazer/activity/dsl/magnetic/builder.rb +0 -101
- data/lib/trailblazer/activity/dsl/magnetic/builder/default_normalizer.rb +0 -26
- data/lib/trailblazer/activity/dsl/magnetic/builder/fast_track.rb +0 -118
- data/lib/trailblazer/activity/dsl/magnetic/builder/normalizer.rb +0 -113
- data/lib/trailblazer/activity/dsl/magnetic/builder/path.rb +0 -105
- data/lib/trailblazer/activity/dsl/magnetic/builder/railway.rb +0 -97
- data/lib/trailblazer/activity/dsl/magnetic/builder/state.rb +0 -58
- data/lib/trailblazer/activity/dsl/magnetic/finalizer.rb +0 -51
- data/lib/trailblazer/activity/dsl/magnetic/generate.rb +0 -62
- data/lib/trailblazer/activity/dsl/magnetic/merge.rb +0 -16
- data/lib/trailblazer/activity/dsl/magnetic/process_options.rb +0 -76
- data/lib/trailblazer/activity/dsl/magnetic/structure/alterations.rb +0 -44
- data/lib/trailblazer/activity/dsl/magnetic/structure/plus_poles.rb +0 -85
- data/lib/trailblazer/activity/dsl/magnetic/structure/polarization.rb +0 -23
- data/lib/trailblazer/activity/dsl/record.rb +0 -11
- data/lib/trailblazer/activity/dsl/schema/dependencies.rb +0 -46
- data/lib/trailblazer/activity/dsl/schema/sequence.rb +0 -46
- data/lib/trailblazer/activity/dsl/strategy/build_state.rb +0 -32
- data/lib/trailblazer/activity/dsl/strategy/fast_track.rb +0 -24
- data/lib/trailblazer/activity/dsl/strategy/path.rb +0 -26
- data/lib/trailblazer/activity/dsl/strategy/plan.rb +0 -36
- data/lib/trailblazer/activity/dsl/strategy/railway.rb +0 -23
- data/lib/trailblazer/activity/interface.rb +0 -16
- data/lib/trailblazer/activity/task_wrap/merge.rb +0 -23
- data/lib/trailblazer/activity/task_wrap/trace.rb +0 -44
- data/lib/trailblazer/circuit.rb +0 -71
@@ -1,113 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
module Activity::Magnetic
|
3
|
-
# One {Normalizer} instance is called for every DSL call (step/pass/fail etc.) and normalizes/defaults
|
4
|
-
# the user options, such as setting `:id`, connecting the task's outputs or wrapping the user's
|
5
|
-
# task via {TaskBuilder::Binary} in order to translate true/false to `Right` or `Left`.
|
6
|
-
#
|
7
|
-
# The Normalizer sits in the `@builder`, which receives all DSL calls from the Operation subclass.
|
8
|
-
class Normalizer
|
9
|
-
def self.build(task_builder: Activity::TaskBuilder.method(:Binary), default_outputs: Builder::Path.default_outputs, pipeline: Pipeline, extension:[], **options)
|
10
|
-
return new(
|
11
|
-
default_outputs: default_outputs,
|
12
|
-
extension: extension,
|
13
|
-
task_builder: task_builder,
|
14
|
-
pipeline: pipeline,
|
15
|
-
), options
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(task_builder:, default_outputs:, pipeline:, **options)
|
19
|
-
@task_builder = task_builder
|
20
|
-
@default_outputs = default_outputs
|
21
|
-
@pipeline = pipeline # TODO: test me.
|
22
|
-
freeze
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(task, options)
|
26
|
-
ctx = {
|
27
|
-
task: task,
|
28
|
-
options: options,
|
29
|
-
task_builder: @task_builder,
|
30
|
-
default_outputs: @default_outputs,
|
31
|
-
}
|
32
|
-
|
33
|
-
signal, (ctx, ) = @pipeline.( [ctx], {} )
|
34
|
-
|
35
|
-
return ctx[:options][:task], ctx[:local_options], ctx[:connection_options], ctx[:sequence_options], ctx[:extension_options]
|
36
|
-
end
|
37
|
-
|
38
|
-
# needs the basic Normalizer
|
39
|
-
|
40
|
-
# :default_plus_poles is an injectable option.
|
41
|
-
module Pipeline
|
42
|
-
extend Trailblazer::Activity::Path( normalizer_class: DefaultNormalizer, plus_poles: PlusPoles.new.merge( Builder::Path.default_outputs.values ) ) # FIXME: the DefaultNormalizer actually doesn't need Left.
|
43
|
-
|
44
|
-
def self.split_options( ctx, task:, options:, ** )
|
45
|
-
keywords = extract_dsl_keywords(options)
|
46
|
-
extensions = extract_extensions(options)
|
47
|
-
|
48
|
-
# sort through the "original" user DSL options.
|
49
|
-
options, extension_options = Options.normalize( options, extensions ) # DISCUSS:
|
50
|
-
options, local_options = Options.normalize( options, keywords ) # DISCUSS:
|
51
|
-
local_options, sequence_options = Options.normalize( local_options, Activity::Schema::Dependencies.sequence_keywords )
|
52
|
-
|
53
|
-
ctx[:local_options],
|
54
|
-
ctx[:connection_options],
|
55
|
-
ctx[:sequence_options],
|
56
|
-
ctx[:extension_options] = local_options, options, sequence_options, extension_options
|
57
|
-
end
|
58
|
-
|
59
|
-
# Filter out connections, e.g. `Output(:fail_fast) => :success` and return only the keywords like `:id` or `:replace`.
|
60
|
-
def self.extract_dsl_keywords(options, connection_classes = [Activity::Output, Activity::DSL::OutputSemantic])
|
61
|
-
options.keys - options.keys.find_all { |k| connection_classes.include?( k.class ) }
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.extract_extensions(options, extensions_classes = [Activity::DSL::Extension])
|
65
|
-
options.keys.find_all { |k| extensions_classes.include?( k.class ) }
|
66
|
-
end
|
67
|
-
|
68
|
-
# FIXME; why don't we use the extensions passed into the initializer?
|
69
|
-
def self.initialize_extension_option( ctx, options:, ** )
|
70
|
-
ctx[:options] = options.merge( Activity::DSL::Extension.new( Activity::DSL.method(:record) ) => true )
|
71
|
-
end
|
72
|
-
|
73
|
-
# Normalizes ctx[:options] (the user-options via the DSL) into the internal Hash format.
|
74
|
-
def self.normalize_for_macro( ctx, task:, options:, task_builder:, ** )
|
75
|
-
ctx[:options] =
|
76
|
-
if task.is_a?(::Hash) # macro.
|
77
|
-
task.merge(options) # Note that the user options are merged over the macro options.
|
78
|
-
else # user step
|
79
|
-
{ id: task }
|
80
|
-
.merge(options) # default :id
|
81
|
-
.merge( task: task_builder.(task) )
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# :outputs passed: I know what I want to have connected.
|
86
|
-
# no :outputs: use default_outputs
|
87
|
-
# ALWAYS connect all outputs to their semantic-color.
|
88
|
-
|
89
|
-
# Create the `plus_poles: <PlusPoles>` tuple where the PlusPoles instance will act as the interface
|
90
|
-
# to rewire or add connections for the DSL.
|
91
|
-
def self.initialize_plus_poles( ctx, local_options:, default_outputs:, ** )
|
92
|
-
outputs = local_options[:outputs] || default_outputs
|
93
|
-
|
94
|
-
ctx[:local_options] =
|
95
|
-
{
|
96
|
-
plus_poles: PlusPoles.initial(outputs),
|
97
|
-
}
|
98
|
-
.merge(local_options)
|
99
|
-
end
|
100
|
-
|
101
|
-
task Activity::TaskBuilder::Binary( method(:initialize_extension_option) ), id: "initialize_extension_option"
|
102
|
-
task Activity::TaskBuilder::Binary( method(:normalize_for_macro) ), id: "normalize_for_macro"
|
103
|
-
|
104
|
-
task Activity::TaskBuilder::Binary( Activity::TaskWrap::VariableMapping.method(:normalizer_step_for_input_output) )
|
105
|
-
|
106
|
-
task Activity::TaskBuilder::Binary( method(:split_options) ), id: "split_options"
|
107
|
-
task Activity::TaskBuilder::Binary( method(:initialize_plus_poles) ), id: "initialize_plus_poles"
|
108
|
-
# task ->((ctx, _), **) { pp ctx; [Activity::Right, [ctx, _]] }
|
109
|
-
end
|
110
|
-
end # Normalizer
|
111
|
-
|
112
|
-
end
|
113
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
module Activity::Magnetic
|
3
|
-
class Builder
|
4
|
-
|
5
|
-
class Path < Builder
|
6
|
-
# strategy_options:
|
7
|
-
# :track_color
|
8
|
-
# :end_semantic
|
9
|
-
def self.for(normalizer, builder_options={}) # Build the Builder.
|
10
|
-
Activity::Magnetic::Builder(
|
11
|
-
Path,
|
12
|
-
normalizer,
|
13
|
-
{ track_color: :success, end_semantic: :success }.merge( builder_options )
|
14
|
-
)
|
15
|
-
end
|
16
|
-
|
17
|
-
# In most cases, a task has a binary signal, which is why we decided to make that
|
18
|
-
# the default output set.
|
19
|
-
def self.default_outputs
|
20
|
-
{
|
21
|
-
:success => Activity.Output(Activity::Right, :success),
|
22
|
-
:failure => Activity.Output(Activity::Left, :failure)
|
23
|
-
}
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
|
27
|
-
def self.InitialAdds(**options)
|
28
|
-
StartAdds(**options) + EndAdds(**options)
|
29
|
-
end
|
30
|
-
|
31
|
-
# TODO: make this nicer.
|
32
|
-
def self.StartAdds(track_color:, end_semantic:, start_outputs: {success: self.default_outputs[:success]}, **)
|
33
|
-
builder_options={ track_color: track_color, end_semantic: end_semantic }
|
34
|
-
|
35
|
-
adds(
|
36
|
-
Activity::Start.new(semantic: :default),
|
37
|
-
|
38
|
-
TaskPolarizations(builder_options),
|
39
|
-
|
40
|
-
{}, { group: :start },
|
41
|
-
|
42
|
-
id: "Start.default",
|
43
|
-
magnetic_to: [],
|
44
|
-
plus_poles: PlusPoles.initial(start_outputs), # FIXME: this is actually redundant with Normalizer
|
45
|
-
)
|
46
|
-
end
|
47
|
-
|
48
|
-
# TODO: make this nicer.
|
49
|
-
def self.EndAdds(track_color:, end_semantic:, track_end: Activity.End(end_semantic), end_id: nil, **)
|
50
|
-
# an end can either be a reference to another task,
|
51
|
-
# or a "real" end event.
|
52
|
-
if end_id
|
53
|
-
[[:magnetic_to,
|
54
|
-
[ end_id, [track_color] ] ]
|
55
|
-
]
|
56
|
-
else
|
57
|
-
builder_options={ track_color: track_color, end_semantic: end_semantic }
|
58
|
-
|
59
|
-
adds(
|
60
|
-
track_end,
|
61
|
-
|
62
|
-
EndEventPolarizations(builder_options), # only sets :magnetic_to.
|
63
|
-
|
64
|
-
{}, { group: :end },
|
65
|
-
|
66
|
-
id: "End.#{track_color}",
|
67
|
-
plus_poles: {},
|
68
|
-
magnetic_to: nil,
|
69
|
-
)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.TaskPolarizations(track_color:, **)
|
74
|
-
[TaskPolarization.new( track_color: track_color )]
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.EndEventPolarizations(track_color:, **)
|
78
|
-
[EndEventPolarization.new( track_color: track_color )]
|
79
|
-
end
|
80
|
-
|
81
|
-
class TaskPolarization
|
82
|
-
def initialize(track_color:)
|
83
|
-
@track_color = track_color
|
84
|
-
end
|
85
|
-
|
86
|
-
def call(magnetic_to, plus_poles, options)
|
87
|
-
[
|
88
|
-
magnetic_to || [@track_color],
|
89
|
-
plus_poles.reconnect( :success => @track_color )
|
90
|
-
]
|
91
|
-
end
|
92
|
-
end # TaskPolarization
|
93
|
-
|
94
|
-
class EndEventPolarization < TaskPolarization
|
95
|
-
def call(magnetic_to, plus_poles, options)
|
96
|
-
[
|
97
|
-
magnetic_to || [@track_color],
|
98
|
-
{}
|
99
|
-
]
|
100
|
-
end
|
101
|
-
end # EndEventPolarization
|
102
|
-
end # Path
|
103
|
-
end # Builder
|
104
|
-
end
|
105
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
module Activity::Magnetic
|
3
|
-
class Builder
|
4
|
-
class Railway < Builder
|
5
|
-
def self.for(normalizer, builder_options={}) # Build the Builder.
|
6
|
-
Activity::Magnetic::Builder(
|
7
|
-
Railway,
|
8
|
-
normalizer,
|
9
|
-
{ track_color: :success, end_semantic: :success, failure_color: :failure }.merge( builder_options )
|
10
|
-
)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Adds the End.failure end to the Path sequence.
|
14
|
-
# @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
|
15
|
-
def self.InitialAdds(failure_color:raise, failure_end: Activity.End(failure_color), **builder_options)
|
16
|
-
path_adds = Path.InitialAdds(**builder_options)
|
17
|
-
|
18
|
-
end_adds = adds(
|
19
|
-
failure_end,
|
20
|
-
|
21
|
-
Path::EndEventPolarizations(builder_options),
|
22
|
-
|
23
|
-
{},
|
24
|
-
{ group: :end },
|
25
|
-
|
26
|
-
magnetic_to: [failure_color],
|
27
|
-
id: "End.#{failure_color}",
|
28
|
-
plus_poles: {},
|
29
|
-
)
|
30
|
-
|
31
|
-
path_adds + end_adds
|
32
|
-
end
|
33
|
-
|
34
|
-
# ONLY JOB: magnetic_to and Outputs ("Polarization") via PlusPoles.merge
|
35
|
-
def self.StepPolarizations(**options)
|
36
|
-
[
|
37
|
-
*Path.TaskPolarizations(options),
|
38
|
-
StepPolarization.new(options)
|
39
|
-
]
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.PassPolarizations(options)
|
43
|
-
[
|
44
|
-
Railway::PassPolarization.new( options )
|
45
|
-
]
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.FailPolarizations(options)
|
49
|
-
[
|
50
|
-
Railway::FailPolarization.new( options )
|
51
|
-
]
|
52
|
-
end
|
53
|
-
|
54
|
-
class StepPolarization
|
55
|
-
def initialize(track_color: :success, failure_color: :failure, **o)
|
56
|
-
@track_color, @failure_color = track_color, failure_color
|
57
|
-
end
|
58
|
-
|
59
|
-
# Returns the polarization for a DSL call. Takes care of user options such as :magnetic_to.
|
60
|
-
def call(magnetic_to, plus_poles, options)
|
61
|
-
[
|
62
|
-
magnetic_to || default_magnetic_to,
|
63
|
-
plus_poles_for(plus_poles, options),
|
64
|
-
]
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def plus_poles_for(plus_poles, options)
|
70
|
-
plus_poles.reconnect( :failure => @failure_color )
|
71
|
-
end
|
72
|
-
|
73
|
-
def default_magnetic_to
|
74
|
-
[@track_color]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class PassPolarization < StepPolarization
|
79
|
-
def plus_poles_for(plus_poles, options)
|
80
|
-
plus_poles.reconnect( :failure => @track_color, :success => @track_color )
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class FailPolarization < StepPolarization
|
85
|
-
def default_magnetic_to
|
86
|
-
[@failure_color]
|
87
|
-
end
|
88
|
-
|
89
|
-
def plus_poles_for(plus_poles, options)
|
90
|
-
plus_poles.reconnect( :failure => @failure_color, :success => @failure_color )
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
end # Railway
|
95
|
-
end # Builder
|
96
|
-
end
|
97
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
class Activity::Magnetic::Builder
|
3
|
-
# Maintain Builder instance plus Adds/Process/Outputs as immutable objects.
|
4
|
-
module State
|
5
|
-
def self.build(builder_class, normalizer, builder_options)
|
6
|
-
builder, adds = builder_class.for(normalizer, builder_options) # e.g. Path.for(...) which creates a Builder::Path instance.
|
7
|
-
|
8
|
-
recompile(builder.freeze, adds.freeze)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.add(builder, adds, strategy, polarizer, *args, &block)
|
12
|
-
new_adds, *returned_options = builder.insert(strategy, polarizer, *args, &block) # TODO: move that out of here.
|
13
|
-
|
14
|
-
adds = adds + new_adds
|
15
|
-
|
16
|
-
recompile(builder, adds.freeze, returned_options)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
# @return {builder, Adds, Process, outputs}, returned_options
|
22
|
-
def self.recompile(builder, adds, *args)
|
23
|
-
circuit, outputs = recompile_circuit(adds)
|
24
|
-
|
25
|
-
return builder, adds, circuit.freeze, outputs.freeze, *args
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.recompile_circuit(adds)
|
29
|
-
circuit, outputs = Recompile.( adds )
|
30
|
-
end
|
31
|
-
|
32
|
-
module Recompile
|
33
|
-
# Recompile the circuit and outputs from the {ADDS} instance that collects circuit tasks and connections.
|
34
|
-
#
|
35
|
-
# @return [Process, Hash] The {Process} instance and its outputs hash.
|
36
|
-
def self.call(adds)
|
37
|
-
circuit, end_events = Finalizer.(adds)
|
38
|
-
outputs = recompile_outputs(end_events)
|
39
|
-
|
40
|
-
return circuit, outputs
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def self.recompile_outputs(end_events)
|
46
|
-
ary = end_events.collect do |evt|
|
47
|
-
[
|
48
|
-
semantic = evt.to_h[:semantic],
|
49
|
-
Activity::Output(evt, semantic)
|
50
|
-
]
|
51
|
-
end
|
52
|
-
|
53
|
-
::Hash[ ary ]
|
54
|
-
end
|
55
|
-
end # Recompile
|
56
|
-
end # State
|
57
|
-
end
|
58
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
module Activity::Magnetic
|
3
|
-
class Builder
|
4
|
-
module Finalizer
|
5
|
-
|
6
|
-
def self.call(adds)
|
7
|
-
tripletts = adds_to_tripletts(adds)
|
8
|
-
|
9
|
-
circuit_hash = tripletts_to_circuit_hash( tripletts )
|
10
|
-
|
11
|
-
circuit_hash_to_process( circuit_hash )
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.adds_to_tripletts(adds)
|
15
|
-
alterations = adds_to_alterations(adds)
|
16
|
-
|
17
|
-
alterations.to_a
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.adds_to_alterations(adds)
|
21
|
-
alterations = DSL::Alterations.new
|
22
|
-
|
23
|
-
adds = adds.compact # TODO: test me explicitly, and where does this come from anyway?
|
24
|
-
|
25
|
-
adds.each { |method, cfg| alterations.send( method, *cfg ) }
|
26
|
-
|
27
|
-
alterations
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.tripletts_to_circuit_hash(tripletts)
|
31
|
-
Activity::Magnetic::Generate.( tripletts )
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.circuit_hash_to_process(circuit_hash)
|
35
|
-
end_events = end_events_for(circuit_hash)
|
36
|
-
|
37
|
-
return Circuit.new(circuit_hash, end_events, start_task: circuit_hash.keys.first), end_events
|
38
|
-
end
|
39
|
-
|
40
|
-
# Find all end events that don't have outgoing connections.
|
41
|
-
def self.end_events_for(circuit_hash)
|
42
|
-
ary = circuit_hash.collect do |task, connections|
|
43
|
-
task.kind_of?(Activity::End) && connections.empty? ? task : nil
|
44
|
-
end
|
45
|
-
|
46
|
-
ary.compact
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
module Activity::Magnetic
|
3
|
-
# Transforms an array of {Triplett}s into a circuit hash.
|
4
|
-
module Generate
|
5
|
-
Line = Struct.new(:source, :output)
|
6
|
-
MinusPole = Struct.new(:color)
|
7
|
-
|
8
|
-
class OpenLines
|
9
|
-
def initialize
|
10
|
-
@arr = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def pop(signal, &block)
|
14
|
-
lines = @arr.find_all { |line| line.output.color == signal }
|
15
|
-
@arr -= lines
|
16
|
-
|
17
|
-
lines.each(&block)
|
18
|
-
lines.any?
|
19
|
-
end
|
20
|
-
|
21
|
-
def <<((node, output))
|
22
|
-
@arr << Line.new(node, output)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.call(tasks)
|
27
|
-
open_plus_poles = OpenLines.new
|
28
|
-
open_minus_poles = OpenLines.new
|
29
|
-
circuit_hash = {}
|
30
|
-
|
31
|
-
tasks.each do |(magnetic_to, node, outputs)|
|
32
|
-
circuit_hash[ node ] ||= {} # DISCUSS: or needed?
|
33
|
-
|
34
|
-
magnetic_to.each do |edge_color| # minus poles
|
35
|
-
open_plus_poles.pop(edge_color) do |line|
|
36
|
-
connect( circuit_hash, line.source, line.output.signal, node )
|
37
|
-
end and next
|
38
|
-
|
39
|
-
# only run when there were no open_minus_poles
|
40
|
-
open_minus_poles << [node, MinusPole.new(edge_color)] # open inputs on a node, waiting to be connected.
|
41
|
-
end
|
42
|
-
|
43
|
-
outputs.each do |output|
|
44
|
-
open_minus_poles.pop(output.color) do |line|
|
45
|
-
connect( circuit_hash, node, output.signal, line.source )
|
46
|
-
end and next
|
47
|
-
|
48
|
-
# only run when there were no open_plus_poles
|
49
|
-
open_plus_poles << [node, output]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
circuit_hash
|
54
|
-
end
|
55
|
-
|
56
|
-
# plus minus
|
57
|
-
def self.connect(circuit_hash, source, signal, target)
|
58
|
-
circuit_hash[ source ][ signal ] = target
|
59
|
-
end
|
60
|
-
end # Magnetic
|
61
|
-
end
|
62
|
-
end
|