bahuvrihi-tap 0.10.6 → 0.10.7
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rap +13 -5
- data/lib/tap.rb +0 -4
- data/lib/tap/app.rb +10 -138
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/declarations.rb +201 -0
- data/lib/tap/env.rb +10 -2
- data/lib/tap/exe.rb +2 -2
- data/lib/tap/generator/generators/root/templates/Rakefile +1 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
- data/lib/tap/spec.rb +38 -63
- data/lib/tap/spec/adapter.rb +8 -31
- data/lib/tap/spec/inheritable_class_test_root.rb +9 -0
- data/lib/tap/support/audit.rb +0 -2
- data/lib/tap/support/combinator.rb +83 -31
- data/lib/tap/support/configurable_class.rb +7 -7
- data/lib/tap/support/{dependable.rb → dependencies.rb} +9 -7
- data/lib/tap/support/executable.rb +226 -19
- data/lib/tap/support/gems/rake.rb +6 -3
- data/lib/tap/support/join.rb +87 -0
- data/lib/tap/support/joins.rb +13 -0
- data/lib/tap/support/joins/fork.rb +18 -0
- data/lib/tap/support/joins/merge.rb +20 -0
- data/lib/tap/support/joins/sequence.rb +21 -0
- data/lib/tap/support/joins/switch.rb +23 -0
- data/lib/tap/support/joins/sync_merge.rb +57 -0
- data/lib/tap/support/lazydoc/document.rb +10 -0
- data/lib/tap/support/node.rb +58 -0
- data/lib/tap/support/parser.rb +379 -0
- data/lib/tap/support/schema.rb +350 -0
- data/lib/tap/support/tdoc.rb +5 -0
- data/lib/tap/support/validation.rb +2 -0
- data/lib/tap/task.rb +26 -61
- data/lib/tap/test.rb +9 -82
- data/lib/tap/test/assertions.rb +38 -0
- data/lib/tap/test/extensions.rb +78 -0
- data/lib/tap/test/{file_methods.rb → file_test.rb} +64 -37
- data/lib/tap/test/{file_methods_class.rb → file_test_class.rb} +2 -2
- data/lib/tap/test/regexp_escape.rb +87 -0
- data/lib/tap/test/script_test.rb +46 -0
- data/lib/tap/test/script_tester.rb +109 -0
- data/lib/tap/test/{subset_methods.rb → subset_test.rb} +9 -9
- data/lib/tap/test/{subset_methods_class.rb → subset_test_class.rb} +22 -14
- data/lib/tap/test/{tap_methods.rb → tap_test.rb} +43 -6
- data/lib/tap/test/utils.rb +6 -3
- metadata +27 -24
- data/lib/tap/parser.rb +0 -619
- data/lib/tap/spec/file_methods.rb +0 -16
- data/lib/tap/spec/file_methods_class.rb +0 -13
- data/lib/tap/spec/subset_methods.rb +0 -14
- data/lib/tap/support/batchable.rb +0 -47
- data/lib/tap/support/batchable_class.rb +0 -107
- data/lib/tap/support/declarations.rb +0 -131
- data/lib/tap/support/lazydoc/declaration.rb +0 -20
- data/lib/tap/support/parsers/base.rb +0 -81
- data/lib/tap/support/parsers/server.rb +0 -113
- data/lib/tap/test/script_methods.rb +0 -75
- data/lib/tap/test/script_methods/regexp_escape.rb +0 -94
- data/lib/tap/test/script_methods/script_test.rb +0 -109
- data/lib/tap/workflow.rb +0 -161
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'tap/support/audit'
|
2
|
-
require 'tap/support/dependable'
|
3
2
|
|
4
3
|
module Tap
|
5
4
|
module Support
|
@@ -8,7 +7,9 @@ module Tap
|
|
8
7
|
# wrapped by extending the object that receives them; the easiest way
|
9
8
|
# to make an object executable is to use Object#_method.
|
10
9
|
module Executable
|
11
|
-
|
10
|
+
|
11
|
+
# The Tap::App the Executable belongs to.
|
12
|
+
attr_reader :app
|
12
13
|
|
13
14
|
# The method called when an Executable is executed via _execute
|
14
15
|
attr_reader :_method_name
|
@@ -19,57 +20,258 @@ module Tap
|
|
19
20
|
# An array of dependency indexes that will be resolved on _execute
|
20
21
|
attr_reader :dependencies
|
21
22
|
|
23
|
+
# The batch for the Executable.
|
24
|
+
attr_reader :batch
|
25
|
+
|
22
26
|
public
|
23
27
|
|
24
28
|
# Extends obj with Executable and sets up all required variables. The
|
25
29
|
# specified method will be called on _execute.
|
26
|
-
def self.initialize(obj, method_name, &on_complete_block)
|
30
|
+
def self.initialize(obj, method_name, app=App.instance, batch=[], dependencies=[], &on_complete_block)
|
27
31
|
obj.extend Executable
|
32
|
+
obj.instance_variable_set(:@app, app)
|
28
33
|
obj.instance_variable_set(:@_method_name, method_name)
|
29
34
|
obj.instance_variable_set(:@on_complete_block, on_complete_block)
|
30
|
-
obj.instance_variable_set(:@dependencies,
|
35
|
+
obj.instance_variable_set(:@dependencies, dependencies)
|
36
|
+
obj.instance_variable_set(:@batch, batch)
|
37
|
+
batch << obj
|
38
|
+
|
31
39
|
obj
|
32
40
|
end
|
33
41
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
42
|
+
# Initializes a new batch object and adds the object to batch.
|
43
|
+
# The object will be a duplicate of self. (Note this method
|
44
|
+
# can raise an error for objects that don't support dup, like
|
45
|
+
# methods generated by Object#_method).
|
46
|
+
def initialize_batch_obj
|
47
|
+
obj = self.dup
|
48
|
+
|
49
|
+
if obj.kind_of?(Executable)
|
50
|
+
batch << obj
|
51
|
+
obj
|
52
|
+
else
|
53
|
+
Executable.initialize(obj, _method_name, app, batch, dependencies, &on_complete_block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns true if the batch size is greater than one
|
58
|
+
# (the one being self).
|
59
|
+
def batched?
|
60
|
+
batch.length > 1
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the index of the self in batch.
|
64
|
+
def batch_index
|
65
|
+
batch.index(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Merges the batches for self and the specified Executables,
|
69
|
+
# removing duplicates.
|
70
|
+
#
|
71
|
+
# class BatchExecutable
|
72
|
+
# include Tap::Support::Executable
|
73
|
+
# def initialize(batch=[])
|
74
|
+
# @batch = batch
|
75
|
+
# batch << self
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# b1 = BatchExecutable.new
|
80
|
+
# b2 = BatchExecutable.new
|
81
|
+
# b3 = BatchExecutable.new
|
82
|
+
#
|
83
|
+
# b1.batch_with(b2, b3)
|
84
|
+
# b1.batch # => [b1, b2, b3]
|
85
|
+
# b3.batch # => [b1, b2, b3]
|
86
|
+
#
|
87
|
+
# Note that batch_with is not recursive (ie it does not
|
88
|
+
# merge the batches of each member in the batch):
|
89
|
+
#
|
90
|
+
# b4 = BatchExecutable.new
|
91
|
+
# b4.batch_with(b3)
|
92
|
+
#
|
93
|
+
# b4.batch # => [b4, b1, b2, b3]
|
94
|
+
# b3.batch # => [b4, b1, b2, b3]
|
95
|
+
# b2.batch # => [b1, b2, b3]
|
96
|
+
# b1.batch # => [b1, b2, b3]
|
97
|
+
#
|
98
|
+
# However it does affect all objects that share the same
|
99
|
+
# underlying batch:
|
100
|
+
#
|
101
|
+
# b5 = BatchExecutable.new(b1.batch)
|
102
|
+
# b6 = BatchExecutable.new
|
103
|
+
#
|
104
|
+
# b5.batch.object_id # => b1.batch.object_id
|
105
|
+
# b5.batch # => [b1, b2, b3, b5]
|
106
|
+
#
|
107
|
+
# b5.batch_with(b6)
|
108
|
+
#
|
109
|
+
# b5.batch # => [b1, b2, b3, b5, b6]
|
110
|
+
# b1.batch # => [b1, b2, b3, b5, b6]
|
111
|
+
#
|
112
|
+
# Returns self.
|
113
|
+
def batch_with(*executables)
|
114
|
+
batches = [batch] + executables.collect {|executable| executable.batch }
|
115
|
+
batches.uniq!
|
116
|
+
|
117
|
+
merged = []
|
118
|
+
batches.each do |batch|
|
119
|
+
merged.concat(batch)
|
120
|
+
batch.clear
|
121
|
+
end
|
122
|
+
|
123
|
+
merged.uniq!
|
124
|
+
batches.each {|batch| batch.concat(merged) }
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
# Enqueues self and self.batch to app with the inputs. The number
|
129
|
+
# of inputs provided should match the number of inputs specified
|
130
|
+
# by the arity of the _method_name method.
|
131
|
+
def enq(*inputs)
|
132
|
+
batch.each do |executable|
|
133
|
+
executable.unbatched_enq(*inputs)
|
134
|
+
end
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Like enq, but only enques self.
|
139
|
+
def unbatched_enq(*inputs)
|
140
|
+
app.queue.enq(self, inputs)
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
# Sets a block to receive the results of _execute. Raises an
|
145
|
+
# error if an on_complete block is already set. Override an
|
146
|
+
# existing on_complete block by specifying override = true.
|
37
147
|
#
|
38
148
|
# Note the block recieves an audited result and not
|
39
149
|
# the result itself (see Audit for more information).
|
40
150
|
def on_complete(override=false, &block) # :yields: _result
|
151
|
+
batch.each do |executable|
|
152
|
+
executable.unbatched_on_complete(override, &block)
|
153
|
+
end
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
# Like on_complete, but only sets on_complete_block for self.
|
158
|
+
def unbatched_on_complete(override=false, &block) # :yields: _result
|
41
159
|
unless on_complete_block == nil || override
|
42
160
|
raise "on_complete_block already set: #{self}"
|
43
161
|
end
|
44
162
|
@on_complete_block = block
|
163
|
+
self
|
45
164
|
end
|
46
165
|
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
166
|
+
# Sets a sequence workflow pattern for the tasks; each task will enque
|
167
|
+
# the next task with it's results.
|
168
|
+
#
|
169
|
+
# Notes:
|
170
|
+
# - Batched tasks will have the pattern set for each task in the batch
|
171
|
+
# - The current audited results are yielded to the block, if given,
|
172
|
+
# before the next task is enqued.
|
173
|
+
# - Executables may provided as well as tasks.
|
174
|
+
def sequence(*tasks, &block) # :yields: _result
|
175
|
+
Joins::Sequence.join(self, tasks, &block)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Sets a fork workflow pattern for the source task; each target
|
179
|
+
# will enque the results of source.
|
180
|
+
#
|
181
|
+
# Notes:
|
182
|
+
# - Batched tasks will have the pattern set for each task in the batch
|
183
|
+
# - The current audited results are yielded to the block, if given,
|
184
|
+
# before the next task is enqued.
|
185
|
+
# - Executables may provided as well as tasks.
|
186
|
+
def fork(*targets, &block) # :yields: _result
|
187
|
+
Joins::Fork.join(self, targets, &block)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Sets a simple merge workflow pattern for the source tasks. Each source
|
191
|
+
# enques target with it's result; no synchronization occurs, nor are
|
192
|
+
# results grouped before being sent to the target.
|
193
|
+
#
|
194
|
+
# Notes:
|
195
|
+
# - Batched tasks will have the pattern set for each task in the batch
|
196
|
+
# - The current audited results are yielded to the block, if given,
|
197
|
+
# before the next task is enqued.
|
198
|
+
# - Executables may provided as well as tasks.
|
199
|
+
def merge(*sources, &block) # :yields: _result
|
200
|
+
Joins::Merge.join(self, sources, &block)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Sets a synchronized merge workflow for the source tasks. Results from
|
204
|
+
# each source task are collected and enqued as a single group to the target.
|
205
|
+
# The target is not enqued until all sources have completed. Raises an
|
206
|
+
# error if a source returns twice before the target is enqued.
|
207
|
+
#
|
208
|
+
# Notes:
|
209
|
+
# - Batched tasks will have the pattern set for each task in the batch
|
210
|
+
# - The current audited results are yielded to the block, if given,
|
211
|
+
# before the next task is enqued.
|
212
|
+
# - Executables may provided as well as tasks.
|
213
|
+
#
|
214
|
+
#-- TODO: add notes on testing and the way results are received
|
215
|
+
# (ie as a single object)
|
216
|
+
#
|
217
|
+
# - note stacking with a sync merge is *somewhat* pointless;
|
218
|
+
# it does not change the run order, but of course it does
|
219
|
+
# allow other tasks to be interleaved.
|
220
|
+
#
|
221
|
+
def sync_merge(*sources, &block) # :yields: _result
|
222
|
+
Joins::SyncMerge.join(self, sources, &block)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Sets a choice workflow pattern for the source task. When the
|
226
|
+
# source task completes, switch yields the audited result to the
|
227
|
+
# block which then returns the index of the target to enque with
|
228
|
+
# the results. No target will be enqued if the index is false or
|
229
|
+
# nil; an error is raised if no target can be found for the
|
230
|
+
# specified index.
|
231
|
+
#
|
232
|
+
# Notes:
|
233
|
+
# - Batched tasks will have the pattern set for each task in the batch
|
234
|
+
# - The current audited results are yielded to the block, if given,
|
235
|
+
# before the next task is enqued.
|
236
|
+
# - Executables may provided as well as tasks.
|
237
|
+
def switch(*targets, &block) # :yields: _result
|
238
|
+
Joins::Switch.join(self, targets, &block)
|
239
|
+
end
|
240
|
+
|
241
|
+
def unbatched_depends_on(dependency, *inputs)
|
51
242
|
raise ArgumentError, "not an Executable: #{dependency}" unless dependency.kind_of?(Executable)
|
52
243
|
raise ArgumentError, "cannot depend on self" if dependency == self
|
53
244
|
|
54
|
-
index =
|
245
|
+
index = app.dependencies.register(dependency, inputs)
|
55
246
|
dependencies << index unless dependencies.include?(index)
|
56
247
|
index
|
57
248
|
end
|
58
249
|
|
250
|
+
# Adds the dependency to self, making self dependent on the dependency.
|
251
|
+
# The dependency will be resolved by calling dependency._execute with
|
252
|
+
# the input arguments during resolve_dependencies.
|
253
|
+
def depends_on(dependency, *inputs)
|
254
|
+
index = unbatched_depends_on(dependency, *inputs)
|
255
|
+
batch.each do |e|
|
256
|
+
e.dependencies << index unless e.dependencies.include?(index)
|
257
|
+
end
|
258
|
+
index
|
259
|
+
end
|
260
|
+
|
59
261
|
# Resolves dependencies by calling dependency._execute with
|
60
262
|
# the dependency arguments. (See Dependable#resolve).
|
61
263
|
def resolve_dependencies
|
62
|
-
|
264
|
+
app.dependencies.resolve(dependencies)
|
63
265
|
self
|
64
266
|
end
|
65
267
|
|
66
268
|
# Resets dependencies so they will be re-resolved on resolve_dependencies.
|
67
269
|
# (See Dependable#reset).
|
68
270
|
def reset_dependencies
|
69
|
-
|
271
|
+
app.dependencies.reset(dependencies)
|
70
272
|
self
|
71
273
|
end
|
72
|
-
|
274
|
+
|
73
275
|
# Auditing method call. Executes _method_name for self, but audits
|
74
276
|
# the result. Sends the audited result to the on_complete_block if set.
|
75
277
|
#
|
@@ -110,10 +312,15 @@ module Tap
|
|
110
312
|
end
|
111
313
|
|
112
314
|
audit._record(self, send(_method_name, *inputs))
|
113
|
-
on_complete_block.call(audit)
|
114
|
-
|
315
|
+
on_complete_block ? on_complete_block.call(audit) : app.aggregator.store(audit)
|
316
|
+
|
115
317
|
audit
|
116
318
|
end
|
319
|
+
|
320
|
+
def inspect
|
321
|
+
"#<#{self.class.to_s}:#{object_id} _method: #{_method_name} batch_length: #{batch.length} app: #{app}>"
|
322
|
+
end
|
323
|
+
|
117
324
|
end
|
118
325
|
end
|
119
326
|
end
|
@@ -137,8 +344,8 @@ class Object
|
|
137
344
|
# Initializes a Tap::Support::Executable using the Method returned by
|
138
345
|
# Object#method(method_name), setting the on_complete block as specified.
|
139
346
|
# Returns nil if Object#method returns nil.
|
140
|
-
def _method(method_name,
|
347
|
+
def _method(method_name, app=Tap::App.instance) # :yields: _result
|
141
348
|
return nil unless m = method(method_name)
|
142
|
-
Tap::Support::Executable.initialize(m, :call,
|
349
|
+
Tap::Support::Executable.initialize(m, :call, app)
|
143
350
|
end
|
144
351
|
end
|
@@ -21,8 +21,11 @@ module Tap
|
|
21
21
|
|
22
22
|
attr_accessor :env
|
23
23
|
|
24
|
-
def collect_tasks
|
25
|
-
|
24
|
+
def collect_tasks(*args)
|
25
|
+
# a little song and dance for compliance with
|
26
|
+
# rake pre- and post-0.8.2
|
27
|
+
argv = args.empty? ? ARGV : args[0]
|
28
|
+
argv.collect! do |arg|
|
26
29
|
next(arg) unless arg =~ /^:([a-z_\d]+):(.*)$/
|
27
30
|
env_pattern = $1
|
28
31
|
rake_task = $2
|
@@ -55,7 +58,7 @@ module Tap
|
|
55
58
|
fail "No Rakefile found for '#{env_pattern}' (looking for: #{@rakefiles.join(', ')})"
|
56
59
|
end
|
57
60
|
end
|
58
|
-
|
61
|
+
|
59
62
|
super
|
60
63
|
end
|
61
64
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Tap
|
2
|
+
module Support
|
3
|
+
class Join
|
4
|
+
class << self
|
5
|
+
def join(source, targets, &block)
|
6
|
+
options = targets[-1].kind_of?(Hash) ? targets.pop : {}
|
7
|
+
new(options).join(source, targets, &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
include Configurable
|
12
|
+
|
13
|
+
config :iterate, false, &c.boolean
|
14
|
+
config :stack, false, &c.boolean
|
15
|
+
config :unbatched, false, &c.boolean
|
16
|
+
|
17
|
+
# An array of workflow flags. All workflow flags are false unless specified.
|
18
|
+
FLAGS = configurations.keys
|
19
|
+
|
20
|
+
# An array of the first character in each WORKFLOW_FLAGS.
|
21
|
+
SHORT_FLAGS = FLAGS.collect {|flag| flag.to_s[0,1]}
|
22
|
+
|
23
|
+
def initialize(options)
|
24
|
+
initialize_config(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
self.class.to_s =~ /.*::(.*)$/
|
29
|
+
$1.underscore.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def options
|
33
|
+
opts = config.to_hash
|
34
|
+
opts.delete_if {|key, value| value == false }
|
35
|
+
opts
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
"#<Join:#{object_id}>"
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def complete(executable, &block)
|
45
|
+
executable.send(unbatched ? :unbatched_on_complete : :on_complete, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def enq(executable, _results)
|
49
|
+
app = executable.app
|
50
|
+
|
51
|
+
results = iterate ? _results._expand : [_results]
|
52
|
+
results.each do |_result|
|
53
|
+
if stack
|
54
|
+
|
55
|
+
if unbatched
|
56
|
+
executable.unbatched_enq(_result)
|
57
|
+
else
|
58
|
+
executable.enq(_result)
|
59
|
+
end
|
60
|
+
|
61
|
+
else
|
62
|
+
|
63
|
+
if unbatched
|
64
|
+
app.execute(executable, _result)
|
65
|
+
else
|
66
|
+
executable.batch.each do |e|
|
67
|
+
app.execute(e, _result)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class ReverseJoin < Join
|
77
|
+
def join(target, sources, &block)
|
78
|
+
options = sources[-1].kind_of?(Hash) ? sources.pop : {}
|
79
|
+
new(options).join(target, sources, &block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
"#<ReverseJoin:#{object_id}>"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'tap/support/join'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Support
|
5
|
+
module Joins
|
6
|
+
autoload(:Sequence, 'tap/support/joins/sequence')
|
7
|
+
autoload(:Fork, 'tap/support/joins/fork')
|
8
|
+
autoload(:Merge, 'tap/support/joins/merge')
|
9
|
+
autoload(:SyncMerge, 'tap/support/joins/sync_merge')
|
10
|
+
autoload(:Switch, 'tap/support/joins/switch')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Tap
|
2
|
+
module Support
|
3
|
+
module Joins
|
4
|
+
|
5
|
+
class Fork < Join
|
6
|
+
def join(source, targets)
|
7
|
+
complete(source) do |_result|
|
8
|
+
targets.each do |target|
|
9
|
+
yield(_result) if block_given?
|
10
|
+
enq(target, _result)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|