tap 0.12.4 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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