Class: Roast::Workflow

Inherits:
Object
  • Object
show all
Defined in:
lib/roast/workflow.rb

Defined Under Namespace

Classes: InvalidLoadableReference, WorkflowAlreadyPreparedError, WorkflowAlreadyStartedError, WorkflowError, WorkflowNotPreparedError

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(workflow_path, workflow_context) ⇒ Workflow

: (String | Pathname, WorkflowContext) -> void



34
35
36
37
38
39
40
41
42
43
# File 'lib/roast/workflow.rb', line 34

def initialize(workflow_path, workflow_context)
  @workflow_path = Pathname.new(workflow_path) #: Pathname
  @workflow_context = workflow_context #: WorkflowContext
  @workflow_definition = File.read(workflow_path) #: String
  @cog_registry = Cog::Registry.new #: Cog::Registry
  @config_procs = [] #: Array[^() -> void]
  @execution_procs = { nil: [] } #: Hash[Symbol?, Array[^() -> void]]
  @config_manager = nil #: ConfigManager?
  @execution_manager = nil #: ExecutionManager?
end

Class Method Details

.from_file(workflow_path, params) ⇒ Object

: (String | Pathname, WorkflowParams) -> void



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/roast/workflow.rb', line 18

def from_file(workflow_path, params)
  Sync do
    Dir.mktmpdir("roast-") do |tmpdir|
      EventMonitor.start!
      workflow_dir = Pathname.new(workflow_path).dirname
      workflow_context = WorkflowContext.new(params: params, tmpdir: tmpdir, workflow_dir: workflow_dir)
      workflow = new(workflow_path, workflow_context)
      workflow.prepare!
      workflow.start!
      EventMonitor.stop!
    end
  end
end

Instance Method Details

#completed?Boolean

: () -> bool

Returns:

  • (Boolean)


91
92
93
# File 'lib/roast/workflow.rb', line 91

def completed?
  @completed ||= false
end

#config(&block) ⇒ Object

: { () [self: Roast::ConfigContext] -> void } -> void



96
97
98
# File 'lib/roast/workflow.rb', line 96

def config(&block)
  @config_procs << block
end

#execute(scope = nil, &block) ⇒ Object

: (?Symbol?) { () [self: Roast::ExecutionContext] -> void } -> void



101
102
103
# File 'lib/roast/workflow.rb', line 101

def execute(scope = nil, &block)
  (@execution_procs[scope] ||= []) << block
end

#prepare!Object

: () -> void



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/roast/workflow.rb', line 46

def prepare!
  raise WorkflowAlreadyPreparedError if preparing? || prepared?

  @preparing = true
  extract_dsl_procs!
  @config_manager = ConfigManager.new(@cog_registry, @config_procs)
  @config_manager.not_nil!.prepare!
  # TODO: probably we should just not pass the params as the top-level scope value anymore
  @execution_manager = ExecutionManager.new(@cog_registry, @config_manager.not_nil!, @execution_procs, @workflow_context, scope_value: @workflow_context.params)
  @execution_manager.not_nil!.prepare!

  @prepared = true
end

#prepared?Boolean

: () -> bool

Returns:

  • (Boolean)


81
82
83
# File 'lib/roast/workflow.rb', line 81

def prepared?
  @prepared ||= false
end

#preparing?Boolean

: () -> bool

Returns:

  • (Boolean)


76
77
78
# File 'lib/roast/workflow.rb', line 76

def preparing?
  @preparing ||= false
end

#start!Object

: () -> void



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/roast/workflow.rb', line 61

def start!
  raise WorkflowNotPreparedError unless @config_manager.present? && @execution_manager.present?
  raise WorkflowAlreadyStartedError if started? || completed?

  @started = true
  begin
    @execution_manager.run!
  rescue ControlFlow::Break
    # treat `break!` like `next!` in the top-level executor scope
    # TODO: maybe do something with the message passed to break!
  end
  @completed = true
end

#started?Boolean

: () -> bool

Returns:

  • (Boolean)


86
87
88
# File 'lib/roast/workflow.rb', line 86

def started?
  @started ||= false
end

#use(*loadables, from: nil) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/roast/workflow.rb', line 105

def use(*loadables, from: nil)
  if from
    # Load gem - no special requires, gem must handle everything
    require from
  else
    # Load from local path
    loadables.each do |cog_name|
      require @workflow_path.realdirpath.dirname.join("cogs/#{cog_name}").to_s
    end
  end
  loadables.each do |name|
    class_name_string = name.camelize
    raise InvalidLoadableReference, "#{name} class not found" unless Object.const_defined?(class_name_string)

    class_name = class_name_string.constantize # rubocop:disable Sorbet/ConstantsFromStrings
    if class_name < Roast::Cog
      @cog_registry.use(class_name)
    else
      raise InvalidLoadableReference, "#{class_name_string} is not a subclass of a usable Roast primitive (cog, provider)."
    end
  end
end