Class: Trailblazer::Circuit

Inherits:
Object
  • Object
show all
Defined in:
lib/trailblazer/circuit.rb,
lib/trailblazer/circuit/task.rb,
lib/trailblazer/circuit/wrap.rb,
lib/trailblazer/circuit/trace.rb,
lib/trailblazer/circuit/present.rb,
lib/trailblazer/circuit/version.rb,
lib/trailblazer/circuit/activity.rb,
lib/trailblazer/circuit/testing.rb

Overview

Running a Circuit instance will run all tasks sequentially depending on the former’s result. Each task is called and retrieves the former task’s return values.

Note: Please use #Activity as a public circuit builder.

See Also:

Defined Under Namespace

Modules: Task, Trace, Wrap Classes: Activity, Direction, End, IllegalInputError, IllegalOutputSignalError, Left, Nested, Right, Start

Constant Summary collapse

Run =
->(activity, direction, *args) { activity.(direction, *args) }
VERSION =
"0.0.11"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(map, stop_events, name) ⇒ Circuit

Returns a new instance of Circuit.



18
19
20
21
22
# File 'lib/trailblazer/circuit.rb', line 18

def initialize(map, stop_events, name)
  @name        = name
  @map         = map
  @stop_events = stop_events
end

Class Method Details

.Activity(name = :default, events = {}, &block) ⇒ Object

Builder for an Activity with Circuit instance and events.



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/trailblazer/circuit/activity.rb', line 20

def self.Activity(name=:default, events={}, &block)
  # default events:
  start   = events[:start] || { default: Start.new(:default) }
  _end    = events[:end]   || { default: End.new(:default) }

  events = { start: start, end: _end }.merge(events)

  evts = Events(events)
  circuit = Circuit(name, evts, _end.values, &block)

  Activity.new(circuit, evts)
end

.ActivityInspect(activity, strip: ["AlterTest::"]) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/trailblazer/circuit/testing.rb', line 20

def self.ActivityInspect(activity, strip: ["AlterTest::"])
  strip += ["Trailblazer::Circuit::"]
  stripped = ->(target) { strip_for(target, strip) }

  map, _ = activity.circuit.to_fields

  content = map.collect do |task, connections|
    bla =
    connections.collect do |direction, target|
      target_str = target.kind_of?(End) ? EndInspect(target) : stripped.(target)
      "#{stripped.(direction)}=>#{target_str}"
    end.join(", ")
    task_str = task.kind_of?(End) ? EndInspect(task) : stripped.(task)
    "#{task_str}=>{#{bla}}"
  end.join(", ")
  "{#{content}}"
end

.Circuit(name = :default, events, end_events) ⇒ Object



33
34
35
# File 'lib/trailblazer/circuit/activity.rb', line 33

def self.Circuit(name=:default, events, end_events)
  Circuit.new(yield(events), end_events, name)
end

.EndInspect(event) ⇒ Object



16
17
18
# File 'lib/trailblazer/circuit/testing.rb', line 16

def self.EndInspect(event)
  event.instance_eval { "#<#{self.class.to_s.split("::").last}: #{@name} #{@options}>" }
end

.Events(events) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/trailblazer/circuit/activity.rb', line 39

def self.Events(events)
  evts = Struct.new(*events.keys) do # [Start, End, Resume]
    def [](event, name=:default)
      cfg = super(event.downcase)
      cfg[name.to_sym] or raise "[Circuit] Event `#{event}.#{name} unknown."
      # DISCUSS: the event type's events should also be a Struct to avoid :symbol vs. string.
    end
  end

  evts.new(*events.values)
end

.strip_for(target, strings) ⇒ Object



38
39
40
41
# File 'lib/trailblazer/circuit/testing.rb', line 38

def self.strip_for(target, strings)
  strings.each { |stripped| target = target.to_s.gsub(stripped, "") }
  target
end

Instance Method Details

#call(activity, options, flow_options = {}, *args) ⇒ Object

Runs the circuit. Stops when hitting a End event or subclass thereof. This method throws exceptions when the return value of a task doesn’t match any wiring.

Parameters:

  • activity

    A task from the circuit where to start

  • args

    An array of options passed to the first task.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/trailblazer/circuit.rb', line 32

def call(activity, options, flow_options={}, *args)
  direction = nil
  runner    = flow_options[:runner] || Run

  loop do
    direction, options, flow_options = runner.( activity, direction, options, flow_options, *args )

    # Stop execution of the circuit when we hit a stop event (< End). This could be an activity's End or Suspend.
    return [ direction, options, flow_options ] if @stop_events.include?(activity)

    activity = next_for(activity, direction) do |next_activity, in_map|
      activity_name = @name[activity] || activity # TODO: this must be implemented only once, somewhere.
      raise IllegalInputError.new("#{@name[:id]} #{activity_name}") unless in_map
      raise IllegalOutputSignalError.new("from #{@name[:id]}: `#{activity_name}`===>[ #{direction.inspect} ]") unless next_activity
    end
  end
end

#to_fieldsObject

Returns the circuit’s components.



51
52
53
# File 'lib/trailblazer/circuit.rb', line 51

def to_fields
  [ @map, @stop_events, @name]
end