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.
Files changed (59) hide show
  1. data/bin/rap +13 -5
  2. data/lib/tap.rb +0 -4
  3. data/lib/tap/app.rb +10 -138
  4. data/lib/tap/constants.rb +1 -1
  5. data/lib/tap/declarations.rb +201 -0
  6. data/lib/tap/env.rb +10 -2
  7. data/lib/tap/exe.rb +2 -2
  8. data/lib/tap/generator/generators/root/templates/Rakefile +1 -0
  9. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  10. data/lib/tap/spec.rb +38 -63
  11. data/lib/tap/spec/adapter.rb +8 -31
  12. data/lib/tap/spec/inheritable_class_test_root.rb +9 -0
  13. data/lib/tap/support/audit.rb +0 -2
  14. data/lib/tap/support/combinator.rb +83 -31
  15. data/lib/tap/support/configurable_class.rb +7 -7
  16. data/lib/tap/support/{dependable.rb → dependencies.rb} +9 -7
  17. data/lib/tap/support/executable.rb +226 -19
  18. data/lib/tap/support/gems/rake.rb +6 -3
  19. data/lib/tap/support/join.rb +87 -0
  20. data/lib/tap/support/joins.rb +13 -0
  21. data/lib/tap/support/joins/fork.rb +18 -0
  22. data/lib/tap/support/joins/merge.rb +20 -0
  23. data/lib/tap/support/joins/sequence.rb +21 -0
  24. data/lib/tap/support/joins/switch.rb +23 -0
  25. data/lib/tap/support/joins/sync_merge.rb +57 -0
  26. data/lib/tap/support/lazydoc/document.rb +10 -0
  27. data/lib/tap/support/node.rb +58 -0
  28. data/lib/tap/support/parser.rb +379 -0
  29. data/lib/tap/support/schema.rb +350 -0
  30. data/lib/tap/support/tdoc.rb +5 -0
  31. data/lib/tap/support/validation.rb +2 -0
  32. data/lib/tap/task.rb +26 -61
  33. data/lib/tap/test.rb +9 -82
  34. data/lib/tap/test/assertions.rb +38 -0
  35. data/lib/tap/test/extensions.rb +78 -0
  36. data/lib/tap/test/{file_methods.rb → file_test.rb} +64 -37
  37. data/lib/tap/test/{file_methods_class.rb → file_test_class.rb} +2 -2
  38. data/lib/tap/test/regexp_escape.rb +87 -0
  39. data/lib/tap/test/script_test.rb +46 -0
  40. data/lib/tap/test/script_tester.rb +109 -0
  41. data/lib/tap/test/{subset_methods.rb → subset_test.rb} +9 -9
  42. data/lib/tap/test/{subset_methods_class.rb → subset_test_class.rb} +22 -14
  43. data/lib/tap/test/{tap_methods.rb → tap_test.rb} +43 -6
  44. data/lib/tap/test/utils.rb +6 -3
  45. metadata +27 -24
  46. data/lib/tap/parser.rb +0 -619
  47. data/lib/tap/spec/file_methods.rb +0 -16
  48. data/lib/tap/spec/file_methods_class.rb +0 -13
  49. data/lib/tap/spec/subset_methods.rb +0 -14
  50. data/lib/tap/support/batchable.rb +0 -47
  51. data/lib/tap/support/batchable_class.rb +0 -107
  52. data/lib/tap/support/declarations.rb +0 -131
  53. data/lib/tap/support/lazydoc/declaration.rb +0 -20
  54. data/lib/tap/support/parsers/base.rb +0 -81
  55. data/lib/tap/support/parsers/server.rb +0 -113
  56. data/lib/tap/test/script_methods.rb +0 -75
  57. data/lib/tap/test/script_methods/regexp_escape.rb +0 -94
  58. data/lib/tap/test/script_methods/script_test.rb +0 -109
  59. 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
- extend Dependable
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
- # Sets a block to receive the results of _execute. Raises an error
35
- # if an on_complete block is already set. Override an existing
36
- # on_complete block by specifying override = true.
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
- # Adds the dependency to self, making self dependent on the dependency.
48
- # The dependency will be resolved by calling dependency._execute with
49
- # the input arguments during resolve_dependencies.
50
- def depends_on(dependency, *inputs)
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 = Executable.register(dependency, inputs)
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
- Executable.resolve(dependencies)
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
- Executable.reset(dependencies)
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) if on_complete_block
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, &on_complete_block) # :yields: _result
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, &on_complete_block)
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
- ARGV.collect! do |arg|
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