oflow 0.6.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -41
- data/lib/oflow.rb +2 -3
- data/lib/oflow/actor.rb +3 -0
- data/lib/oflow/actors/httpserver.rb +3 -1
- data/lib/oflow/actors/log.rb +3 -2
- data/lib/oflow/actors/persister.rb +29 -6
- data/lib/oflow/actors/timer.rb +29 -12
- data/lib/oflow/box.rb +2 -2
- data/lib/oflow/env.rb +221 -15
- data/lib/oflow/flow.rb +217 -37
- data/lib/oflow/graffle.rb +293 -0
- data/lib/oflow/haserrorhandler.rb +3 -22
- data/lib/oflow/haslog.rb +21 -15
- data/lib/oflow/inspector.rb +18 -17
- data/lib/oflow/link.rb +11 -6
- data/lib/oflow/task.rb +134 -22
- data/lib/oflow/test/actorwrap.rb +1 -1
- data/lib/oflow/version.rb +1 -1
- data/test/actors/balancer_test.rb +17 -12
- data/test/actors/httpserver_test.rb +11 -10
- data/test/actors/log_test.rb +3 -6
- data/test/actors/merger_test.rb +23 -18
- data/test/actors/persister_test.rb +6 -8
- data/test/actors/timer_test.rb +63 -35
- data/test/actorwrap_test.rb +2 -6
- data/test/all_tests.rb +3 -7
- data/test/box_test.rb +4 -10
- data/test/flow_basic_test.rb +24 -22
- data/test/flow_cfg_error_test.rb +17 -13
- data/test/flow_linked_test.rb +146 -0
- data/test/flow_log_test.rb +43 -29
- data/test/flow_rescue_test.rb +41 -27
- data/test/flow_tracker_test.rb +26 -30
- data/test/helper.rb +15 -0
- data/test/task_test.rb +3 -7
- data/test/tracker_test.rb +3 -11
- metadata +5 -7
- data/lib/oflow/haslinks.rb +0 -68
- data/lib/oflow/hasname.rb +0 -31
- data/lib/oflow/hastasks.rb +0 -214
- data/test/flow_nest_test.rb +0 -215
@@ -7,25 +7,6 @@ module OFlow
|
|
7
7
|
# the next Flow until an error handler is found.
|
8
8
|
module HasErrorHandler
|
9
9
|
|
10
|
-
# Returns an error handler Task by checking for an @error_handler variable,
|
11
|
-
# then looking for a Task with a base name of :error in itself or any of the
|
12
|
-
# containing Flows.
|
13
|
-
# @return [Task|nil] Task to handle errors
|
14
|
-
def error_handler()
|
15
|
-
return @error_handler if instance_variable_defined?(:@error_handler) && !@error_handler.nil?
|
16
|
-
if instance_variable_defined?(:@flow)
|
17
|
-
if @flow.respond_to?(:find_task)
|
18
|
-
eh = @flow.find_task(:error)
|
19
|
-
return eh unless eh.nil?
|
20
|
-
end
|
21
|
-
if @flow.respond_to?(:error_handler)
|
22
|
-
eh = @flow.error_handler()
|
23
|
-
return eh unless eh.nil?
|
24
|
-
end
|
25
|
-
end
|
26
|
-
nil
|
27
|
-
end
|
28
|
-
|
29
10
|
# Sets avaliable for handling errors.
|
30
11
|
# @param t [Task|nil] Task for handling error or nil to unset
|
31
12
|
def error_handler=(t)
|
@@ -36,11 +17,11 @@ module OFlow
|
|
36
17
|
# @param e [Exception] error to handle
|
37
18
|
def handle_error(e)
|
38
19
|
handler = error_handler()
|
39
|
-
|
40
|
-
handler.receive(nil, Box.new([e, full_name()]))
|
41
|
-
else
|
20
|
+
if handler.nil?
|
42
21
|
puts "** [#{full_name()}] #{e.class}: #{e.message}"
|
43
22
|
e.backtrace.each { |line| puts " #{line}" }
|
23
|
+
else
|
24
|
+
handler.receive(nil, Box.new([e, full_name()]))
|
44
25
|
end
|
45
26
|
end
|
46
27
|
|
data/lib/oflow/haslog.rb
CHANGED
@@ -4,26 +4,12 @@ module OFlow
|
|
4
4
|
# Adds the ability to log by sending log requests to a log Task.
|
5
5
|
module HasLog
|
6
6
|
|
7
|
-
# Returns a log Task by looking for that Task in an attribute and then in
|
8
|
-
# the contained Tasks or Tasks in outer Flows.
|
9
|
-
# @return [Task] log Task.
|
10
|
-
def log()
|
11
|
-
return @log if instance_variable_defined?(:@log) && !@log.nil?
|
12
|
-
# Log task take precedence over log variable.
|
13
|
-
if respond_to?(:find_task)
|
14
|
-
lg = find_task(:log)
|
15
|
-
return lg unless lg.nil?
|
16
|
-
end
|
17
|
-
return @flow.log if instance_variable_defined?(:@flow) && @flow.respond_to?(:log)
|
18
|
-
nil
|
19
|
-
end
|
20
|
-
|
21
7
|
# Sets the log attribute.
|
22
8
|
# @param t [Task] log Task
|
23
9
|
def log=(t)
|
24
10
|
@log = t
|
25
11
|
end
|
26
|
-
|
12
|
+
|
27
13
|
# Lower level logging method. Generally only used when one of the primary
|
28
14
|
# severity methods are called.
|
29
15
|
# @param level [String] message severity or level
|
@@ -45,6 +31,26 @@ module OFlow
|
|
45
31
|
end
|
46
32
|
end
|
47
33
|
|
34
|
+
# @return true if errors would be logged.
|
35
|
+
def error?()
|
36
|
+
Env.log_level <= Logger::Severity::ERROR
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return true if warn messages would be logged.
|
40
|
+
def warn?()
|
41
|
+
Env.log_level <= Logger::Severity::WARN
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return true if info messages would be logged.
|
45
|
+
def info?()
|
46
|
+
Env.log_level <= Logger::Severity::INFO
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return true if debug messages would be logged.
|
50
|
+
def debug?()
|
51
|
+
Env.log_level <= Logger::Severity::DEBUG
|
52
|
+
end
|
53
|
+
|
48
54
|
# Logs the message if logging level is at least debug.
|
49
55
|
# @param msg [String] message to log
|
50
56
|
def debug(msg)
|
data/lib/oflow/inspector.rb
CHANGED
@@ -6,8 +6,9 @@ module OFlow
|
|
6
6
|
class Inspector < ::OTerm::Executor
|
7
7
|
attr_reader :running
|
8
8
|
|
9
|
-
def initialize(port=6060)
|
9
|
+
def initialize(env, port=6060)
|
10
10
|
super()
|
11
|
+
@env = env
|
11
12
|
@running = true
|
12
13
|
|
13
14
|
register('busy', self, :busy, 'returns the busy state of the system.', nil)
|
@@ -44,7 +45,7 @@ available for sorting on name, activity, or queue size.|)
|
|
44
45
|
def shutdown(listener, args)
|
45
46
|
super
|
46
47
|
@running = false
|
47
|
-
|
48
|
+
@env.shutdown()
|
48
49
|
end
|
49
50
|
|
50
51
|
def greeting()
|
@@ -56,7 +57,7 @@ available for sorting on name, activity, or queue size.|)
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def busy(listener, args)
|
59
|
-
if
|
60
|
+
if @env.busy?()
|
60
61
|
listener.out.pl("One or more Tasks is busy.")
|
61
62
|
else
|
62
63
|
listener.out.pl("All Tasks are idle.")
|
@@ -64,14 +65,14 @@ available for sorting on name, activity, or queue size.|)
|
|
64
65
|
end
|
65
66
|
|
66
67
|
def flows(listener, args)
|
67
|
-
|
68
|
+
@env.each_task() do |t|
|
68
69
|
listener.out.pl(t.full_name)
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
72
73
|
def list(listener, args)
|
73
74
|
if nil == args
|
74
|
-
|
75
|
+
@env.each_task() do |task|
|
75
76
|
listener.out.pl(task.full_name)
|
76
77
|
end
|
77
78
|
return
|
@@ -81,7 +82,7 @@ available for sorting on name, activity, or queue size.|)
|
|
81
82
|
if id.nil?
|
82
83
|
flow = Env
|
83
84
|
else
|
84
|
-
flow =
|
85
|
+
flow = @env.locate(id)
|
85
86
|
end
|
86
87
|
if flow.nil?
|
87
88
|
listener.out.pl("--- No Flow or Task found for #{id}")
|
@@ -100,7 +101,7 @@ available for sorting on name, activity, or queue size.|)
|
|
100
101
|
detail, id, ok = _parse_opt_id_args(args, 'v', listener)
|
101
102
|
return unless ok
|
102
103
|
|
103
|
-
task =
|
104
|
+
task = @env.locate(id)
|
104
105
|
if task.nil?
|
105
106
|
listener.out.pl("--- Failed to find '#{id}'")
|
106
107
|
return
|
@@ -110,11 +111,11 @@ available for sorting on name, activity, or queue size.|)
|
|
110
111
|
|
111
112
|
def start(listener, args)
|
112
113
|
if nil == args || 0 == args.size()
|
113
|
-
|
114
|
+
@env.start()
|
114
115
|
listener.out.pl("All Tasks restarted")
|
115
116
|
else
|
116
117
|
args.strip!
|
117
|
-
task =
|
118
|
+
task = @env.locate(args)
|
118
119
|
if task.nil?
|
119
120
|
listener.out.pl("--- Failed to find '#{args}'")
|
120
121
|
else
|
@@ -125,7 +126,7 @@ available for sorting on name, activity, or queue size.|)
|
|
125
126
|
end
|
126
127
|
|
127
128
|
def step(listener, args)
|
128
|
-
lg =
|
129
|
+
lg = @env.log()
|
129
130
|
stop_after = false
|
130
131
|
if !lg.nil? && Task::STOPPED == lg.state
|
131
132
|
lg.start()
|
@@ -136,7 +137,7 @@ available for sorting on name, activity, or queue size.|)
|
|
136
137
|
task = Env
|
137
138
|
else
|
138
139
|
args.strip!
|
139
|
-
task =
|
140
|
+
task = @env.locate(args)
|
140
141
|
end
|
141
142
|
if task.nil?
|
142
143
|
listener.out.pl("--- Failed to find '#{args}'")
|
@@ -153,11 +154,11 @@ available for sorting on name, activity, or queue size.|)
|
|
153
154
|
|
154
155
|
def stop(listener, args)
|
155
156
|
if nil == args || 0 == args.size()
|
156
|
-
|
157
|
+
@env.stop()
|
157
158
|
listener.out.pl("All Tasks stopped(paused)")
|
158
159
|
else
|
159
160
|
args.strip!
|
160
|
-
task =
|
161
|
+
task = @env.locate(args)
|
161
162
|
if task.nil?
|
162
163
|
listener.out.pl("--- Failed to find '#{args}'")
|
163
164
|
else
|
@@ -168,7 +169,7 @@ available for sorting on name, activity, or queue size.|)
|
|
168
169
|
end
|
169
170
|
|
170
171
|
def verbosity(listener, args)
|
171
|
-
lg =
|
172
|
+
lg = @env.log
|
172
173
|
if lg.nil?
|
173
174
|
listener.out.pl("--- No logger")
|
174
175
|
return
|
@@ -188,10 +189,10 @@ available for sorting on name, activity, or queue size.|)
|
|
188
189
|
def watch(listener, args)
|
189
190
|
tasks = []
|
190
191
|
if args.nil? || 0 == args.size()
|
191
|
-
|
192
|
+
@env.walk_tasks() { |t| tasks << t }
|
192
193
|
else
|
193
194
|
args.strip!
|
194
|
-
task =
|
195
|
+
task = @env.locate(args)
|
195
196
|
if task.nil?
|
196
197
|
listener.out.pl("--- Failed to find '#{args}'")
|
197
198
|
return
|
@@ -388,7 +389,7 @@ available for sorting on name, activity, or queue size.|)
|
|
388
389
|
names = ['fatal', 'error', 'warn', 'info', 'debug'].select { |s| s.start_with?(last.downcase()) }
|
389
390
|
else # expect id or options
|
390
391
|
with_colon = ':' == last[0]
|
391
|
-
|
392
|
+
@env.walk_tasks(false) do |t|
|
392
393
|
fn = t.full_name
|
393
394
|
fn = fn[1..-1] unless with_colon
|
394
395
|
names << fn if fn.start_with?(last)
|
data/lib/oflow/link.rb
CHANGED
@@ -7,24 +7,25 @@ module OFlow
|
|
7
7
|
|
8
8
|
# Name of the target.
|
9
9
|
attr_reader :target_name
|
10
|
+
# Name of the target's parent flow.
|
11
|
+
attr_reader :flow_name
|
10
12
|
# Operation to provide the target.
|
11
13
|
attr_reader :op
|
12
|
-
# The actual target Task
|
14
|
+
# The actual target Task.
|
13
15
|
attr_reader :target
|
14
|
-
# Flag indicating the Link is from a Flow to a Task contained in the Flow.
|
15
|
-
attr_reader :ingress
|
16
16
|
|
17
17
|
# Creates a new Link. This is called from link() and route() methods on
|
18
18
|
# Tasks and Flows.
|
19
|
+
# @param flow_name [Symbol|String] parent flow name to find the target task in or nil for this parent
|
19
20
|
# @param target_name [Symbol] target Task base name
|
20
21
|
# @param op [Symbol] operation to use on the target
|
21
22
|
# @param ingress [true|false] indicates the Link is internal
|
22
23
|
# @return [Link] new Link
|
23
|
-
def initialize(target_name, op
|
24
|
+
def initialize(flow_name, target_name, op)
|
24
25
|
@target_name = target_name
|
26
|
+
@flow_name = flow_name
|
25
27
|
@op = op
|
26
28
|
@target = nil
|
27
|
-
@ingress = ingress
|
28
29
|
end
|
29
30
|
|
30
31
|
# Delivers a package (Box) to the target.
|
@@ -35,7 +36,11 @@ module OFlow
|
|
35
36
|
|
36
37
|
# Returns a string representation of the Link.
|
37
38
|
def to_s()
|
38
|
-
|
39
|
+
if @flow_name.nil?
|
40
|
+
"Link{target_name: #{@target_name}, op: #{op}, target: #{@target}}"
|
41
|
+
else
|
42
|
+
"Link{target_name: #{@flow_name}:#{@target_name}, op: #{op}, target: #{@target}}"
|
43
|
+
end
|
39
44
|
end
|
40
45
|
alias inspect to_s
|
41
46
|
|
data/lib/oflow/task.rb
CHANGED
@@ -6,11 +6,17 @@ module OFlow
|
|
6
6
|
# data by the receive() method. The request is put on a queue and popped off
|
7
7
|
# one at a time and handed to an Actor associatesd with the Task.
|
8
8
|
class Task
|
9
|
-
|
10
|
-
include HasLinks
|
9
|
+
|
11
10
|
include HasErrorHandler
|
12
11
|
include HasLog
|
13
12
|
|
13
|
+
# The name.
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
attr_accessor :bounds
|
17
|
+
attr_accessor :shape
|
18
|
+
attr_accessor :color
|
19
|
+
|
14
20
|
# value of @state that indicates the Task is being created.
|
15
21
|
STARTING = 0
|
16
22
|
# value of @state that indicates the Task is not currently processing requests
|
@@ -36,7 +42,12 @@ module OFlow
|
|
36
42
|
# @param actor_class [Class] _class Class of the Actor to create
|
37
43
|
# @param options [Hash] additional options for the Task or Actor
|
38
44
|
def initialize(flow, name, actor_class, options={})
|
45
|
+
@flow = flow
|
46
|
+
@name = name.to_sym
|
39
47
|
@state = STARTING
|
48
|
+
@bounds = nil # [x, y, w, h] as fixnums
|
49
|
+
@color = nil # [r, g, b] as floats
|
50
|
+
@shape = nil # Rectangle is the default
|
40
51
|
@queue = []
|
41
52
|
@req_mutex = Mutex.new()
|
42
53
|
@req_thread = nil
|
@@ -47,9 +58,10 @@ module OFlow
|
|
47
58
|
@current_req = nil
|
48
59
|
@proc_cnt = 0
|
49
60
|
@loop = nil
|
61
|
+
@links = {}
|
62
|
+
@log = nil
|
63
|
+
@error_handler = nil
|
50
64
|
|
51
|
-
init_name(flow, name)
|
52
|
-
init_links()
|
53
65
|
set_options(options)
|
54
66
|
|
55
67
|
info("Creating actor #{actor_class} with options #{options}.")
|
@@ -57,6 +69,7 @@ module OFlow
|
|
57
69
|
raise Exception.new("#{actor} does not respond to the perform() method.") unless @actor.respond_to?(:perform)
|
58
70
|
|
59
71
|
@state = options.fetch(:state, RUNNING)
|
72
|
+
|
60
73
|
return unless @actor.with_own_thread()
|
61
74
|
|
62
75
|
@loop = Thread.start(self) do |me|
|
@@ -77,7 +90,11 @@ module OFlow
|
|
77
90
|
|
78
91
|
@current_req = req
|
79
92
|
begin
|
80
|
-
|
93
|
+
if debug?
|
94
|
+
debug("perform(#{req.op}, #{req.box.nil? ? '<nil>' : req.box})")
|
95
|
+
else
|
96
|
+
info("perform(#{req.op})")
|
97
|
+
end
|
81
98
|
@actor.perform(req.op, req.box) unless req.nil?
|
82
99
|
rescue Exception => e
|
83
100
|
handle_error(e)
|
@@ -100,17 +117,63 @@ module OFlow
|
|
100
117
|
end
|
101
118
|
end
|
102
119
|
|
120
|
+
# Creates a Link identified by the label that has a target Task and
|
121
|
+
# operation.
|
122
|
+
|
123
|
+
# @param label [Symbol|String] identifer of the Link
|
124
|
+
# @param target [Symbol|String] identifer of the target Task
|
125
|
+
# @param op [Symbol|String] operation to perform on the target Task
|
126
|
+
# @param flow_name [Symbol|String] parent flow name to find the target task in or nil for this parent
|
127
|
+
def link(label, target, op, flow_name=nil)
|
128
|
+
label = label.to_sym unless label.nil?
|
129
|
+
op = op.to_sym unless op.nil?
|
130
|
+
flow_name = flow_name.to_sym unless flow_name.nil?
|
131
|
+
raise ConfigError.new("Link #{label} already exists.") unless @links[label].nil?
|
132
|
+
@links[label] = Link.new(flow_name, target.to_sym, op)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Similar to a full file path. The full_name described the containment of
|
136
|
+
# the named item.
|
137
|
+
# @return [String] full name of item
|
138
|
+
def full_name()
|
139
|
+
if @flow.nil?
|
140
|
+
':' + @name.to_s
|
141
|
+
else
|
142
|
+
@flow.full_name() + ':' + @name.to_s
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns a log Task by looking for that Task as an attribute and then in
|
147
|
+
# the parent Flow.
|
148
|
+
# @return [Task] log Task.
|
149
|
+
def log()
|
150
|
+
return @log unless @log.nil?
|
151
|
+
@flow.log()
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns an error handler Task by looking for that Task as an attribute and then in
|
155
|
+
# the parent Flow.
|
156
|
+
# @return [Task] error handler Task.
|
157
|
+
def error_handler()
|
158
|
+
return @error_handler unless @error_handler.nil?
|
159
|
+
@flow.error_handler()
|
160
|
+
end
|
161
|
+
|
103
162
|
# Returns the state of the Task as a String.
|
104
163
|
# @return [String] String representation of the state
|
105
164
|
def state_string()
|
106
165
|
ss = 'UNKNOWN'
|
107
166
|
case @state
|
167
|
+
when STARTING
|
168
|
+
ss = 'STARTING'
|
108
169
|
when STOPPED
|
109
170
|
ss = 'STOPPED'
|
110
171
|
when RUNNING
|
111
172
|
ss = 'RUNNING'
|
112
173
|
when CLOSING
|
113
174
|
ss = 'CLOSING'
|
175
|
+
when BLOCKED
|
176
|
+
ss = 'BLOCKED'
|
114
177
|
when STEP
|
115
178
|
ss = 'STEP'
|
116
179
|
end
|
@@ -124,7 +187,11 @@ module OFlow
|
|
124
187
|
i = ' ' * indent
|
125
188
|
lines = ["#{i}#{name} (#{actor.class}) {"]
|
126
189
|
@links.each { |local,link|
|
127
|
-
|
190
|
+
if link.flow_name.nil?
|
191
|
+
lines << " #{i}#{local} => :#{link.target_name}:#{link.op}"
|
192
|
+
else
|
193
|
+
lines << " #{i}#{local} => #{link.flow_name}:#{link.target_name}:#{link.op}"
|
194
|
+
end
|
128
195
|
}
|
129
196
|
if 1 <= detail
|
130
197
|
lines << " #{i}queued: #{queue_count()} (#{busy? ? 'busy' : 'idle'})"
|
@@ -281,8 +348,11 @@ module OFlow
|
|
281
348
|
# @param op [Symbol] operation to perform
|
282
349
|
# @param box [Box] contents or data for the request
|
283
350
|
def receive(op, box)
|
284
|
-
|
285
|
-
|
351
|
+
if debug?
|
352
|
+
debug("receive(#{op}, #{box.nil? ? '<nil>' : box}) #{state_string}")
|
353
|
+
else
|
354
|
+
info("receive(#{op})")
|
355
|
+
end
|
286
356
|
return if CLOSING == @state
|
287
357
|
|
288
358
|
raise BlockedError.new() if BLOCKED == @state
|
@@ -317,7 +387,11 @@ module OFlow
|
|
317
387
|
box.freeze() unless box.nil?
|
318
388
|
link = resolve_link(dest)
|
319
389
|
raise LinkError.new(dest) if link.nil? || link.target.nil?
|
320
|
-
|
390
|
+
if debug?
|
391
|
+
debug("shipping #{box} to #{link.target_name}:#{link.op}")
|
392
|
+
else
|
393
|
+
info("shipping to #{link.target_name}:#{link.op}")
|
394
|
+
end
|
321
395
|
link.target.receive(link.op, box)
|
322
396
|
link
|
323
397
|
end
|
@@ -333,6 +407,17 @@ module OFlow
|
|
333
407
|
@req_timeout = options.fetch(:request_timeout, @req_timeout).to_f
|
334
408
|
end
|
335
409
|
|
410
|
+
def set_option(key, value)
|
411
|
+
case key.to_sym()
|
412
|
+
when :max_queue_count
|
413
|
+
@max_queue_count = value.to_i
|
414
|
+
when :request_timeout
|
415
|
+
@req_timeout = value.to_f
|
416
|
+
else
|
417
|
+
@actor.set_option(key, value)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
336
421
|
def _validation_errors()
|
337
422
|
errors = []
|
338
423
|
@links.each_value { |lnk| _check_link(lnk, errors) }
|
@@ -377,6 +462,46 @@ module OFlow
|
|
377
462
|
}
|
378
463
|
end
|
379
464
|
|
465
|
+
# Attempts to find and resolve the Link identified by the label. Resolving a
|
466
|
+
# Link uses the target identifier to find the target Task and save that in
|
467
|
+
# the Link.
|
468
|
+
# @param label [Symbol|String] identifer of the Link
|
469
|
+
# @return [Link] returns the Link for the label
|
470
|
+
def resolve_link(label)
|
471
|
+
label = label.to_sym unless label.nil?
|
472
|
+
lnk = @links[label] || @links[nil]
|
473
|
+
return nil if lnk.nil?
|
474
|
+
set_link_target(lnk) if lnk.target.nil?
|
475
|
+
lnk
|
476
|
+
end
|
477
|
+
|
478
|
+
# Sets the target Task for a Link.
|
479
|
+
# @param lnk [Link] Link to find the target Task for.
|
480
|
+
def set_link_target(lnk)
|
481
|
+
f = @flow
|
482
|
+
f = @flow.env.find_flow(lnk.flow_name) unless lnk.flow_name.nil?
|
483
|
+
raise ConfigError.new("Flow '#{lnk.flow_name}' not found.") if f.nil?
|
484
|
+
lnk.instance_variable_set(:@target, f.find_task(lnk.target_name))
|
485
|
+
end
|
486
|
+
|
487
|
+
# Attempts to find the Link identified by the label.
|
488
|
+
# @param label [Symbol|String] identifer of the Link
|
489
|
+
# @return [Link] returns the Link for the label
|
490
|
+
def find_link(label)
|
491
|
+
label = label.to_sym unless label.nil?
|
492
|
+
@links[label] || @links[nil]
|
493
|
+
end
|
494
|
+
|
495
|
+
# Returns the Links.
|
496
|
+
# @return [Hash] Hash of Links with the keys as Symbols that are the labels of the Links.
|
497
|
+
def links()
|
498
|
+
@links
|
499
|
+
end
|
500
|
+
|
501
|
+
def has_links?()
|
502
|
+
!@links.nil? && !@links.empty?
|
503
|
+
end
|
504
|
+
|
380
505
|
private
|
381
506
|
|
382
507
|
# Internal class used to store information about asynchronous method
|
@@ -404,18 +529,5 @@ module OFlow
|
|
404
529
|
|
405
530
|
end # Request
|
406
531
|
|
407
|
-
class Link
|
408
|
-
attr_reader :name
|
409
|
-
attr_reader :task
|
410
|
-
attr_reader :op
|
411
|
-
|
412
|
-
def initialize(name, task, op)
|
413
|
-
@name = name
|
414
|
-
@task = task
|
415
|
-
@op = op
|
416
|
-
end
|
417
|
-
|
418
|
-
end # Link
|
419
|
-
|
420
532
|
end # Task
|
421
533
|
end # OFlow
|