Module: Trailblazer::Activity::Path::DSL

Defined in:
lib/trailblazer/activity/path.rb

Overview

Functions that help creating a path-specific sequence.

Defined Under Namespace

Classes: State

Constant Summary collapse

Linear =
Activity::DSL::Linear
Normalizers =

This is slow and should be done only once at compile-time, DISCUSS: maybe make this a function? These are the normalizers for an Trailblazer::Activity, to be injected into a State.

Linear::State::Normalizer.new(
  step:  Linear::Normalizer.activity_normalizer( Path::DSL.normalizer ), # here, we extend the generic FastTrack::step_normalizer with the Activity-specific DSL
)

Class Method Summary collapse

Class Method Details

.append_end(sequence, **options) ⇒ Object



123
124
125
# File 'lib/trailblazer/activity/path.rb', line 123

def append_end(sequence, **options)
  sequence = Linear::DSL.insert_task(sequence, **append_end_options(options))
end

.append_end_options(task:, magnetic_to:, id:, append_to: "End.success") ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/trailblazer/activity/path.rb', line 127

def append_end_options(task:, magnetic_to:, id:, append_to: "End.success")
  end_args = {sequence_insert: [Linear::Insert.method(:Append), append_to], stop_event: true}

  {
    task:         task,
    magnetic_to:  magnetic_to,
    id:           id,
    wirings:      [
      Linear::Search::Noop(
        Activity::Output.new(task, task.to_h[:semantic]), # DISCUSS: do we really want to transport the semantic "in" the object?
        # magnetic_to
      )],
    # outputs:      {magnetic_to => },
    # connections:  {magnetic_to => [Linear::Search.method(:Noop)]},
    **end_args
   }
end

.initial_sequence(track_name:, end_task:, end_id:) ⇒ Object

Returns an initial two-step sequence with > End.success.



117
118
119
120
121
# File 'lib/trailblazer/activity/path.rb', line 117

def initial_sequence(track_name:, end_task:, end_id:)
  # TODO: this could be an Activity itself but maybe a bit too much for now.
  sequence = start_sequence(track_name: track_name)
  sequence = append_end(sequence, task: end_task, magnetic_to: track_name, id: end_id, append_to: "Start.default")
end

.merge_path_connections(ctx, flow_options) ⇒ Object



52
53
54
55
56
57
# File 'lib/trailblazer/activity/path.rb', line 52

def merge_path_connections((ctx, flow_options), *)
  raise unless track_name = ctx[:track_name]# TODO: make track_name required kw.
  ctx = {connections: unary_connections(track_name: track_name)}.merge(ctx)

  return Right, [ctx, flow_options]
end

.merge_path_outputs(ctx, flow_options) ⇒ Object



46
47
48
49
50
# File 'lib/trailblazer/activity/path.rb', line 46

def merge_path_outputs((ctx, flow_options), *)
  ctx = {outputs: unary_outputs}.merge(ctx)

  return Right, [ctx, flow_options]
end

.normalize_magnetic_to(ctx, flow_options) ⇒ Object

TODO: merge with Railway.merge_magnetic_to



94
95
96
97
98
99
100
# File 'lib/trailblazer/activity/path.rb', line 94

def normalize_magnetic_to((ctx, flow_options), *) # TODO: merge with Railway.merge_magnetic_to
  raise unless track_name = ctx[:track_name]# TODO: make track_name required kw.

  ctx = {magnetic_to: track_name}.merge(ctx)

  return Right, [ctx, flow_options]
end

.normalize_sequence_insert(ctx, flow_options) ⇒ Object

Processes :before,:after,:replace,:delete options and defaults to “End.success” which, yeah.



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/trailblazer/activity/path.rb', line 61

def normalize_sequence_insert((ctx, flow_options), *)
  insertion = ctx.keys & sequence_insert_options.keys
  insertion = insertion[0]   || :before
  raise if ctx[:end_id].nil? # FIXME
  target    = ctx[insertion] || ctx[:end_id]

  insertion_method = sequence_insert_options[insertion]

  ctx = ctx.merge(sequence_insert: [Linear::Insert.method(insertion_method), target])

  return Right, [ctx, flow_options]
end

.normalizerObject



11
12
13
14
15
# File 'lib/trailblazer/activity/path.rb', line 11

def normalizer
  prepend_step_options(
    initial_sequence(track_name: :success, end_task: Activity::End.new(semantic: :success), end_id: "End.success")
  )
end

.OptionsForState(normalizers: Normalizers, track_name: :success, end_task: Activity::End.new(semantic: :success), end_id: "End.success", **options) ⇒ Object

pp Normalizers



154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/trailblazer/activity/path.rb', line 154

def self.OptionsForState(normalizers: Normalizers, track_name: :success, end_task: Activity::End.new(semantic: :success), end_id: "End.success", **options)
  initial_sequence = Path::DSL.initial_sequence(track_name: track_name, end_task: end_task, end_id: end_id) # DISCUSS: the standard initial_seq could be cached.

  {
    normalizers:      normalizers,
    initial_sequence: initial_sequence,

    track_name:             track_name,
    end_id:                 end_id,
    step_interface_builder: Activity::TaskBuilder.method(:Binary), # DISCUSS: this is currently the only option we want to pass on in Path() ?
    adds:                   [],
    **options
  }
end

.prepend_step_options(sequence) ⇒ Object

Return Path::Normalizer sequence.



103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/trailblazer/activity/path.rb', line 103

def prepend_step_options(sequence)
  prepend_to_path(
    sequence,

    "path.outputs"          => method(:merge_path_outputs),
    "path.connections"      => method(:merge_path_connections),
    "path.sequence_insert"  => method(:normalize_sequence_insert),
    "path.raise_on_duplicate_id"  => method(:raise_on_duplicate_id),
    "path.magnetic_to"      => method(:normalize_magnetic_to),
    "path.wirings"          => Linear::Normalizer.method(:compile_wirings),
  )
end

.prepend_to_path(sequence, steps, insertion_method = Linear::Insert.method(:Prepend), insert_id = "End.success") ⇒ Object

DISCUSS: still not sure this should sit here. Pseudo-DSL that prepends steps to sequence.



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/trailblazer/activity/path.rb', line 25

def prepend_to_path(sequence, steps, insertion_method=Linear::Insert.method(:Prepend), insert_id="End.success")
  new_rows = steps.collect do |id, task|
    Linear::Sequence.create_row(
      task:         task,
      magnetic_to:  :success,
      wirings:      [Linear::Search::Forward(unary_outputs[:success], :success)],
      id:           id,
    )
  end

  insertion_method.(sequence, new_rows, insert_id)
end

.raise_on_duplicate_id(ctx, flow_options) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/trailblazer/activity/path.rb', line 84

def raise_on_duplicate_id((ctx, flow_options), *)
  id, sequence, insert = ctx[:id], ctx[:sequence], ctx[:sequence_insert][0] # DISCUSS: should we use Replace here or rather the option(s)?

  if insert != Linear::Insert.method(:Replace)
    raise "ID #{id} is already taken. Please specify an `:id`." if sequence.find { |row| row[3][:id] == id }
  end

  return Right, [ctx, flow_options]
end

.sequence_insert_optionsObject



75
76
77
78
79
80
81
82
# File 'lib/trailblazer/activity/path.rb', line 75

def sequence_insert_options
  {
    :before  => :Prepend,
    :after   => :Append,
    :replace => :Replace,
    :delete  => :Delete,
  }
end

.start_sequence(track_name:) ⇒ Object



17
18
19
20
21
# File 'lib/trailblazer/activity/path.rb', line 17

def start_sequence(track_name:)
  start_default = Activity::Start.new(semantic: :default)
  start_event   = Linear::Sequence.create_row(task: start_default, id: "Start.default", magnetic_to: nil, wirings: [Linear::Search::Forward(unary_outputs[:success], track_name)])
  sequence      = Linear::Sequence[start_event]
end

.unary_connections(track_name: :success) ⇒ Object



42
43
44
# File 'lib/trailblazer/activity/path.rb', line 42

def unary_connections(track_name: :success)
  {success: [Linear::Search.method(:Forward), track_name]}
end

.unary_outputsObject



38
39
40
# File 'lib/trailblazer/activity/path.rb', line 38

def unary_outputs
  {success: Activity::Output(Activity::Right, :success)}
end