Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions dsl/step_communication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# typed: false
# frozen_string_literal: true

# How do we pass information between steps?
# Demonstrate by passing result of a command output to another step

config do
cmd(:echo) { display! }
end

execute do
cmd(:ls) { "ls -al" }
cmd(:echo) do
# TODO: this is a bespoke output object for cmd, is there a generic one we can offer
first_line = cmd(:ls).command_output.split("\n").second
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i love this!

"echo '#{first_line}'"
end
end
27 changes: 17 additions & 10 deletions lib/roast/dsl/cog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
module Roast
module DSL
class Cog
class CogAlreadyRanError < StandardError; end

class << self
def on_create
eigen = self
proc do |instance_name = Random.uuid, &action|
#: self as Roast::DSL::ExecutionContext
add_cog_instance(instance_name, eigen.new(action))
#: self as Roast::DSL::WorkflowExecutionContext
add_cog_instance(instance_name, eigen.new(instance_name, action))
end
end

Expand Down Expand Up @@ -39,23 +41,28 @@ def find_child_config_or_default
end
end

attr_reader :output
attr_reader :name, :output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes pls


def initialize(cog_input_proc)
def initialize(name, cog_input_proc)
@name = name
@cog_input_proc = cog_input_proc
@finished = false
end

def input
@cog_input_proc.call
end
def run!(config, cog_execution_context)
raise CogAlreadyRanError if ran?

def run!(config)
@config = config
@output = execute
@output = execute(cog_execution_context.instance_exec(&@cog_input_proc))
@finished = true
end

def ran?
@finished
end

# Inheriting cog must implement this
def execute
def execute(input)
raise NotImplementedError
end
end
Expand Down
5 changes: 1 addition & 4 deletions lib/roast/dsl/cog/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ class Cog
class Store
class CogAlreadyDefinedError < Roast::Error; end

#: (Symbol) -> Roast::DSL::Cog?
def find(id)
store[id]
end
delegate :[], to: :store

#: (Symbol, Roast::DSL::Cog) -> Roast::DSL::Cog
def insert(id, inst)
Expand Down
29 changes: 29 additions & 0 deletions lib/roast/dsl/cog_execution_context.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# typed: true
# frozen_string_literal: true

module Roast
module DSL
# Contains the cogs already executed in this run.
class CogExecutionContext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be called something like CogInputContext, because the proc running in this context is just generating the input for the cog's actual work, which will be done by the cog itself not in a user's proc at all

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll drop a rename PR on top of this

# Raises if you access a cog in an execution block that hasn't already been run.
class IncompleteCogExecutionAccessError < StandardError; end

def initialize(cogs, bound_names)
@cogs = cogs
bind_cog_methods(bound_names)
end

private

def bind_cog_methods(bound_names)
bound_names.map do |name|
define_singleton_method(name.to_sym, ->(name) do
@cogs[name].tap do |cog|
raise IncompleteCogExecutionAccessError unless cog.ran?
end.output
end)
end
end
end
end
end
14 changes: 9 additions & 5 deletions lib/roast/dsl/cogs/cmd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Cogs
class Cmd < Cog
class Output
#: String?
attr_reader :output
attr_reader :command_output

#: String?
attr_reader :err
Expand All @@ -21,7 +21,7 @@ class Output
#| Process::Status? status
#| ) -> void
def initialize(output, error, status)
@output = output
@command_output = output
@err = error
@status = status
end
Expand All @@ -37,12 +37,16 @@ def print_all!
def print_all?
!!@values[:print_all]
end

def display!
print_all!
end
end

#: () -> Output
def execute
#: (String) -> Output
def execute(input)
result = Output.new(*Roast::Helpers::CmdRunner.capture3(input))
puts result.output if @config.print_all?
puts result.command_output if @config.print_all?
result
end
end
Expand Down
9 changes: 6 additions & 3 deletions lib/roast/dsl/executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def prepare!(input)

@config_context = ConfigContext.new(@cogs, @config_proc)
@config_context.prepare!
@execution_context = ExecutionContext.new(@cogs, @cog_stack, @execution_proc)
@execution_context = WorkflowExecutionContext.new(@cogs, @cog_stack, @execution_proc)
@execution_context.prepare!

@prepared = true
Expand All @@ -44,7 +44,10 @@ def start!
raise ExecutorAlreadyCompletedError if @completed

@cog_stack.map do |name, cog|
cog.run!(@config_context.fetch_merged_config(cog.class, name.to_sym))
cog.run!(
@config_context.fetch_merged_config(cog.class, name.to_sym),
@execution_context.cog_execution_context,
)
end

@completed = true
Expand All @@ -63,7 +66,7 @@ def config(&block)
@config_proc = block
end

#: { () [self: ExecutionContext] -> void} -> void
#: { () [self: WorkflowExecutionContext] -> void} -> void
def execute(&block)
@execution_proc = block
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,41 @@

module Roast
module DSL
class ExecutionContext
class WorkflowExecutionContext
def initialize(cogs, cog_stack, execution_proc)
@cogs = cogs
@cog_stack = cog_stack
@execution_proc = execution_proc
@bound_names = []
end

def prepare!
bind_default_cogs
instance_eval(&@execution_proc)
end

def cog_execution_context
@cog_execution_context ||= CogExecutionContext.new(@cogs, @bound_names)
end

private

def add_cog_instance(name, cog)
@cogs.insert(name, cog)
@cog_stack.push([name, cog])
end

def output(name)
@cogs[name].output
end

#: () -> void
def bind_default_cogs
bind_cog(Cogs::Cmd, :cmd)
end

def bind_cog(cog_class, name)
@bound_names << name
instance_eval do
define_singleton_method(name, &cog_class.on_create)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

module Roast
module DSL
class ExecutionContext
class WorkflowExecutionContext
#: (?Symbol?) {() [self: Roast::DSL::Cogs::Cmd] -> String} -> void
def cmd(name = nil, &block); end
end
Expand Down