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.
Files changed (102) hide show
  1. data/History +34 -0
  2. data/README +62 -41
  3. data/bin/tap +36 -40
  4. data/cmd/console.rb +14 -6
  5. data/cmd/manifest.rb +62 -58
  6. data/cmd/run.rb +49 -31
  7. data/doc/API +84 -0
  8. data/doc/Class Reference +83 -115
  9. data/doc/Examples/Command Line +36 -0
  10. data/doc/Examples/Workflow +40 -0
  11. data/lib/tap/app.rb +293 -214
  12. data/lib/tap/app/node.rb +43 -0
  13. data/lib/tap/app/queue.rb +77 -0
  14. data/lib/tap/app/stack.rb +16 -0
  15. data/lib/tap/app/state.rb +22 -0
  16. data/lib/tap/constants.rb +2 -2
  17. data/lib/tap/env.rb +400 -314
  18. data/lib/tap/env/constant.rb +227 -0
  19. data/lib/tap/env/gems.rb +63 -0
  20. data/lib/tap/env/manifest.rb +89 -0
  21. data/lib/tap/env/minimap.rb +292 -0
  22. data/lib/tap/{support → env}/string_ext.rb +2 -2
  23. data/lib/tap/exe.rb +113 -125
  24. data/lib/tap/join.rb +175 -0
  25. data/lib/tap/joins.rb +9 -0
  26. data/lib/tap/joins/switch.rb +44 -0
  27. data/lib/tap/joins/sync.rb +99 -0
  28. data/lib/tap/root.rb +100 -491
  29. data/lib/tap/root/utils.rb +220 -0
  30. data/lib/tap/{support → root}/versions.rb +31 -29
  31. data/lib/tap/schema.rb +248 -0
  32. data/lib/tap/schema/parser.rb +413 -0
  33. data/lib/tap/schema/utils.rb +82 -0
  34. data/lib/tap/support/intern.rb +19 -6
  35. data/lib/tap/support/templater.rb +8 -3
  36. data/lib/tap/task.rb +175 -171
  37. data/lib/tap/tasks/dump.rb +58 -0
  38. data/lib/tap/tasks/load.rb +62 -0
  39. metadata +30 -73
  40. data/cmd/destroy.rb +0 -27
  41. data/cmd/generate.rb +0 -27
  42. data/doc/Command Reference +0 -105
  43. data/doc/Syntax Reference +0 -234
  44. data/doc/Tutorial +0 -348
  45. data/lib/tap/dump.rb +0 -142
  46. data/lib/tap/file_task.rb +0 -384
  47. data/lib/tap/generator/arguments.rb +0 -13
  48. data/lib/tap/generator/base.rb +0 -176
  49. data/lib/tap/generator/destroy.rb +0 -60
  50. data/lib/tap/generator/generate.rb +0 -93
  51. data/lib/tap/generator/generators/command/command_generator.rb +0 -21
  52. data/lib/tap/generator/generators/command/templates/command.erb +0 -32
  53. data/lib/tap/generator/generators/config/config_generator.rb +0 -98
  54. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -37
  55. data/lib/tap/generator/generators/generator/templates/task.erb +0 -27
  56. data/lib/tap/generator/generators/generator/templates/test.erb +0 -26
  57. data/lib/tap/generator/generators/root/root_generator.rb +0 -84
  58. data/lib/tap/generator/generators/root/templates/MIT-LICENSE +0 -22
  59. data/lib/tap/generator/generators/root/templates/README +0 -14
  60. data/lib/tap/generator/generators/root/templates/Rakefile +0 -84
  61. data/lib/tap/generator/generators/root/templates/Rapfile +0 -11
  62. data/lib/tap/generator/generators/root/templates/gemspec +0 -27
  63. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -3
  64. data/lib/tap/generator/generators/task/task_generator.rb +0 -25
  65. data/lib/tap/generator/generators/task/templates/task.erb +0 -14
  66. data/lib/tap/generator/generators/task/templates/test.erb +0 -19
  67. data/lib/tap/generator/manifest.rb +0 -20
  68. data/lib/tap/generator/preview.rb +0 -69
  69. data/lib/tap/load.rb +0 -64
  70. data/lib/tap/spec.rb +0 -41
  71. data/lib/tap/support/aggregator.rb +0 -65
  72. data/lib/tap/support/audit.rb +0 -333
  73. data/lib/tap/support/constant.rb +0 -143
  74. data/lib/tap/support/constant_manifest.rb +0 -126
  75. data/lib/tap/support/dependencies.rb +0 -54
  76. data/lib/tap/support/dependency.rb +0 -44
  77. data/lib/tap/support/executable.rb +0 -198
  78. data/lib/tap/support/executable_queue.rb +0 -125
  79. data/lib/tap/support/gems.rb +0 -43
  80. data/lib/tap/support/join.rb +0 -144
  81. data/lib/tap/support/joins.rb +0 -12
  82. data/lib/tap/support/joins/switch.rb +0 -27
  83. data/lib/tap/support/joins/sync_merge.rb +0 -38
  84. data/lib/tap/support/manifest.rb +0 -171
  85. data/lib/tap/support/minimap.rb +0 -90
  86. data/lib/tap/support/node.rb +0 -176
  87. data/lib/tap/support/parser.rb +0 -450
  88. data/lib/tap/support/schema.rb +0 -385
  89. data/lib/tap/support/shell_utils.rb +0 -67
  90. data/lib/tap/test.rb +0 -77
  91. data/lib/tap/test/assertions.rb +0 -38
  92. data/lib/tap/test/env_vars.rb +0 -29
  93. data/lib/tap/test/extensions.rb +0 -73
  94. data/lib/tap/test/file_test.rb +0 -362
  95. data/lib/tap/test/file_test_class.rb +0 -15
  96. data/lib/tap/test/regexp_escape.rb +0 -87
  97. data/lib/tap/test/script_test.rb +0 -46
  98. data/lib/tap/test/script_tester.rb +0 -115
  99. data/lib/tap/test/subset_test.rb +0 -260
  100. data/lib/tap/test/subset_test_class.rb +0 -99
  101. data/lib/tap/test/tap_test.rb +0 -109
  102. data/lib/tap/test/utils.rb +0 -231
@@ -1,126 +0,0 @@
1
- require 'tap/support/manifest'
2
- require 'tap/support/constant'
3
-
4
- module Tap
5
- module Support
6
-
7
- # :startdoc:::-
8
- #
9
- # ConstantManifest builds a manifest of Constant entries using Lazydoc.
10
- #
11
- # Lazydoc can quickly scan files for constant attributes, and thereby
12
- # identify constants based upon a flag like the '::manifest' attribute used
13
- # to identify task classes. ConstantManifest registers paths that will be
14
- # scanned for a specific resource, and lazily builds the references to load
15
- # them as necessary.
16
- #
17
- # :startdoc:::+
18
- class ConstantManifest < Support::Manifest
19
-
20
- # The attribute identifying constants in a file
21
- attr_reader :const_attr
22
-
23
- # An array of registered (root, [paths]) pairs
24
- # that will be searched for const_attr
25
- attr_reader :search_paths
26
-
27
- # The current index of search_paths
28
- attr_reader :search_path_index
29
-
30
- # The current index of paths
31
- attr_reader :path_index
32
-
33
- # Initializes a new ConstantManifest that will identify constants
34
- # using the specified constant attribute.
35
- def initialize(const_attr)
36
- @const_attr = const_attr
37
- @search_paths = []
38
- @search_path_index = 0
39
- @path_index = 0
40
- super([])
41
- end
42
-
43
- # Registers the files matching pattern under dir. Returns self.
44
- def register(dir, pattern)
45
- paths = Dir.glob(File.join(dir, pattern)).select {|file| File.file?(file) }
46
- search_paths << [dir, paths.sort]
47
- self
48
- end
49
-
50
- # Searches all paths for entries and adds them to self. Returns self.
51
- def build
52
- each {|entry| } unless built?
53
- self
54
- end
55
-
56
- # True if there are no more paths to search
57
- # (ie search_path_index == search_paths.length)
58
- def built?
59
- search_path_index == search_paths.length
60
- end
61
-
62
- # Sets search_path_index and path_index to zero and clears entries.
63
- # Returns self.
64
- def reset
65
- @search_paths.each {|path| Lazydoc[path].resolved = false }
66
- @entries.clear
67
- @search_path_index = 0
68
- @path_index = 0
69
- super
70
- end
71
-
72
- # Yields each Constant entry to the block. Unless built?, each
73
- # lazily iterates over search_paths to look for new entries.
74
- def each
75
- entries.each do |entry|
76
- yield(entry)
77
- end
78
-
79
- search_paths[search_path_index, search_paths.length - search_path_index].each do |(path_root, paths)|
80
- paths[path_index, paths.length - path_index].each do |path|
81
- new_entries = resolve(path_root, path)
82
- entries.concat(new_entries)
83
-
84
- @path_index += 1
85
- new_entries.each {|entry| yield(entry) }
86
- end
87
-
88
- @search_path_index += 1
89
- @path_index = 0
90
- end unless built?
91
- end
92
-
93
- protected
94
-
95
- def minikey(const) # :nodoc:
96
- const.path
97
- end
98
-
99
- # Scans path for constants having const_attr, and initializes Constant
100
- # objects for each. If the document has no default_const_name set,
101
- # resolve will set the default_const_name based on the relative
102
- # filepath from path_root to path.
103
- def resolve(path_root, path) # :nodoc:
104
- entries = []
105
- document = nil
106
-
107
- Lazydoc::Document.scan(File.read(path), const_attr) do |const_name, key, value|
108
- if document == nil
109
- relative_path = Root.relative_filepath(path_root, path).chomp(File.extname(path))
110
- document = Lazydoc.register_file(path, relative_path.camelize)
111
- end
112
-
113
- const_name = document.default_const_name if const_name.empty?
114
- comment = Lazydoc::Subject.new(nil, document)
115
- comment.value = value
116
-
117
- document[const_name][key] = comment
118
- entries << Constant.new(const_name, path)
119
- end
120
-
121
- entries
122
- end
123
-
124
- end
125
- end
126
- end
@@ -1,54 +0,0 @@
1
- require 'tap/support/dependency'
2
-
3
- module Tap
4
- module Support
5
-
6
- # Dependencies tracks Executable dependencies and results, and provides
7
- # for thread-safe resolution of dependencies.
8
- class Dependencies < Monitor
9
-
10
- # Initializes a new Dependencies
11
- def initialize
12
- super
13
- @resolve_stack = []
14
- end
15
-
16
- # Thread-safe registration of instance as a dependency. During
17
- # registration, instance is extended with the Dependency module.
18
- # Returns self.
19
- def register(instance)
20
- synchronize do
21
- unless instance.kind_of?(Dependency)
22
- instance.extend Dependency
23
- end
24
- end
25
- self
26
- end
27
-
28
- # Thread-safe resolution of the instance. Resolve checks for
29
- # circular dependencies, then yields control to the block,
30
- # which is responsible for the actual resolution.
31
- def resolve(instance)
32
- synchronize do
33
- if @resolve_stack.include?(instance)
34
- raise CircularDependencyError.new(@resolve_stack)
35
- end
36
-
37
- # mark the results at the index to prevent
38
- # infinite loops with circular dependencies
39
- @resolve_stack.push instance
40
- yield()
41
- @resolve_stack.pop
42
- end
43
- self
44
- end
45
-
46
- # Raised when Dependencies#resolve detects a circular dependency.
47
- class CircularDependencyError < StandardError
48
- def initialize(resolve_stack)
49
- super "circular dependency: [#{resolve_stack.join(', ')}]"
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,44 +0,0 @@
1
- module Tap
2
- module Support
3
-
4
- # Constrains an Executable to only _execute once, and provides several
5
- # methods making the Executable behave like a Dependency.
6
- module Dependency
7
-
8
- # The audited result of self
9
- attr_accessor :_result
10
-
11
- def self.extended(base) # :nodoc:
12
- base.instance_variable_set(:@_result, nil)
13
- end
14
-
15
- # Conditional _execute; only calls method_name if
16
- # resolved? is false (thus assuring self will only
17
- # be executed once).
18
- #
19
- # Returns _result.
20
- def _execute(*args)
21
- app.dependencies.resolve(self) do
22
- @_result = super
23
- end unless resolved?
24
- _result
25
- end
26
-
27
- # Alias for _execute().
28
- def resolve
29
- _execute
30
- end
31
-
32
- # True if _result is non-nil.
33
- def resolved?
34
- @_result != nil
35
- end
36
-
37
- # Resets the dependency by setting _result to nil.
38
- def reset
39
- @_result = nil
40
- end
41
-
42
- end
43
- end
44
- end
@@ -1,198 +0,0 @@
1
- require 'tap/support/audit'
2
- require 'tap/support/joins'
3
-
4
- module Tap
5
- module Support
6
-
7
- # Executable wraps objects to make them executable by App.
8
- module Executable
9
-
10
- # The App receiving self during enq
11
- attr_reader :app
12
-
13
- # The method called during _execute
14
- attr_reader :method_name
15
-
16
- # The block called when _execute completes
17
- attr_reader :on_complete_block
18
-
19
- # An array of dependency indicies that will be resolved on _execute
20
- attr_reader :dependencies
21
-
22
- public
23
-
24
- # Extends obj with Executable and sets up all required variables. The
25
- # specified method will be called on _execute.
26
- def self.initialize(obj, method_name, app=App.instance, dependencies=[], &on_complete_block)
27
- obj.extend Executable
28
- obj.instance_variable_set(:@app, app)
29
- obj.instance_variable_set(:@method_name, method_name)
30
- obj.instance_variable_set(:@on_complete_block, on_complete_block)
31
- obj.instance_variable_set(:@dependencies, dependencies)
32
- obj
33
- end
34
-
35
- # Enqueues self to app with the inputs. The number of inputs provided
36
- # should match the number of inputs for the method_name method.
37
- def enq(*inputs)
38
- app.queue.enq(self, inputs)
39
- self
40
- end
41
-
42
- # Sets a block to receive the results of _execute. Raises an error if
43
- # an on_complete_block is already set. Override the existing
44
- # on_complete_block by specifying override = true.
45
- #
46
- # Note: the block recieves an audited result and not the result
47
- # itself (see Audit for more information).
48
- def on_complete(override=false, &block) # :yields: _result
49
- unless on_complete_block == nil || override
50
- raise "on_complete_block already set: #{self}"
51
- end
52
- @on_complete_block = block
53
- self
54
- end
55
-
56
- # Sets a sequence workflow pattern for the tasks; each task
57
- # enques the next task with it's results, starting with self.
58
- def sequence(*tasks, &block) # :yields: _result
59
- options = tasks[-1].kind_of?(Hash) ? tasks.pop : {}
60
-
61
- current_task = self
62
- tasks.each do |next_task|
63
- Join.new(options).join([current_task], [next_task], &block)
64
- current_task = next_task
65
- end
66
- end
67
-
68
- # Sets a fork workflow pattern for self; each target will enque the
69
- # results of self.
70
- def fork(*targets, &block) # :yields: _result
71
- options = targets[-1].kind_of?(Hash) ? targets.pop : {}
72
- Join.new(options).join([self], targets, &block)
73
- end
74
-
75
- # Sets a simple merge workflow pattern for the source tasks. Each
76
- # source enques self with it's result; no synchronization occurs,
77
- # nor are results grouped before being enqued.
78
- def merge(*sources, &block) # :yields: _result
79
- options = sources[-1].kind_of?(Hash) ? sources.pop : {}
80
- Join.new(options).join(sources, [self], &block)
81
- end
82
-
83
- # Sets a synchronized merge workflow for the source tasks. Results
84
- # from each source are collected and enqued as a single group to
85
- # self. The collective results are not enqued until all sources
86
- # have completed. See Joins::SyncMerge.
87
- def sync_merge(*sources, &block) # :yields: _result
88
- options = sources[-1].kind_of?(Hash) ? sources.pop : {}
89
- Joins::SyncMerge.new(options).join(sources, [self], &block)
90
- end
91
-
92
- # Sets a switch workflow pattern for self. On complete, switch yields
93
- # the audited result to the block and the block should return the index
94
- # of the target to enque with the results. No target will be enqued if
95
- # the index is false or nil. An error is raised if no target can be
96
- # found for the specified index. See Joins::Switch.
97
- def switch(*targets, &block) # :yields: _result
98
- options = targets[-1].kind_of?(Hash) ? targets.pop : {}
99
- Joins::Switch.new(options).join([self], targets, &block)
100
- end
101
-
102
- # Adds the dependencies to self. Dependencies are resolved during
103
- # _execute through resolve_dependencies.
104
- def depends_on(*dependencies)
105
- raise ArgumentError, "cannot depend on self" if dependencies.include?(self)
106
-
107
- dependencies.each do |dependency|
108
- app.dependencies.register(dependency)
109
- self.dependencies << dependency unless self.dependencies.include?(dependency)
110
- end
111
-
112
- self
113
- end
114
-
115
- # Resolves dependencies. (See Dependency#resolve).
116
- def resolve_dependencies
117
- dependencies.each {|dependency| dependency.resolve }
118
- self
119
- end
120
-
121
- # Resets dependencies so they will be re-resolved on
122
- # resolve_dependencies. (See Dependency#reset).
123
- def reset_dependencies
124
- dependencies.each {|dependency| dependency.reset }
125
- self
126
- end
127
-
128
- # Auditing method call. Resolves dependencies, executes method_name,
129
- # and sends the audited result to the on_complete_block (if set).
130
- #
131
- # Returns the audited result.
132
- def _execute(*inputs)
133
- resolve_dependencies
134
-
135
- previous = []
136
- inputs.collect! do |input|
137
- if input.kind_of?(Audit)
138
- previous << input
139
- input.value
140
- else
141
- previous << Audit.new(nil, input)
142
- input
143
- end
144
- end
145
-
146
- audit = Audit.new(self, send(method_name, *inputs), app.audit ? previous : nil)
147
- if complete_block = on_complete_block || app.on_complete_block
148
- complete_block.call(audit)
149
- else
150
- app.aggregator.store(audit)
151
- end
152
-
153
- audit
154
- end
155
-
156
- # Calls _execute with the inputs and returns the non-audited result.
157
- def execute(*inputs)
158
- _execute(*inputs).value
159
- end
160
-
161
- # Raises a TerminateError if app.state == State::TERMINATE.
162
- # check_terminate may be called at any time to provide a
163
- # breakpoint in long-running processes.
164
- def check_terminate
165
- if app.state == App::State::TERMINATE
166
- raise App::TerminateError.new
167
- end
168
- end
169
-
170
- end
171
- end
172
- end
173
-
174
- # Tap extends Object with <tt>_method</tt> to generate executable methods
175
- # that can be enqued by Tap::App and incorporated into workflows.
176
- #
177
- # array = []
178
- # push_to_array = array._method(:push)
179
- #
180
- # task = Tap::Task.new
181
- # task.sequence(push_to_array)
182
- #
183
- # task.enq(1).enq(2,3)
184
- # task.app.run
185
- #
186
- # array # => [[1],[2,3]]
187
- #
188
- class Object
189
-
190
- # Initializes a Tap::Support::Executable using the object returned by
191
- # Object#method(method_name).
192
- #
193
- # Returns nil if Object#method returns nil.
194
- def _method(method_name, app=Tap::App.instance)
195
- return nil unless m = method(method_name)
196
- Tap::Support::Executable.initialize(m, :call, app)
197
- end
198
- end
@@ -1,125 +0,0 @@
1
- require 'tap/support/executable'
2
-
3
- module Tap
4
- module Support
5
-
6
- # ExecutableQueue allows thread-safe enqueing and dequeing of Executable
7
- # methods and inputs for execution.
8
- class ExecutableQueue < Monitor
9
-
10
- # Creates a new ExecutableQueue
11
- def initialize
12
- super
13
- @rounds = [[]]
14
- end
15
-
16
- # Clears self and returns an array of the enqueued methods and inputs,
17
- # organized by round.
18
- def clear
19
- synchronize do
20
- current, @rounds = @rounds, [[]]
21
- current
22
- end
23
- end
24
-
25
- # Returns the number of enqueued methods
26
- def size
27
- synchronize do
28
- size = 0
29
- @rounds.each {|round| size += round.length }
30
- size
31
- end
32
- end
33
-
34
- # True if no methods are enqueued
35
- def empty?
36
- synchronize { size == 0 }
37
- end
38
-
39
- def has?(entry)
40
- synchronize do
41
- entry_id = entry.object_id
42
-
43
- @rounds.each do |round|
44
- round.each do |enqued_entry|
45
- return true if entry_id == enqued_entry.object_id
46
- end
47
- end
48
- false
49
- end
50
- end
51
-
52
- # Enqueues the method and inputs. Raises an error if the
53
- # method is not an Executable.
54
- def enq(method, inputs)
55
- synchronize do
56
- check_method(method)
57
- queue.push [method, inputs]
58
- end
59
- end
60
-
61
- # Enqueues the method and inputs, but to the top of the queue.
62
- # Raises an error if the method is not an Executable.
63
- def unshift(method, inputs)
64
- synchronize do
65
- check_method(method)
66
- queue.unshift [method, inputs]
67
- end
68
- end
69
-
70
- # Dequeues the next method and inputs as an array like
71
- # [method, inputs]. Returns nil if the queue is empty.
72
- def deq
73
- synchronize { queue.shift }
74
- end
75
-
76
- # Enques an array of [method, inputs] entries as a round. Rounds are
77
- # dequeued completely before the next round is dequeued.
78
- def concat(round)
79
- synchronize do
80
- round.each do |method, inputs|
81
- check_method(method)
82
- end
83
-
84
- @rounds << round
85
- end
86
- end
87
-
88
- # Converts self to an array. If flatten is specified, all rounds are
89
- # concatenated into a single array.
90
- def to_a(flatten=true)
91
- synchronize do
92
- if flatten
93
- array = []
94
- @rounds.each {|round| array.concat(round) }
95
- array
96
- else
97
- @rounds.collect {|round| round.dup}
98
- end
99
- end
100
- end
101
-
102
- protected
103
-
104
- # Returns the active round.
105
- def queue # :nodoc:
106
- while @rounds.length > 1
107
- queue = @rounds[0]
108
-
109
- if queue.empty?
110
- @rounds.shift
111
- else
112
- return queue
113
- end
114
- end
115
-
116
- @rounds[0]
117
- end
118
-
119
- # Checks if the input method is extended with Executable
120
- def check_method(method) # :nodoc:
121
- raise "not executable: #{method.inspect}" unless method.kind_of?(Executable)
122
- end
123
- end
124
- end
125
- end