tap 0.12.4 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +34 -0
- data/README +62 -41
- data/bin/tap +36 -40
- data/cmd/console.rb +14 -6
- data/cmd/manifest.rb +62 -58
- data/cmd/run.rb +49 -31
- data/doc/API +84 -0
- data/doc/Class Reference +83 -115
- data/doc/Examples/Command Line +36 -0
- data/doc/Examples/Workflow +40 -0
- data/lib/tap/app.rb +293 -214
- data/lib/tap/app/node.rb +43 -0
- data/lib/tap/app/queue.rb +77 -0
- data/lib/tap/app/stack.rb +16 -0
- data/lib/tap/app/state.rb +22 -0
- data/lib/tap/constants.rb +2 -2
- data/lib/tap/env.rb +400 -314
- data/lib/tap/env/constant.rb +227 -0
- data/lib/tap/env/gems.rb +63 -0
- data/lib/tap/env/manifest.rb +89 -0
- data/lib/tap/env/minimap.rb +292 -0
- data/lib/tap/{support → env}/string_ext.rb +2 -2
- data/lib/tap/exe.rb +113 -125
- data/lib/tap/join.rb +175 -0
- data/lib/tap/joins.rb +9 -0
- data/lib/tap/joins/switch.rb +44 -0
- data/lib/tap/joins/sync.rb +99 -0
- data/lib/tap/root.rb +100 -491
- data/lib/tap/root/utils.rb +220 -0
- data/lib/tap/{support → root}/versions.rb +31 -29
- data/lib/tap/schema.rb +248 -0
- data/lib/tap/schema/parser.rb +413 -0
- data/lib/tap/schema/utils.rb +82 -0
- data/lib/tap/support/intern.rb +19 -6
- data/lib/tap/support/templater.rb +8 -3
- data/lib/tap/task.rb +175 -171
- data/lib/tap/tasks/dump.rb +58 -0
- data/lib/tap/tasks/load.rb +62 -0
- metadata +30 -73
- data/cmd/destroy.rb +0 -27
- data/cmd/generate.rb +0 -27
- data/doc/Command Reference +0 -105
- data/doc/Syntax Reference +0 -234
- data/doc/Tutorial +0 -348
- data/lib/tap/dump.rb +0 -142
- data/lib/tap/file_task.rb +0 -384
- data/lib/tap/generator/arguments.rb +0 -13
- data/lib/tap/generator/base.rb +0 -176
- data/lib/tap/generator/destroy.rb +0 -60
- data/lib/tap/generator/generate.rb +0 -93
- data/lib/tap/generator/generators/command/command_generator.rb +0 -21
- data/lib/tap/generator/generators/command/templates/command.erb +0 -32
- data/lib/tap/generator/generators/config/config_generator.rb +0 -98
- data/lib/tap/generator/generators/generator/generator_generator.rb +0 -37
- data/lib/tap/generator/generators/generator/templates/task.erb +0 -27
- data/lib/tap/generator/generators/generator/templates/test.erb +0 -26
- data/lib/tap/generator/generators/root/root_generator.rb +0 -84
- data/lib/tap/generator/generators/root/templates/MIT-LICENSE +0 -22
- data/lib/tap/generator/generators/root/templates/README +0 -14
- data/lib/tap/generator/generators/root/templates/Rakefile +0 -84
- data/lib/tap/generator/generators/root/templates/Rapfile +0 -11
- data/lib/tap/generator/generators/root/templates/gemspec +0 -27
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -3
- data/lib/tap/generator/generators/task/task_generator.rb +0 -25
- data/lib/tap/generator/generators/task/templates/task.erb +0 -14
- data/lib/tap/generator/generators/task/templates/test.erb +0 -19
- data/lib/tap/generator/manifest.rb +0 -20
- data/lib/tap/generator/preview.rb +0 -69
- data/lib/tap/load.rb +0 -64
- data/lib/tap/spec.rb +0 -41
- data/lib/tap/support/aggregator.rb +0 -65
- data/lib/tap/support/audit.rb +0 -333
- data/lib/tap/support/constant.rb +0 -143
- data/lib/tap/support/constant_manifest.rb +0 -126
- data/lib/tap/support/dependencies.rb +0 -54
- data/lib/tap/support/dependency.rb +0 -44
- data/lib/tap/support/executable.rb +0 -198
- data/lib/tap/support/executable_queue.rb +0 -125
- data/lib/tap/support/gems.rb +0 -43
- data/lib/tap/support/join.rb +0 -144
- data/lib/tap/support/joins.rb +0 -12
- data/lib/tap/support/joins/switch.rb +0 -27
- data/lib/tap/support/joins/sync_merge.rb +0 -38
- data/lib/tap/support/manifest.rb +0 -171
- data/lib/tap/support/minimap.rb +0 -90
- data/lib/tap/support/node.rb +0 -176
- data/lib/tap/support/parser.rb +0 -450
- data/lib/tap/support/schema.rb +0 -385
- data/lib/tap/support/shell_utils.rb +0 -67
- data/lib/tap/test.rb +0 -77
- data/lib/tap/test/assertions.rb +0 -38
- data/lib/tap/test/env_vars.rb +0 -29
- data/lib/tap/test/extensions.rb +0 -73
- data/lib/tap/test/file_test.rb +0 -362
- data/lib/tap/test/file_test_class.rb +0 -15
- data/lib/tap/test/regexp_escape.rb +0 -87
- data/lib/tap/test/script_test.rb +0 -46
- data/lib/tap/test/script_tester.rb +0 -115
- data/lib/tap/test/subset_test.rb +0 -260
- data/lib/tap/test/subset_test_class.rb +0 -99
- data/lib/tap/test/tap_test.rb +0 -109
- data/lib/tap/test/utils.rb +0 -231
data/lib/tap/support/intern.rb
CHANGED
@@ -1,29 +1,42 @@
|
|
1
1
|
module Tap
|
2
2
|
module Support
|
3
3
|
|
4
|
-
# Generates an Intern module
|
4
|
+
# Generates an Intern module to override the specified method_name. Intern
|
5
|
+
# modules are useful to override a tiny bit of functionality without having
|
6
|
+
# to generate a full subclass.
|
7
|
+
#
|
5
8
|
# An Intern module:
|
9
|
+
#
|
6
10
|
# - adds an accessor for <method_name>_block
|
7
|
-
# - overrides <method_name> to call the block
|
11
|
+
# - overrides <method_name> to call the block, prepending self to
|
12
|
+
# the input arguments
|
13
|
+
#
|
14
|
+
# For example:
|
15
|
+
#
|
16
|
+
# array = [1,2,3].extend Intern(:last)
|
17
|
+
#
|
18
|
+
# array.last # => 3
|
19
|
+
# array.last_block = lambda {|arr| arr.first }
|
20
|
+
# array.last # => 3
|
8
21
|
#
|
9
22
|
def self.Intern(method_name)
|
10
23
|
mod = INTERN_MODULES[method_name.to_sym]
|
11
24
|
return mod unless mod == nil
|
12
|
-
|
25
|
+
|
13
26
|
mod = INTERN_MODULES[method_name.to_sym] = Module.new
|
14
27
|
mod.module_eval %Q{
|
15
28
|
attr_accessor :#{method_name}_block
|
16
29
|
|
17
30
|
def #{method_name}(*inputs)
|
18
|
-
|
31
|
+
return super unless #{method_name}_block
|
19
32
|
inputs.unshift(self)
|
20
|
-
|
33
|
+
|
21
34
|
arity = #{method_name}_block.arity
|
22
35
|
n = inputs.length
|
23
36
|
unless n == arity || (arity < 0 && (-1-n) <= arity)
|
24
37
|
raise ArgumentError.new("wrong number of arguments (\#{n} for \#{arity})")
|
25
38
|
end
|
26
|
-
|
39
|
+
|
27
40
|
#{method_name}_block.call(*inputs)
|
28
41
|
end
|
29
42
|
}
|
@@ -121,8 +121,10 @@ module Tap
|
|
121
121
|
end
|
122
122
|
|
123
123
|
class << self
|
124
|
-
|
125
|
-
|
124
|
+
|
125
|
+
# Builds the erb template with the specified attributes.
|
126
|
+
def build(template, attributes={}, filename=nil)
|
127
|
+
new(template, attributes, filename).build
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
@@ -163,6 +165,8 @@ module Tap
|
|
163
165
|
end
|
164
166
|
|
165
167
|
unless RUBY_VERSION < "1.9"
|
168
|
+
#-- TODO
|
169
|
+
# check if this is still needed...
|
166
170
|
def force_encoding(encoding)
|
167
171
|
@_erbout.force_encoding(encoding)
|
168
172
|
@_erbout
|
@@ -188,11 +192,12 @@ module Tap
|
|
188
192
|
|
189
193
|
# Build the template. All methods of self will be
|
190
194
|
# accessible in the template.
|
191
|
-
def build(attrs={})
|
195
|
+
def build(attrs={}, filename=nil)
|
192
196
|
attrs.each_pair do |key, value|
|
193
197
|
send("#{key}=", value)
|
194
198
|
end
|
195
199
|
|
200
|
+
@template.filename = filename
|
196
201
|
@template.result(binding)
|
197
202
|
@_erbout
|
198
203
|
end
|
data/lib/tap/task.rb
CHANGED
@@ -1,13 +1,22 @@
|
|
1
|
-
|
1
|
+
require 'tap/joins'
|
2
|
+
require 'tap/root'
|
3
|
+
require 'tap/env/string_ext'
|
2
4
|
|
3
5
|
module Tap
|
4
|
-
autoload(:FileTask, 'tap/file_task')
|
5
|
-
|
6
6
|
module Support
|
7
7
|
autoload(:Templater, 'tap/support/templater')
|
8
|
-
autoload(:Intern, 'tap/support/intern')
|
9
8
|
end
|
10
9
|
|
10
|
+
class App
|
11
|
+
# Generates a task initialized to self.
|
12
|
+
def task(config={}, klass=Task, &block)
|
13
|
+
klass.intern(config, self, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Tasks are nodes that map to the command line. Tasks provide support for
|
18
|
+
# configuration, documentation, and provide helpers to build workflows.
|
19
|
+
#
|
11
20
|
# === Task Definition
|
12
21
|
#
|
13
22
|
# Tasks specify executable code by overridding the process method in
|
@@ -31,17 +40,17 @@ module Tap
|
|
31
40
|
# MixedInputs.new.execute(:a, :b) # => [:a, :b, []]
|
32
41
|
# MixedInputs.new.execute(:a, :b, 1, 2, 3) # => [:a, :b, [1,2,3]]
|
33
42
|
#
|
34
|
-
# Tasks may be
|
35
|
-
# using a block that receives the task
|
43
|
+
# Tasks may be created with new, or with intern. Intern overrides process
|
44
|
+
# using a block that receives the task and the inputs.
|
36
45
|
#
|
37
46
|
# no_inputs = Task.intern {|task| [] }
|
38
47
|
# one_input = Task.intern {|task, input| [input] }
|
39
48
|
# mixed_inputs = Task.intern {|task, a, b, *args| [a, b, args] }
|
40
49
|
#
|
41
|
-
# no_inputs.execute
|
42
|
-
# one_input.execute(:a)
|
43
|
-
# mixed_inputs.execute(:a, :b)
|
44
|
-
# mixed_inputs.execute(:a, :b, 1, 2, 3)
|
50
|
+
# no_inputs.execute # => []
|
51
|
+
# one_input.execute(:a) # => [:a]
|
52
|
+
# mixed_inputs.execute(:a, :b) # => [:a, :b, []]
|
53
|
+
# mixed_inputs.execute(:a, :b, 1, 2, 3) # => [:a, :b, [1,2,3]]
|
45
54
|
#
|
46
55
|
# === Configuration
|
47
56
|
#
|
@@ -80,16 +89,17 @@ module Tap
|
|
80
89
|
# end
|
81
90
|
#
|
82
91
|
# t = ValidatingTask.new
|
83
|
-
# t.string = 1
|
84
|
-
# t.integer = 1.1
|
92
|
+
# t.string = 1 # !> ValidationError
|
93
|
+
# t.integer = 1.1 # !> ValidationError
|
85
94
|
#
|
86
95
|
# t.integer = "1"
|
87
|
-
# t.integer == 1
|
96
|
+
# t.integer == 1 # => true
|
88
97
|
#
|
89
98
|
# See the {Configurable}[http://tap.rubyforge.org/configurable/]
|
90
99
|
# documentation for more information.
|
91
100
|
#
|
92
101
|
# === Subclassing
|
102
|
+
#
|
93
103
|
# Tasks may be subclassed normally, but be sure to call super as necessary,
|
94
104
|
# in particular when overriding the following methods:
|
95
105
|
#
|
@@ -110,29 +120,16 @@ module Tap
|
|
110
120
|
# end
|
111
121
|
#
|
112
122
|
class Task
|
123
|
+
include App::Node
|
113
124
|
include Configurable
|
114
|
-
include Support::Executable
|
115
125
|
|
116
126
|
class << self
|
117
127
|
# Returns class dependencies
|
118
128
|
attr_reader :dependencies
|
119
129
|
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
# Returns the default name for the class: to_s.underscore
|
124
|
-
def default_name
|
125
|
-
# lazy-setting default_name like this (rather than
|
126
|
-
# within inherited, for example) is an optimization
|
127
|
-
# since many subclass operations end up setting
|
128
|
-
# default_name themselves.
|
129
|
-
@default_name ||= to_s.underscore
|
130
|
-
end
|
131
|
-
|
132
|
-
# Returns an instance of self; the instance is a kind of 'global'
|
133
|
-
# instance used in class-level dependencies. See depends_on.
|
134
|
-
def instance
|
135
|
-
@instance ||= new.extend(Support::Dependency)
|
130
|
+
# Returns or initializes the instance of self cached with app.
|
131
|
+
def instance(app=Tap::App.instance, auto_initialize=true)
|
132
|
+
app.cache[self] ||= (auto_initialize ? new({}, app) : nil)
|
136
133
|
end
|
137
134
|
|
138
135
|
def inherited(child) # :nodoc:
|
@@ -146,26 +143,28 @@ module Tap
|
|
146
143
|
end
|
147
144
|
|
148
145
|
# Instantiates a new task with the input arguments and overrides
|
149
|
-
# process with the block. The block will be called with the
|
146
|
+
# process with the block. The block will be called with the task
|
150
147
|
# instance, plus any inputs.
|
151
148
|
#
|
152
149
|
# Simply instantiates a new task if no block is given.
|
153
|
-
def intern(
|
154
|
-
instance = new(
|
150
|
+
def intern(config={}, app=Tap::App.instance, &block) # :yields: task, inputs...
|
151
|
+
instance = new(config, app)
|
155
152
|
if block_given?
|
156
|
-
instance.extend Support::Intern
|
153
|
+
instance.extend Support::Intern(:process)
|
157
154
|
instance.process_block = block
|
158
155
|
end
|
159
156
|
instance
|
160
157
|
end
|
161
158
|
|
162
|
-
# Parses the argv into an instance of self and an array of arguments
|
163
|
-
# (implicitly to be enqued to the instance).
|
159
|
+
# Parses the argv into an instance of self and an array of arguments
|
160
|
+
# (implicitly to be enqued to the instance). By default parse
|
161
|
+
# parses an argh then calls instantiate, but there is no requirement
|
162
|
+
# that this occurs in subclasses.
|
164
163
|
def parse(argv=ARGV, app=Tap::App.instance)
|
165
164
|
parse!(argv.dup, app)
|
166
165
|
end
|
167
166
|
|
168
|
-
# Same as parse, but removes
|
167
|
+
# Same as parse, but removes arguments destructively.
|
169
168
|
def parse!(argv=ARGV, app=Tap::App.instance)
|
170
169
|
opts = ConfigParser.new
|
171
170
|
|
@@ -189,51 +188,44 @@ module Tap
|
|
189
188
|
puts opts
|
190
189
|
exit
|
191
190
|
end
|
192
|
-
|
193
|
-
# add option to specify the task name
|
194
|
-
name = default_name
|
195
|
-
opts.on('--name NAME', 'Specifies the task name') do |value|
|
196
|
-
name = value
|
197
|
-
end
|
198
191
|
|
199
192
|
# add option to specify a config file
|
200
|
-
|
201
|
-
|
202
|
-
config_path = value
|
203
|
-
end
|
204
|
-
|
205
|
-
# add option to load args to ARGV
|
206
|
-
use_args = []
|
207
|
-
opts.on('--use FILE', 'Loads inputs to ARGV') do |path|
|
208
|
-
use(path, use_args)
|
193
|
+
opts.on('--config FILE', 'Specifies a config file') do |config_file|
|
194
|
+
opts.config.merge!(load_config(config_file))
|
209
195
|
end
|
210
196
|
|
211
|
-
#
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
instance = new({}, name, app).reconfigure(config).reconfigure(opts.nested_config)
|
197
|
+
# (note defaults are not added so they will not
|
198
|
+
# conflict with string keys from a config file)
|
199
|
+
argv = opts.parse!(argv, :add_defaults => false)
|
200
|
+
argh = {
|
201
|
+
:config => opts.nested_config,
|
202
|
+
:args => argv
|
203
|
+
}
|
219
204
|
|
220
|
-
|
205
|
+
instantiate(argh, app)
|
221
206
|
end
|
222
207
|
|
223
|
-
#
|
224
|
-
#
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
208
|
+
# Instantiates an instance of self and returns an instance of self and
|
209
|
+
# an array of arguments (implicitly to be enqued to the instance).
|
210
|
+
def instantiate(argh={}, app=Tap::App.instance)
|
211
|
+
config = argh[:config] || {}
|
212
|
+
instance = new(config, app)
|
213
|
+
|
214
|
+
if argh[:cache]
|
215
|
+
if app.cache.has_key?(self) && app.cache[self] != instance
|
216
|
+
raise "cache already has an instance for: #{self}"
|
217
|
+
end
|
218
|
+
|
219
|
+
app.cache[self] = instance
|
220
|
+
end
|
221
|
+
|
222
|
+
[instance, argh[:args]]
|
231
223
|
end
|
232
224
|
|
233
|
-
DEFAULT_HELP_TEMPLATE = %Q{<%
|
234
|
-
<%= task_class %><%=
|
225
|
+
DEFAULT_HELP_TEMPLATE = %Q{<% desc = task_class::desc %>
|
226
|
+
<%= task_class %><%= desc.empty? ? '' : ' -- ' %><%= desc.to_s %>
|
235
227
|
|
236
|
-
<% desc =
|
228
|
+
<% desc = desc.kind_of?(Lazydoc::Comment) ? desc.wrap(77, 2, nil) : [] %>
|
237
229
|
<% unless desc.empty? %>
|
238
230
|
<%= '-' * 80 %>
|
239
231
|
|
@@ -253,51 +245,34 @@ module Tap
|
|
253
245
|
# Recursively loads path into a nested configuration file.
|
254
246
|
def load_config(path)
|
255
247
|
# optimization to check for trivial paths
|
256
|
-
return {} if Root.trivial?(path)
|
248
|
+
return {} if Root::Utils.trivial?(path)
|
257
249
|
|
258
250
|
Configurable::Utils.load_file(path, true) do |base, key, value|
|
259
251
|
base[key] ||= value if base.kind_of?(Hash)
|
260
252
|
end
|
261
253
|
end
|
262
254
|
|
263
|
-
# Loads the contents of path onto argv.
|
264
|
-
def use(path, argv=ARGV)
|
265
|
-
obj = Root.trivial?(path) ? [] : (YAML.load_file(path) || [])
|
266
|
-
|
267
|
-
case obj
|
268
|
-
when Array then argv.concat(obj)
|
269
|
-
else argv << obj
|
270
|
-
end
|
271
|
-
|
272
|
-
argv
|
273
|
-
end
|
274
|
-
|
275
255
|
protected
|
276
256
|
|
277
257
|
# Sets a class-level dependency; when task class B depends_on another
|
278
|
-
# task class A, instances of B are initialized to depend on
|
258
|
+
# task class A, instances of B are initialized to depend on a shared
|
259
|
+
# instance of A. The shared instance is specific to an app and can
|
260
|
+
# be accessed through instance(app).
|
261
|
+
#
|
279
262
|
# If a non-nil name is specified, depends_on will create a reader of
|
280
|
-
# the
|
263
|
+
# the dependency instance.
|
281
264
|
#
|
282
265
|
# class A < Tap::Task
|
283
|
-
# def process
|
284
|
-
# "result"
|
285
|
-
# end
|
286
266
|
# end
|
287
267
|
#
|
288
268
|
# class B < Tap::Task
|
289
269
|
# depends_on :a, A
|
290
270
|
# end
|
291
271
|
#
|
292
|
-
#
|
293
|
-
# b
|
294
|
-
# b.
|
295
|
-
#
|
296
|
-
# A.instance.resolved? # => true
|
297
|
-
#
|
298
|
-
# Normally class-level dependencies are not added to existing instances
|
299
|
-
# but, as a special case, depends_on updates instance to depend on
|
300
|
-
# dependency_class.instance.
|
272
|
+
# app = Tap::App.new
|
273
|
+
# b = B.new({}, app)
|
274
|
+
# b.dependencies # => [A.instance(app)]
|
275
|
+
# b.a # => A.instance(app)
|
301
276
|
#
|
302
277
|
# Returns self.
|
303
278
|
def depends_on(name, dependency_class)
|
@@ -305,15 +280,10 @@ module Tap
|
|
305
280
|
dependencies << dependency_class
|
306
281
|
end
|
307
282
|
|
308
|
-
# update instance with the dependency if necessary
|
309
|
-
if instance_variable_defined?(:@instance)
|
310
|
-
instance.depends_on(dependency_class.instance)
|
311
|
-
end
|
312
|
-
|
313
283
|
if name
|
314
284
|
# returns the resolved result of the dependency
|
315
285
|
define_method(name) do
|
316
|
-
dependency_class.instance
|
286
|
+
dependency_class.instance(app)
|
317
287
|
end
|
318
288
|
|
319
289
|
public(name)
|
@@ -322,14 +292,13 @@ module Tap
|
|
322
292
|
self
|
323
293
|
end
|
324
294
|
|
325
|
-
# Defines a task subclass with the specified configurations and process
|
326
|
-
# During initialization the subclass is instantiated and made
|
327
|
-
# through
|
295
|
+
# Defines a task subclass with the specified configurations and process
|
296
|
+
# block. During initialization the subclass is instantiated and made
|
297
|
+
# accessible through the name method.
|
328
298
|
#
|
329
|
-
# Defined tasks may be configured during
|
330
|
-
#
|
331
|
-
#
|
332
|
-
# joined in the workflow method.
|
299
|
+
# Defined tasks may be configured during through config, or directly
|
300
|
+
# through the instance; in effect you get tasks with nested configs which
|
301
|
+
# can greatly facilitate workflows.
|
333
302
|
#
|
334
303
|
# class AddALetter < Tap::Task
|
335
304
|
# config :letter, 'a'
|
@@ -341,7 +310,8 @@ module Tap
|
|
341
310
|
# define :b, AddALetter, {:letter => 'b'}
|
342
311
|
# define :c, AddALetter, {:letter => 'c'}
|
343
312
|
#
|
344
|
-
# def
|
313
|
+
# def initialize(*args)
|
314
|
+
# super
|
345
315
|
# a.sequence(b, c)
|
346
316
|
# end
|
347
317
|
#
|
@@ -394,8 +364,6 @@ module Tap
|
|
394
364
|
def define(name, baseclass=Tap::Task, configs={}, options={}, &block)
|
395
365
|
# define the subclass
|
396
366
|
subclass = Class.new(baseclass)
|
397
|
-
subclass.default_name = name.to_s
|
398
|
-
|
399
367
|
configs.each_pair do |key, value|
|
400
368
|
subclass.send(:config, key, value)
|
401
369
|
end
|
@@ -416,25 +384,34 @@ module Tap
|
|
416
384
|
end
|
417
385
|
|
418
386
|
instance_variable_set(:@source_file, __FILE__)
|
419
|
-
instance_variable_set(:@default_name, 'tap/task')
|
420
387
|
instance_variable_set(:@dependencies, [])
|
421
388
|
|
422
|
-
lazy_attr :
|
389
|
+
lazy_attr :desc, 'task'
|
423
390
|
lazy_attr :args, :process
|
424
391
|
lazy_register :process, Lazydoc::Arguments
|
425
392
|
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
393
|
+
###############################################################
|
394
|
+
# [depreciated] manifest will be removed at 1.0
|
395
|
+
lazy_attr :manifest
|
396
|
+
def self.desc(resolve=true)
|
397
|
+
comment = const_attrs['task'] ||= self.manifest
|
398
|
+
resolve && comment.kind_of?(Lazydoc::Comment) ? comment.resolve : comment
|
399
|
+
end
|
400
|
+
def self.manifest
|
401
|
+
# :::-
|
402
|
+
#"warn manifest is depreciated, use ::task instead"
|
403
|
+
# :::+
|
404
|
+
const_attrs['manifest'] ||= Lazydoc::Subject.new(nil, lazydoc)
|
405
|
+
end
|
406
|
+
###############################################################
|
407
|
+
|
408
|
+
# The App receiving self during enq
|
409
|
+
attr_reader :app
|
431
410
|
|
432
411
|
# Initializes a new Task.
|
433
|
-
def initialize(config={},
|
434
|
-
@name = name || self.class.default_name
|
412
|
+
def initialize(config={}, app=Tap::App.instance)
|
435
413
|
@app = app
|
436
|
-
@
|
437
|
-
@on_complete_block = nil
|
414
|
+
@joins = []
|
438
415
|
@dependencies = []
|
439
416
|
|
440
417
|
# initialize configs
|
@@ -442,10 +419,20 @@ module Tap
|
|
442
419
|
|
443
420
|
# setup class dependencies
|
444
421
|
self.class.dependencies.each do |dependency_class|
|
445
|
-
depends_on
|
422
|
+
depends_on dependency_class.instance(app)
|
446
423
|
end
|
447
|
-
|
448
|
-
|
424
|
+
end
|
425
|
+
|
426
|
+
# Auditing method call. Resolves dependencies, executes method_name,
|
427
|
+
# and sends the audited result to the on_complete_block (if set).
|
428
|
+
#
|
429
|
+
# Returns the audited result.
|
430
|
+
def execute(*inputs)
|
431
|
+
app.dispatch(self, inputs)
|
432
|
+
end
|
433
|
+
|
434
|
+
def call(*inputs)
|
435
|
+
process(*inputs)
|
449
436
|
end
|
450
437
|
|
451
438
|
# The method for processing inputs into outputs. Override this method in
|
@@ -459,65 +446,82 @@ module Tap
|
|
459
446
|
# end
|
460
447
|
# end
|
461
448
|
#
|
462
|
-
#
|
449
|
+
# results = []
|
450
|
+
# app = Tap::App.new {|result| results << result }
|
451
|
+
#
|
452
|
+
# t = TaskWithTwoInputs.new({}, app)
|
463
453
|
# t.enq(1,2).enq(3,4)
|
464
|
-
#
|
465
|
-
#
|
454
|
+
#
|
455
|
+
# app.run
|
456
|
+
# results # => [[2,1], [4,3]]
|
466
457
|
#
|
467
458
|
# By default, process simply returns the inputs.
|
468
459
|
def process(*inputs)
|
469
460
|
inputs
|
470
461
|
end
|
471
462
|
|
472
|
-
#
|
473
|
-
|
474
|
-
|
475
|
-
app.
|
463
|
+
# Enqueues self to app with the inputs. The number of inputs provided
|
464
|
+
# should match the number of inputs for the method_name method.
|
465
|
+
def enq(*inputs)
|
466
|
+
app.queue.enq(self, inputs)
|
467
|
+
self
|
476
468
|
end
|
477
469
|
|
478
|
-
#
|
479
|
-
|
480
|
-
|
470
|
+
# Sets a sequence workflow pattern for the tasks; each task
|
471
|
+
# enques the next task with it's results, starting with self.
|
472
|
+
def sequence(*tasks)
|
473
|
+
options = tasks[-1].kind_of?(Hash) ? tasks.pop : {}
|
474
|
+
|
475
|
+
current_task = self
|
476
|
+
tasks.each do |next_task|
|
477
|
+
Join.new(options, app).join([current_task], [next_task])
|
478
|
+
current_task = next_task
|
479
|
+
end
|
481
480
|
end
|
482
|
-
|
483
|
-
#
|
484
|
-
#
|
485
|
-
def
|
486
|
-
|
481
|
+
|
482
|
+
# Sets a fork workflow pattern for self; each target will enque the
|
483
|
+
# results of self.
|
484
|
+
def fork(*targets)
|
485
|
+
options = targets[-1].kind_of?(Hash) ? targets.pop : {}
|
486
|
+
Join.new(options, app).join([self], targets)
|
487
487
|
end
|
488
|
-
|
489
|
-
protected
|
490
488
|
|
491
|
-
#
|
492
|
-
|
489
|
+
# Sets a simple merge workflow pattern for the source tasks. Each
|
490
|
+
# source enques self with it's result; no synchronization occurs,
|
491
|
+
# nor are results grouped before being enqued.
|
492
|
+
def merge(*sources)
|
493
|
+
options = sources[-1].kind_of?(Hash) ? sources.pop : {}
|
494
|
+
Join.new(options, app).join(sources, [self])
|
493
495
|
end
|
494
|
-
|
495
|
-
# Hook to execute code before inputs are processed.
|
496
|
-
def before_execute() end
|
497
|
-
|
498
|
-
# Hook to execute code after inputs are processed.
|
499
|
-
def after_execute() end
|
500
496
|
|
501
|
-
#
|
502
|
-
#
|
503
|
-
|
504
|
-
|
497
|
+
# Sets a synchronized merge workflow for the source tasks. Results
|
498
|
+
# from each source are collected and enqued as a single group to
|
499
|
+
# self. The collective results are not enqued until all sources
|
500
|
+
# have completed. See Joins::Sync.
|
501
|
+
def sync_merge(*sources)
|
502
|
+
options = sources[-1].kind_of?(Hash) ? sources.pop : {}
|
503
|
+
Joins::Sync.new(options, app).join(sources, [self])
|
504
|
+
end
|
505
|
+
|
506
|
+
# Sets a switch workflow pattern for self. On complete, switch yields
|
507
|
+
# the result to the block and the block should return the index of the
|
508
|
+
# target to enque with the results. No target will be enqued if the
|
509
|
+
# index is false or nil. An error is raised if no target can be found
|
510
|
+
# for the specified index. See Joins::Switch.
|
511
|
+
def switch(*targets, &block) # :yields: result
|
512
|
+
options = targets[-1].kind_of?(Hash) ? targets.pop : {}
|
513
|
+
Joins::Switch.new(options, app).join([self], targets, &block)
|
505
514
|
end
|
506
515
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
def execute_with_callbacks(*inputs) # :nodoc:
|
511
|
-
before_execute
|
512
|
-
begin
|
513
|
-
result = process(*inputs)
|
514
|
-
rescue
|
515
|
-
on_execute_error($!)
|
516
|
-
end
|
517
|
-
after_execute
|
518
|
-
|
519
|
-
result
|
516
|
+
# Logs the inputs to the application logger (via app.log)
|
517
|
+
def log(action, msg="", level=Logger::INFO)
|
518
|
+
app.log(action, msg, level)
|
520
519
|
end
|
521
520
|
|
521
|
+
# Provides an abbreviated version of the default inspect, with only
|
522
|
+
# the task class, object_id, and configurations listed.
|
523
|
+
def inspect
|
524
|
+
"#<#{self.class.to_s}:#{object_id} #{config.to_hash.inspect} >"
|
525
|
+
end
|
522
526
|
end
|
523
527
|
end
|