tap 0.12.4 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|