Module: Trailblazer::Activity::Schema::Intermediate::Compiler

Defined in:
lib/trailblazer/activity/schema/compiler.rb

Constant Summary collapse

DEFAULT_CONFIG =

DISCUSS: this really doesn’t have to be here, but works for now and we want it in 99%.

{wrap_static: Hash.new(Activity::TaskWrap.initial_wrap_static.freeze)}

Class Method Summary collapse

Class Method Details

.call(intermediate, implementation, config_merge: {}) ⇒ Object

Compiles a Trailblazer::Activity::Schema instance from an intermediate structure and the implementation object references.

Intermediate structure, Implementation, calls extensions, passes config # TODO



15
16
17
18
19
20
21
22
23
# File 'lib/trailblazer/activity/schema/compiler.rb', line 15

def call(intermediate, implementation, config_merge: {})
  config = DEFAULT_CONFIG
    .merge(config_merge)
    .freeze

  circuit, outputs, nodes, config = schema_components(intermediate, implementation, config)

  Schema.new(circuit, outputs, nodes, config)
end

.connections_for(intermediate_outs, task_outputs, implementation) ⇒ Object

Compute the connections for circuit_task. For a terminus, this produces an empty hash.



69
70
71
72
73
74
75
76
# File 'lib/trailblazer/activity/schema/compiler.rb', line 69

def connections_for(intermediate_outs, task_outputs, implementation)
  intermediate_outs.collect { |intermediate_out| # Intermediate::Out, it's abstract.
    [
      output_for_semantic(task_outputs, intermediate_out.semantic).signal,
      implementation.fetch(intermediate_out.target).circuit_task    # Find the implementation task, the Ruby code component for runtime.
    ]
  }.to_h
end

.invoke_extensions_for(config, impl_task, id) ⇒ Object

Run all Implementation::Task.extensions and return new config



92
93
94
95
96
# File 'lib/trailblazer/activity/schema/compiler.rb', line 92

def invoke_extensions_for(config, impl_task, id)
  impl_task
    .extensions
    .inject(config) { |cfg, ext| ext.(config: cfg, id: id, task: impl_task) } # {ext} must return new config hash.
end

.output_for_semantic(outputs, semantic) ⇒ Object

In an array of Output, find the output matching semantic.



99
100
101
# File 'lib/trailblazer/activity/schema/compiler.rb', line 99

def output_for_semantic(outputs, semantic)
  outputs.find { |out| out.semantic == semantic } or raise "`#{semantic}` not found in implementation"
end

.schema_components(intermediate, implementation, config) ⇒ Object

From the intermediate “template” and the actual implementation, compile a Circuit instance.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/trailblazer/activity/schema/compiler.rb', line 26

def schema_components(intermediate, implementation, config)
  wiring = {}.compare_by_identity # https://ruby-doc.org/3.3.0/Hash.html#class-Hash-label-Modifying+an+Active+Hash+Key
  nodes_attributes  = []

  intermediate.wiring.each do |task_ref, outs|
    id        = task_ref.id
    impl_task = implementation.fetch(id)
    task      = impl_task.circuit_task
    outputs   = impl_task.outputs

    wiring[task] = connections_for(outs, outputs, implementation)

    nodes_attributes << [
      id,               # id
      task,             # task
      task_ref[:data],  # TODO: allow adding data from implementation.
      outputs           # {Activity::Output}s
    ]

    # Invoke each task's extensions (usually coming from the DSL user or some macro).
    # We're expecting each {ext} to be a {TaskWrap::Extension::WrapStatic} instance.
    config = invoke_extensions_for(config, impl_task, id)
  end

  start_id = intermediate.start_task_id

  terminus_to_output  = terminus_to_output(intermediate, implementation)
  activity_outputs    = terminus_to_output.values

  circuit = Circuit.new(
    wiring,
    terminus_to_output.keys, # termini
    start_task: implementation.fetch(start_id).circuit_task
  )

  return circuit,
    activity_outputs,
    Schema::Nodes(nodes_attributes),
    config
end

.terminus_to_output(intermediate, implementation) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/trailblazer/activity/schema/compiler.rb', line 78

def terminus_to_output(intermediate, implementation)
  terminus_to_semantic = intermediate.stop_task_ids

  terminus_to_semantic.collect do |id, semantic|
    terminus_task = implementation.fetch(id).circuit_task

    [
      terminus_task,
      Activity::Output(terminus_task, semantic) # The End instance is the signal.
    ]
  end.to_h
end