Skip to content

Commit

Permalink
Merge pull request #23 from yogeshjain999/strategy-list
Browse files Browse the repository at this point in the history
Introduce Helper module for strategy extensions
  • Loading branch information
yogeshjain999 committed May 21, 2020
2 parents 4986cce + 2e32d56 commit 09b2e48
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 118 deletions.
2 changes: 1 addition & 1 deletion lib/trailblazer/activity/dsl/linear.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ def apply_adds_from_dsl(sequence, sequence_insert:, adds:, **options)

require "trailblazer/activity/dsl/linear/normalizer"
require "trailblazer/activity/dsl/linear/state"
require "trailblazer/activity/dsl/linear/helper"
require "trailblazer/activity/dsl/linear/strategy"
require "trailblazer/activity/dsl/linear/compiler"
require "trailblazer/activity/path"
require "trailblazer/activity/railway"
require "trailblazer/activity/fast_track"
require "trailblazer/activity/dsl/linear/helper" # FIXME
require "trailblazer/activity/dsl/linear/variable_mapping"
234 changes: 122 additions & 112 deletions lib/trailblazer/activity/dsl/linear/helper.rb
Original file line number Diff line number Diff line change
@@ -1,134 +1,144 @@
module Trailblazer
class Activity
module DSL::Linear # TODO: rename!
# @api private
OutputSemantic = Struct.new(:value)
Id = Struct.new(:value)
Track = Struct.new(:color, :adds)
Extension = Struct.new(:callable) do
def call(*args, &block)
callable.(*args, &block)
end
end

# Shortcut functions for the DSL.
module_function

# Output( Left, :failure )
# Output( :failure ) #=> Output::Semantic
def Output(signal, semantic=nil)
return OutputSemantic.new(signal) if semantic.nil?

Activity.Output(signal, semantic)
end

def End(semantic)
Activity.End(semantic)
end

def end_id(_end)
"End.#{_end.to_h[:semantic]}" # TODO: use everywhere
end

def Track(color)
Track.new(color, []).freeze
end

def Id(id)
Id.new(id).freeze
end

def Path(track_color: "track_#{rand}", end_id:"path_end_#{rand}", connect_to:nil, **options, &block)
# DISCUSS: here, we use the global normalizer and don't allow injection.
state = Activity::Path::DSL::State.new(Activity::Path::DSL.OptionsForState(track_name: track_color, end_id: end_id, **options)) # TODO: test injecting {:normalizers}.

# seq = block.call(state) # state changes.
state.instance_exec(&block)

seq = state.to_h[:sequence]

_end_id =
if connect_to
end_id
else
nil
module DSL
module Linear
module Helper
# @api private
OutputSemantic = Struct.new(:value)
Id = Struct.new(:value)
Track = Struct.new(:color, :adds)
Extension = Struct.new(:callable) do
def call(*args, &block)
callable.(*args, &block)
end
end

seq = strip_start_and_ends(seq, end_id: _end_id) # don't cut off end unless {:connect_to} is set.
def self.included(base)
base.extend ClassMethods
end

if connect_to
output, _ = seq[-1][2][0].(seq, seq[-1]) # FIXME: the Forward() proc contains the row's Output, and the only current way to retrieve it is calling the search strategy. It should be Forward#to_h
# Shortcut functions for the DSL.
module ClassMethods
# Output( Left, :failure )
# Output( :failure ) #=> Output::Semantic
def Output(signal, semantic=nil)
return OutputSemantic.new(signal) if semantic.nil?

searches = [Search.ById(output, connect_to.value)]
Activity.Output(signal, semantic)
end

row = seq[-1]
row = row[0..1] + [searches] + [row[3]] # FIXME: not mutating an array is so hard: we only want to replace the "searches" element, index 2
def End(semantic)
Activity.End(semantic)
end

seq = seq[0..-2] + [row]
end
def end_id(_end)
"End.#{_end.to_h[:semantic]}" # TODO: use everywhere
end

# Add the path before End.success - not sure this is bullet-proof.
adds = seq.collect do |row|
{
row: row,
insert: [Insert.method(:Prepend), "End.success"]
}
end
def Track(color)
Track.new(color, []).freeze
end

# Connect the Output() => Track(path_track)
return Track.new(track_color, adds)
end
def Id(id)
Id.new(id).freeze
end

# Computes the {:outputs} options for {activity}.
def Subprocess(activity, patch: {})
activity = Patch.customize(activity, options: patch)
def Path(track_color: "track_#{rand}", end_id:"path_end_#{rand}", connect_to:nil, **options, &block)
# DISCUSS: here, we use the global normalizer and don't allow injection.
state = Activity::Path::DSL::State.new(Activity::Path::DSL.OptionsForState(track_name: track_color, end_id: end_id, **options)) # TODO: test injecting {:normalizers}.

{
task: activity,
outputs: Hash[activity.to_h[:outputs].collect { |output| [output.semantic, output] }]
}
end
# seq = block.call(state) # state changes.
state.instance_exec(&block)

module Patch
module_function
seq = state.to_h[:sequence]

def customize(activity, options:)
options = options.is_a?(Proc) ?
{ [] => options } : # hash-wrapping with empty path, for patching given activity itself
options
_end_id =
if connect_to
end_id
else
nil
end

options.each do |path, patch|
activity = call(activity, path, patch) # TODO: test if multiple patches works!
end
seq = strip_start_and_ends(seq, end_id: _end_id) # don't cut off end unless {:connect_to} is set.

if connect_to
output, _ = seq[-1][2][0].(seq, seq[-1]) # FIXME: the Forward() proc contains the row's Output, and the only current way to retrieve it is calling the search strategy. It should be Forward#to_h

searches = [Search.ById(output, connect_to.value)]

activity
end
row = seq[-1]
row = row[0..1] + [searches] + [row[3]] # FIXME: not mutating an array is so hard: we only want to replace the "searches" element, index 2

def call(activity, path, customization)
task_id, *path = path
seq = seq[0..-2] + [row]
end

# Add the path before End.success - not sure this is bullet-proof.
adds = seq.collect do |row|
{
row: row,
insert: [Insert.method(:Prepend), "End.success"]
}
end

# Connect the Output() => Track(path_track)
return Track.new(track_color, adds)
end

patch =
if task_id
segment_activity = Introspect::Graph(activity).find(task_id).task
patched_segment_activity = call(segment_activity, path, customization)
# Computes the {:outputs} options for {activity}.
def Subprocess(activity, patch: {})
activity = Patch.customize(activity, options: patch)

# Replace the patched subprocess.
-> { step Subprocess(patched_segment_activity), replace: task_id, id: task_id }
else
customization # apply the *actual* patch from the Subprocess() call.
{
task: activity,
outputs: Hash[activity.to_h[:outputs].collect { |output| [output.semantic, output] }]
}
end

patched_activity = Class.new(activity)
patched_activity.class_exec(&patch)
patched_activity
end
end

def normalize(options, local_keys) # TODO: test me.
locals = options.reject { |key, value| ! local_keys.include?(key) }
foreign = options.reject { |key, value| local_keys.include?(key) }
return foreign, locals
end
end
end
module Patch
module_function

def customize(activity, options:)
options = options.is_a?(Proc) ?
{ [] => options } : # hash-wrapping with empty path, for patching given activity itself
options

options.each do |path, patch|
activity = call(activity, path, patch) # TODO: test if multiple patches works!
end

activity
end

def call(activity, path, customization)
task_id, *path = path

patch =
if task_id
segment_activity = Introspect::Graph(activity).find(task_id).task
patched_segment_activity = call(segment_activity, path, customization)

# Replace the patched subprocess.
-> { step Subprocess(patched_segment_activity), replace: task_id, id: task_id }
else
customization # apply the *actual* patch from the Subprocess() call.
end

patched_activity = Class.new(activity)
patched_activity.class_exec(&patch)
patched_activity
end
end

def normalize(options, local_keys) # TODO: test me.
locals = options.reject { |key, value| ! local_keys.include?(key) }
foreign = options.reject { |key, value| local_keys.include?(key) }
return foreign, locals
end
end
end # Helper

include Helper # Introduce Helper constants in DSL::Linear scope
end # Linear
end # DSL
end # Activity
end
5 changes: 0 additions & 5 deletions lib/trailblazer/activity/dsl/linear/strategy.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require "forwardable"

module Trailblazer
class Activity
module DSL
Expand Down Expand Up @@ -76,9 +74,6 @@ def self.task_for!(state, type, task, options={}, &block)
return args[0], options.merge(evaluated_options)
end

extend Forwardable
def_delegators Linear, :Output, :End, :Track, :Id, :Subprocess

def Path(options, &block) # syntactically, we can't access the {do ... end} block here.
BlockProxy.new(options, block)
end
Expand Down
1 change: 1 addition & 0 deletions lib/trailblazer/activity/fast_track.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class << self
end
end

include Activity::DSL::Linear::Helper
extend Activity::DSL::Linear::Strategy

initialize!(Railway::DSL::State.new(DSL.OptionsForState()))
Expand Down
1 change: 1 addition & 0 deletions lib/trailblazer/activity/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def step(*args)

end # DSL

include DSL::Linear::Helper
extend DSL::Linear::Strategy

initialize!(Path::DSL::State.new(DSL.OptionsForState()))
Expand Down
1 change: 1 addition & 0 deletions lib/trailblazer/activity/railway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class << self
end
end

include DSL::Linear::Helper
extend DSL::Linear::Strategy

initialize!(Railway::DSL::State.new(DSL.OptionsForState()))
Expand Down

0 comments on commit 09b2e48

Please sign in to comment.