tap 0.19.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +100 -45
- data/MIT-LICENSE +1 -1
- data/README +95 -51
- data/bin/tap +11 -57
- data/bin/tapexe +84 -0
- data/doc/API +91 -139
- data/doc/Configuration +93 -0
- data/doc/Examples/Command Line +10 -42
- data/doc/Examples/Tapfile +124 -0
- data/doc/Ruby to Ruby +87 -0
- data/doc/Workflow Syntax +185 -0
- data/lib/tap.rb +74 -5
- data/lib/tap/app.rb +217 -310
- data/lib/tap/app/api.rb +44 -23
- data/lib/tap/app/queue.rb +11 -12
- data/lib/tap/app/stack.rb +4 -4
- data/lib/tap/declarations.rb +200 -0
- data/lib/tap/declarations/context.rb +31 -0
- data/lib/tap/declarations/description.rb +33 -0
- data/lib/tap/env.rb +133 -779
- data/lib/tap/env/cache.rb +87 -0
- data/lib/tap/env/constant.rb +94 -39
- data/lib/tap/env/path.rb +71 -0
- data/lib/tap/join.rb +42 -78
- data/lib/tap/joins/gate.rb +85 -0
- data/lib/tap/joins/switch.rb +4 -2
- data/lib/tap/joins/sync.rb +3 -3
- data/lib/tap/middleware.rb +5 -5
- data/lib/tap/middlewares/debugger.rb +18 -58
- data/lib/tap/parser.rb +115 -183
- data/lib/tap/root.rb +162 -239
- data/lib/tap/signal.rb +72 -0
- data/lib/tap/signals.rb +20 -2
- data/lib/tap/signals/class_methods.rb +38 -43
- data/lib/tap/signals/configure.rb +19 -0
- data/lib/tap/signals/help.rb +5 -7
- data/lib/tap/signals/load.rb +49 -0
- data/lib/tap/signals/module_methods.rb +1 -0
- data/lib/tap/task.rb +46 -275
- data/lib/tap/tasks/dump.rb +21 -16
- data/lib/tap/tasks/list.rb +184 -0
- data/lib/tap/tasks/load.rb +4 -4
- data/lib/tap/tasks/prompt.rb +128 -0
- data/lib/tap/tasks/signal.rb +42 -0
- data/lib/tap/tasks/singleton.rb +35 -0
- data/lib/tap/tasks/stream.rb +64 -0
- data/lib/tap/utils.rb +83 -0
- data/lib/tap/version.rb +2 -2
- data/lib/tap/workflow.rb +124 -0
- data/tap.yml +0 -0
- metadata +59 -24
- data/cmd/console.rb +0 -43
- data/cmd/manifest.rb +0 -118
- data/cmd/run.rb +0 -145
- data/doc/Examples/Workflow +0 -40
- data/lib/tap/app/node.rb +0 -29
- data/lib/tap/env/context.rb +0 -61
- data/lib/tap/env/gems.rb +0 -63
- data/lib/tap/env/manifest.rb +0 -179
- data/lib/tap/env/minimap.rb +0 -308
- data/lib/tap/intern.rb +0 -50
- data/lib/tap/joins.rb +0 -9
- data/lib/tap/prompt.rb +0 -36
- data/lib/tap/root/utils.rb +0 -220
- data/lib/tap/root/versions.rb +0 -138
- data/lib/tap/signals/signal.rb +0 -68
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'tap/env/path'
|
2
|
+
|
3
|
+
autoload(:Gem, 'rubygems')
|
4
|
+
autoload(:RbConfig, 'rbconfig')
|
5
|
+
module Tap
|
6
|
+
class Env
|
7
|
+
class Cache
|
8
|
+
attr_reader :cache_home
|
9
|
+
|
10
|
+
def initialize(dir=Dir.pwd, debug=false)
|
11
|
+
@cache_home = File.expand_path("#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{RUBY_VERSION}", dir)
|
12
|
+
@debug = debug
|
13
|
+
end
|
14
|
+
|
15
|
+
def select(dependencies)
|
16
|
+
if dependencies.kind_of?(String)
|
17
|
+
dependencies = dependencies.split(':')
|
18
|
+
end
|
19
|
+
|
20
|
+
paths = []
|
21
|
+
dependencies.collect! do |dep|
|
22
|
+
dep.kind_of?(String) ? dep.split(',', 2) : dep
|
23
|
+
end.each do |(pattern, version_requirements)|
|
24
|
+
pattern = Regexp.new(pattern) if pattern.kind_of?(String)
|
25
|
+
paths.concat search(pattern, version_requirements)
|
26
|
+
end
|
27
|
+
|
28
|
+
paths.uniq!
|
29
|
+
paths
|
30
|
+
end
|
31
|
+
|
32
|
+
def search(pattern, version_requirements)
|
33
|
+
dependency = Gem::Dependency.new(pattern, version_requirements)
|
34
|
+
|
35
|
+
sources = {}
|
36
|
+
Gem.source_index.search(dependency).sort_by do |spec|
|
37
|
+
spec.version
|
38
|
+
end.reverse_each do |spec|
|
39
|
+
sources[spec.name] ||= spec
|
40
|
+
end
|
41
|
+
|
42
|
+
paths = []
|
43
|
+
sources.values.sort_by do |spec|
|
44
|
+
spec.name
|
45
|
+
end.each do |spec|
|
46
|
+
unless File.exists? File.expand_path(Path::FILE, spec.full_gem_path)
|
47
|
+
next
|
48
|
+
end
|
49
|
+
|
50
|
+
path = File.join(cache_home, spec.full_name)
|
51
|
+
gem_path = spec.full_gem_path
|
52
|
+
|
53
|
+
unless FileUtils.uptodate?(path, [gem_path, __FILE__])
|
54
|
+
unless File.exists?(cache_home)
|
55
|
+
FileUtils.mkdir_p(cache_home)
|
56
|
+
end
|
57
|
+
|
58
|
+
if @debug
|
59
|
+
$stderr.puts(App::LOG_FORMAT % [' ', nil, :generate, spec.full_name])
|
60
|
+
end
|
61
|
+
|
62
|
+
File.open(path, 'w') do |io|
|
63
|
+
io << generate(spec)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
paths << path
|
68
|
+
end
|
69
|
+
|
70
|
+
paths
|
71
|
+
end
|
72
|
+
|
73
|
+
def generate(spec)
|
74
|
+
lines = Env.generate(
|
75
|
+
:dir => spec.full_gem_path,
|
76
|
+
:pathfile => File.expand_path(Path::FILE, spec.full_gem_path),
|
77
|
+
:load_paths => false)
|
78
|
+
|
79
|
+
lines.unshift "# Generated for #{spec.full_name} on #{Time.now}. Do not edit."
|
80
|
+
lines << "activate #{spec.name} #{spec.version}"
|
81
|
+
lines.uniq!
|
82
|
+
lines.sort!
|
83
|
+
lines.join("\n")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/tap/env/constant.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tap/env/string_ext'
|
2
|
+
require 'tap/root'
|
2
3
|
|
3
4
|
module Tap
|
4
5
|
class Env
|
@@ -8,11 +9,11 @@ module Tap
|
|
8
9
|
# it doesn't exist, constantize requires require_path and tries again.
|
9
10
|
#
|
10
11
|
# Object.const_defined?(:Net) # => false
|
11
|
-
# $".
|
12
|
+
# $".grep(/net\/http.rb$/).empty? # => true
|
12
13
|
#
|
13
14
|
# http = Constant.new('Net::HTTP', 'net/http.rb')
|
14
15
|
# http.constantize # => Net::HTTP
|
15
|
-
# $".
|
16
|
+
# $".grep(/net\/http.rb$/).empty? # => false
|
16
17
|
#
|
17
18
|
# === Unloading
|
18
19
|
#
|
@@ -84,33 +85,39 @@ module Tap
|
|
84
85
|
const
|
85
86
|
end
|
86
87
|
|
87
|
-
# Scans the directory and pattern for constants
|
88
|
-
|
89
|
-
|
90
|
-
if pattern.include?("..")
|
91
|
-
raise "patterns cannot include relative paths: #{pattern.inspect}"
|
92
|
-
end
|
88
|
+
# Scans the directory and pattern for constants.
|
89
|
+
def scan(dir, pattern="**/*.rb")
|
90
|
+
constants = {}
|
93
91
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
Lazydoc::Document.scan(File.read(path)) do |const_name, type, summary|
|
103
|
-
const_name = default_const_name if const_name.empty?
|
104
|
-
|
105
|
-
constant = (constants[const_name] ||= Constant.new(const_name))
|
106
|
-
constant.register_as(type, summary)
|
107
|
-
constant.require_paths << path
|
92
|
+
root = Root.new(dir)
|
93
|
+
root.glob(pattern).each do |path|
|
94
|
+
Lazydoc::Document.scan(File.read(path)) do |const_name, type, summary|
|
95
|
+
require_path = root.relative_path(path)
|
96
|
+
|
97
|
+
if const_name.empty?
|
98
|
+
extname = File.extname(path)
|
99
|
+
const_name = require_path.chomp(extname).camelize
|
108
100
|
end
|
101
|
+
|
102
|
+
constant = (constants[const_name] ||= new(const_name))
|
103
|
+
constant.register_as(type, summary)
|
104
|
+
constant.require_paths << require_path
|
109
105
|
end
|
110
106
|
end
|
111
|
-
|
107
|
+
|
108
|
+
constants = constants.values
|
109
|
+
constants.each {|constant| constant.require_paths.uniq! }
|
112
110
|
constants
|
113
111
|
end
|
112
|
+
|
113
|
+
def cast(obj)
|
114
|
+
case obj
|
115
|
+
when String then new(obj)
|
116
|
+
when Module then new(obj.to_s)
|
117
|
+
when Constant then obj
|
118
|
+
else raise ArgumentError, "not a constant or constant name: #{obj.inspect}"
|
119
|
+
end
|
120
|
+
end
|
114
121
|
|
115
122
|
private
|
116
123
|
|
@@ -129,9 +136,12 @@ module Tap
|
|
129
136
|
end
|
130
137
|
end
|
131
138
|
|
132
|
-
# Matches a valid constant
|
139
|
+
# Matches a valid constant. After the match:
|
140
|
+
#
|
141
|
+
# $1:: The unqualified constant (ex 'Const' for '::Const')
|
142
|
+
#
|
133
143
|
CONST_REGEXP = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
|
134
|
-
|
144
|
+
|
135
145
|
# The full constant name
|
136
146
|
attr_reader :const_name
|
137
147
|
|
@@ -142,21 +152,24 @@ module Tap
|
|
142
152
|
# A hash of (type, summary) pairs used to classify self.
|
143
153
|
attr_reader :types
|
144
154
|
|
145
|
-
# Initializes a new Constant with the specified constant name,
|
146
|
-
#
|
147
|
-
# constant name.
|
155
|
+
# Initializes a new Constant with the specified constant name, and
|
156
|
+
# require_paths. Raises an error if const_name is not valid.
|
148
157
|
def initialize(const_name, *require_paths)
|
149
|
-
@const_name = const_name
|
150
|
-
@require_paths = require_paths
|
151
158
|
@types = {}
|
159
|
+
@const_name = normalize(const_name)
|
160
|
+
@require_paths = require_paths
|
161
|
+
end
|
162
|
+
|
163
|
+
def relative_path
|
164
|
+
@relative_path ||= const_name.underscore
|
152
165
|
end
|
153
166
|
|
154
167
|
# Returns the underscored const_name.
|
155
168
|
#
|
156
|
-
# Constant.new("Const::Name").path # => 'const/name'
|
169
|
+
# Constant.new("Const::Name").path # => '/const/name'
|
157
170
|
#
|
158
171
|
def path
|
159
|
-
@path ||=
|
172
|
+
@path ||= "/#{relative_path}"
|
160
173
|
end
|
161
174
|
|
162
175
|
# Returns the basename of path.
|
@@ -169,10 +182,10 @@ module Tap
|
|
169
182
|
|
170
183
|
# Returns the path, minus the basename of path.
|
171
184
|
#
|
172
|
-
# Constant.new("Const::Name").dirname # => 'const'
|
185
|
+
# Constant.new("Const::Name").dirname # => '/const'
|
173
186
|
#
|
174
187
|
def dirname
|
175
|
-
@dirname ||=
|
188
|
+
@dirname ||= File.dirname(path)
|
176
189
|
end
|
177
190
|
|
178
191
|
# Returns the name of the constant, minus nesting.
|
@@ -206,12 +219,17 @@ module Tap
|
|
206
219
|
another.const_name == self.const_name &&
|
207
220
|
another.require_paths == self.require_paths
|
208
221
|
end
|
222
|
+
|
223
|
+
# Peforms comparison of the const_name of self vs another.
|
224
|
+
def <=>(another)
|
225
|
+
const_name <=> another.const_name
|
226
|
+
end
|
209
227
|
|
210
228
|
# Registers the type and summary with self. Raises an error if self is
|
211
229
|
# already registerd as the type and override is false.
|
212
230
|
def register_as(type, summary=nil, override=false)
|
213
|
-
if types.include?(type) && !override
|
214
|
-
raise "already registered as a #{type.inspect}"
|
231
|
+
if types.include?(type) && types[type] != summary && !override
|
232
|
+
raise "already registered as a #{type.inspect} (#{const_name})"
|
215
233
|
end
|
216
234
|
|
217
235
|
types[type] = summary
|
@@ -250,8 +268,10 @@ module Tap
|
|
250
268
|
|
251
269
|
if const.const_defined?(name)
|
252
270
|
require_paths.each do |require_path|
|
253
|
-
|
254
|
-
|
271
|
+
require_path = File.extname(require_path).empty? ? "#{require_path}.rb" : require_path
|
272
|
+
regexp = /#{require_path}$/
|
273
|
+
|
274
|
+
$".delete_if {|path| path =~ regexp }
|
255
275
|
end if unrequire
|
256
276
|
|
257
277
|
return const.send(:remove_const, name)
|
@@ -259,7 +279,19 @@ module Tap
|
|
259
279
|
|
260
280
|
nil
|
261
281
|
end
|
262
|
-
|
282
|
+
|
283
|
+
def path_match?(head, tail=nil)
|
284
|
+
(head.nil? || head.empty? || head_match(head)) && (tail.nil? || tail.empty? || tail_match(tail))
|
285
|
+
end
|
286
|
+
|
287
|
+
def type_match?(type)
|
288
|
+
case type
|
289
|
+
when nil then true
|
290
|
+
when Array then type.any? {|t| types.has_key?(t) }
|
291
|
+
else types.has_key?(type)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
263
295
|
# Returns a string like:
|
264
296
|
#
|
265
297
|
# "#<Tap::Env::Constant:object_id Const::Name (require_path)>"
|
@@ -272,6 +304,29 @@ module Tap
|
|
272
304
|
def to_s
|
273
305
|
const_name
|
274
306
|
end
|
307
|
+
|
308
|
+
private
|
309
|
+
|
310
|
+
def normalize(const_name) # :nodoc:
|
311
|
+
case const_name
|
312
|
+
when Module then const_name.to_s
|
313
|
+
when CONST_REGEXP then $1
|
314
|
+
else raise NameError, "#{const_name.inspect} is not a valid constant name!"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def head_match(head) # :nodoc:
|
319
|
+
index = path.index(head)
|
320
|
+
index == (head[0] == ?/ ? 0 : 1) && begin
|
321
|
+
match_end = index + head.length
|
322
|
+
(match_end == path.length || path[match_end] == ?/)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def tail_match(tail) # :nodoc:
|
327
|
+
index = path.rindex(tail)
|
328
|
+
index && (index + tail.length) == path.length && (index == 0 || path[index-1] == ?/)
|
329
|
+
end
|
275
330
|
end
|
276
331
|
end
|
277
332
|
end
|
data/lib/tap/env/path.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Tap
|
2
|
+
class Env
|
3
|
+
class Path
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Splits the path string along ':' boundaries and expands each
|
7
|
+
# resulting fragments relative to dir. Duplicate paths are removed.
|
8
|
+
# Returns the resulting paths.
|
9
|
+
#
|
10
|
+
# An array of pre-split paths may also be provided as an input.
|
11
|
+
def split(str, dir=Dir.pwd)
|
12
|
+
paths = str.kind_of?(String) ? str.split(':') : str
|
13
|
+
paths.collect! {|path| File.expand_path(path, dir) } if dir
|
14
|
+
paths.uniq!
|
15
|
+
paths
|
16
|
+
end
|
17
|
+
|
18
|
+
def join(paths)
|
19
|
+
paths.join(':')
|
20
|
+
end
|
21
|
+
|
22
|
+
def load(path_file)
|
23
|
+
Root.trivial?(path_file) ? {} : (YAML.load_file(path_file) || {})
|
24
|
+
end
|
25
|
+
|
26
|
+
def escape(str)
|
27
|
+
"'#{str.gsub("'", "\\\\'")}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
FILE = 'tap.yml'
|
32
|
+
|
33
|
+
# The path base.
|
34
|
+
attr_reader :base
|
35
|
+
|
36
|
+
# A mapping of types to paths.
|
37
|
+
attr_reader :map
|
38
|
+
|
39
|
+
# Creates a new Path relative to the base.
|
40
|
+
def initialize(base, map={})
|
41
|
+
@base = File.expand_path(base)
|
42
|
+
@map = {}
|
43
|
+
|
44
|
+
map.each_pair {|type, paths| self[type] = paths }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns an array of expanded paths associated with the type; by
|
48
|
+
# default the type expanded under base.
|
49
|
+
def [](type)
|
50
|
+
map[type] ||= [File.expand_path(type.to_s, base)]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the path for the type. Paths are split and expanded relative to
|
54
|
+
# base (see Path.split).
|
55
|
+
def []=(type, paths)
|
56
|
+
map[type] = Path.split(paths, base)
|
57
|
+
end
|
58
|
+
|
59
|
+
def ==(another)
|
60
|
+
another.kind_of?(Path) &&
|
61
|
+
base == another.base &&
|
62
|
+
map == another.map
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the base path.
|
66
|
+
def to_s
|
67
|
+
base
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/tap/join.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
|
-
require 'tap/app'
|
2
|
-
require 'tap/intern'
|
1
|
+
require 'tap/app/api'
|
3
2
|
|
4
3
|
module Tap
|
5
|
-
|
6
|
-
# Generates a join between the inputs and outputs.
|
7
|
-
def join(inputs, outputs, config={}, klass=Join, &block)
|
8
|
-
klass.new(config, self).join(inputs, outputs, &block)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
# :startdoc::join an unsyncrhonized, multi-way join
|
4
|
+
# :startdoc::join unsyncrhonized multi-way join
|
13
5
|
#
|
14
6
|
# Join defines an unsynchronized, multi-way join where n inputs send their
|
15
7
|
# results to m outputs. Flags can augment how the results are passed, in
|
@@ -17,34 +9,7 @@ module Tap
|
|
17
9
|
#
|
18
10
|
class Join < App::Api
|
19
11
|
class << self
|
20
|
-
|
21
|
-
# Instantiates a new join with the input arguments and overrides
|
22
|
-
# call with the block. The block will be called with the join
|
23
|
-
# instance and result.
|
24
|
-
#
|
25
|
-
# Simply instantiates a new join if no block is given.
|
26
|
-
def intern(config={}, app=Tap::App.instance, &block) # :yields: join, result
|
27
|
-
instance = new(config, app)
|
28
|
-
if block_given?
|
29
|
-
instance.extend Intern(:call)
|
30
|
-
instance.call_block = block
|
31
|
-
end
|
32
|
-
instance
|
33
|
-
end
|
34
|
-
|
35
|
-
def parse!(argv=ARGV, app=Tap::App.instance)
|
36
|
-
parser = self.parser
|
37
|
-
argv = parser.parse!(argv, :add_defaults => false)
|
38
|
-
instance = build({
|
39
|
-
'config' => parser.nested_config,
|
40
|
-
'inputs' => argv.shift,
|
41
|
-
'outputs' => argv.shift
|
42
|
-
}, app)
|
43
|
-
|
44
|
-
[instance, argv]
|
45
|
-
end
|
46
|
-
|
47
|
-
def build(spec={}, app=Tap::App.instance)
|
12
|
+
def build(spec={}, app=Tap::App.current)
|
48
13
|
inputs = resolve(spec['inputs']) do |var|
|
49
14
|
app.get(var) or raise "missing join input: #{var}"
|
50
15
|
end
|
@@ -58,6 +23,14 @@ module Tap
|
|
58
23
|
|
59
24
|
protected
|
60
25
|
|
26
|
+
def convert_to_spec(parser, args)
|
27
|
+
{
|
28
|
+
'config' => parser.nested_config,
|
29
|
+
'inputs' => args.shift,
|
30
|
+
'outputs' => args.shift
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
61
34
|
def resolve(refs) # :nodoc:
|
62
35
|
refs = case refs
|
63
36
|
when String then parse_indicies(refs)
|
@@ -83,34 +56,23 @@ module Tap
|
|
83
56
|
end
|
84
57
|
|
85
58
|
# Causes the outputs to be enqued rather than executed immediately.
|
86
|
-
config :enq, false, :short => 'q', &c.flag # Enque output
|
59
|
+
config :enq, false, :short => 'q', &c.flag # Enque output tasks
|
87
60
|
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
|
92
|
-
# # outputs: call(*inputs)
|
93
|
-
# app.execute(output, *result)
|
94
|
-
#
|
95
|
-
config :splat, false, :short => 's', &c.flag # Splat results to outputs
|
61
|
+
# Converts each result into a one-member array before being passed onto
|
62
|
+
# outputs. Arrayify occurs before iterate and combined the two flags
|
63
|
+
# cancel.
|
64
|
+
config :arrayify, false, :short => 'a', &c.flag # Arrayify results
|
96
65
|
|
97
|
-
# Iterates the results to the outputs
|
98
|
-
#
|
99
|
-
# to arrays using to_ary:
|
66
|
+
# Iterates the results to the outputs. Non-array results are converted to
|
67
|
+
# arrays using to_ary:
|
100
68
|
#
|
101
69
|
# # results: [1,2,3]
|
102
70
|
# # outputs: call(input)
|
103
|
-
# result.to_ary.each {|r| app.
|
104
|
-
#
|
105
|
-
# Iterate may be combined with splat:
|
106
|
-
#
|
107
|
-
# # results: [[1,2],3]
|
108
|
-
# # outputs: call(*inputs)
|
109
|
-
# result.to_ary.each {|r| app.execute(output, *r) }
|
71
|
+
# result.to_ary.each {|r| app.exe(output, r) }
|
110
72
|
#
|
111
73
|
config :iterate, false, :short => 'i', &c.flag # Iterate results to outputs
|
112
74
|
|
113
|
-
signal :join do |sig, (inputs, outputs)|
|
75
|
+
signal :join do |sig, (inputs, outputs)| # join app objects
|
114
76
|
app = sig.obj.app
|
115
77
|
|
116
78
|
inputs = resolve(inputs) do |var|
|
@@ -124,14 +86,14 @@ module Tap
|
|
124
86
|
[inputs, outputs]
|
125
87
|
end
|
126
88
|
|
127
|
-
# An array of input
|
89
|
+
# An array of input tasks, or nil if the join has not been set.
|
128
90
|
attr_reader :inputs
|
129
91
|
|
130
|
-
# An array of output
|
92
|
+
# An array of output tasks, or nil if the join has not been set.
|
131
93
|
attr_reader :outputs
|
132
94
|
|
133
95
|
# Initializes a new join with the specified configuration.
|
134
|
-
def initialize(config={}, app=Tap::App.
|
96
|
+
def initialize(config={}, app=Tap::App.current)
|
135
97
|
@inputs = nil
|
136
98
|
@outputs = nil
|
137
99
|
super
|
@@ -143,6 +105,12 @@ module Tap
|
|
143
105
|
input.joins.delete(self)
|
144
106
|
end if @inputs
|
145
107
|
|
108
|
+
inputs.each do |input|
|
109
|
+
unless input.respond_to?(:joins)
|
110
|
+
raise "input does not support joins: #{input.inspect}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
146
114
|
@inputs = inputs
|
147
115
|
|
148
116
|
inputs.each do |input|
|
@@ -157,7 +125,7 @@ module Tap
|
|
157
125
|
# each output.
|
158
126
|
def call(result)
|
159
127
|
outputs.each do |output|
|
160
|
-
|
128
|
+
exe(output, result)
|
161
129
|
end
|
162
130
|
end
|
163
131
|
|
@@ -167,29 +135,25 @@ module Tap
|
|
167
135
|
|
168
136
|
def to_spec
|
169
137
|
spec = super
|
170
|
-
spec['inputs'] = inputs.collect {|
|
171
|
-
spec['outputs'] = outputs.collect {|
|
138
|
+
spec['inputs'] = inputs.collect {|task| app.var(task) }
|
139
|
+
spec['outputs'] = outputs.collect {|task| app.var(task) }
|
172
140
|
spec
|
173
141
|
end
|
174
142
|
|
175
143
|
protected
|
176
144
|
|
177
|
-
#
|
178
|
-
def
|
179
|
-
mode = enq ? :enq : :
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
execute(mode, node, result)
|
145
|
+
# Executes the task with the input results.
|
146
|
+
def exe(task, result) # :nodoc:
|
147
|
+
mode = enq ? :enq : :exe
|
148
|
+
|
149
|
+
if arrayify
|
150
|
+
result = [result]
|
184
151
|
end
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
def execute(mode, node, result) # :nodoc:
|
189
|
-
if splat
|
190
|
-
app.send(mode, node, *result)
|
152
|
+
|
153
|
+
if iterate
|
154
|
+
result.to_ary.each {|item| app.send(mode, task, item) }
|
191
155
|
else
|
192
|
-
app.send(mode,
|
156
|
+
app.send(mode, task, result)
|
193
157
|
end
|
194
158
|
end
|
195
159
|
end
|