tap 0.19.0 → 1.3.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 (66) hide show
  1. data/History +100 -45
  2. data/MIT-LICENSE +1 -1
  3. data/README +95 -51
  4. data/bin/tap +11 -57
  5. data/bin/tapexe +84 -0
  6. data/doc/API +91 -139
  7. data/doc/Configuration +93 -0
  8. data/doc/Examples/Command Line +10 -42
  9. data/doc/Examples/Tapfile +124 -0
  10. data/doc/Ruby to Ruby +87 -0
  11. data/doc/Workflow Syntax +185 -0
  12. data/lib/tap.rb +74 -5
  13. data/lib/tap/app.rb +217 -310
  14. data/lib/tap/app/api.rb +44 -23
  15. data/lib/tap/app/queue.rb +11 -12
  16. data/lib/tap/app/stack.rb +4 -4
  17. data/lib/tap/declarations.rb +200 -0
  18. data/lib/tap/declarations/context.rb +31 -0
  19. data/lib/tap/declarations/description.rb +33 -0
  20. data/lib/tap/env.rb +133 -779
  21. data/lib/tap/env/cache.rb +87 -0
  22. data/lib/tap/env/constant.rb +94 -39
  23. data/lib/tap/env/path.rb +71 -0
  24. data/lib/tap/join.rb +42 -78
  25. data/lib/tap/joins/gate.rb +85 -0
  26. data/lib/tap/joins/switch.rb +4 -2
  27. data/lib/tap/joins/sync.rb +3 -3
  28. data/lib/tap/middleware.rb +5 -5
  29. data/lib/tap/middlewares/debugger.rb +18 -58
  30. data/lib/tap/parser.rb +115 -183
  31. data/lib/tap/root.rb +162 -239
  32. data/lib/tap/signal.rb +72 -0
  33. data/lib/tap/signals.rb +20 -2
  34. data/lib/tap/signals/class_methods.rb +38 -43
  35. data/lib/tap/signals/configure.rb +19 -0
  36. data/lib/tap/signals/help.rb +5 -7
  37. data/lib/tap/signals/load.rb +49 -0
  38. data/lib/tap/signals/module_methods.rb +1 -0
  39. data/lib/tap/task.rb +46 -275
  40. data/lib/tap/tasks/dump.rb +21 -16
  41. data/lib/tap/tasks/list.rb +184 -0
  42. data/lib/tap/tasks/load.rb +4 -4
  43. data/lib/tap/tasks/prompt.rb +128 -0
  44. data/lib/tap/tasks/signal.rb +42 -0
  45. data/lib/tap/tasks/singleton.rb +35 -0
  46. data/lib/tap/tasks/stream.rb +64 -0
  47. data/lib/tap/utils.rb +83 -0
  48. data/lib/tap/version.rb +2 -2
  49. data/lib/tap/workflow.rb +124 -0
  50. data/tap.yml +0 -0
  51. metadata +59 -24
  52. data/cmd/console.rb +0 -43
  53. data/cmd/manifest.rb +0 -118
  54. data/cmd/run.rb +0 -145
  55. data/doc/Examples/Workflow +0 -40
  56. data/lib/tap/app/node.rb +0 -29
  57. data/lib/tap/env/context.rb +0 -61
  58. data/lib/tap/env/gems.rb +0 -63
  59. data/lib/tap/env/manifest.rb +0 -179
  60. data/lib/tap/env/minimap.rb +0 -308
  61. data/lib/tap/intern.rb +0 -50
  62. data/lib/tap/joins.rb +0 -9
  63. data/lib/tap/prompt.rb +0 -36
  64. data/lib/tap/root/utils.rb +0 -220
  65. data/lib/tap/root/versions.rb +0 -138
  66. data/lib/tap/signals/signal.rb +0 -68
@@ -1,179 +0,0 @@
1
- require 'tap/env/minimap'
2
-
3
- module Tap
4
- class Env
5
-
6
- # Manifests provide concise access to resources within a nested Env.
7
- class Manifest
8
- class << self
9
-
10
- # Interns a new Manifest using the block as the builder.
11
- def intern(env, cache={}, &block)
12
- new(env, block, cache)
13
- end
14
- end
15
-
16
- include Enumerable
17
-
18
- # Matches a compound registry search key. After the match, if the key is
19
- # compound then:
20
- #
21
- # $1:: env_key
22
- # $2:: key
23
- #
24
- # If the key is not compound, $2 is nil and $1 is the key.
25
- COMPOUND_KEY = /^((?:[A-z]:(?:\/|\\))?.*?)(?::(.*))?$/
26
-
27
- # The default summary template
28
- DEFAULT_TEMPLATE = %q{<% if !minimap.empty? && count > 1 %>
29
- <%= env_key %>:
30
- <% end %>
31
- <% minimap.each do |key, entry| %>
32
- <%= key.ljust(width) %> # <%= entry %>
33
- <% end %>
34
- }
35
-
36
- # The Env queried for manifest data
37
- attr_reader :env
38
-
39
- # An object that responds to call, typically a block, that recieves
40
- # an env and returns an array of resources, each of which must be
41
- # minimappable. Alternatively, the builder may return a Minimap.
42
- attr_reader :builder
43
-
44
- # A cache of (dir, [entries]) pairs mapping the root of an env
45
- # to the array of resources associated with the env.
46
- attr_reader :cache
47
-
48
- def initialize(env, builder, cache={})
49
- @env = env
50
- @builder = builder
51
- @cache = cache
52
-
53
- cache.each_value do |value|
54
- ensure_minimap(value)
55
- end
56
- end
57
-
58
- # Builds the manifest for each env in env.
59
- def build
60
- self.env.each {|env| entries(env) }
61
- self
62
- end
63
-
64
- # Returns the entries associated with env. If no entries are currently
65
- # registered to env, the env is passed to the builder and the results
66
- # stored in the cache.
67
- def entries(env)
68
- cache[env] ||= begin
69
- ensure_minimap builder.call(env)
70
- end
71
- end
72
-
73
- # Yields each entry for each env to the block.
74
- def each
75
- self.env.each do |env|
76
- entries(env).each do |entry|
77
- yield(entry)
78
- end
79
- end
80
- end
81
-
82
- # Searches for the first entry mini-matching the key. A single env can
83
- # be specified by using a compound key like 'env_key:key'.
84
- #
85
- # If a block is provided, each matching entry is yielded until the
86
- # block returns true. Set env_also to true to return an array like
87
- # [env, entry], where env is the env where the entry was found.
88
- #
89
- # Returns nil if no matching entry is found.
90
- def seek(key, env_also=false)
91
- key =~ COMPOUND_KEY
92
- envs = if $2
93
- # compound key, match for env
94
- key = $2
95
- [env.minimatch($1)].compact
96
- else
97
- # not a compound key, search all envs by iterating env
98
- env
99
- end
100
-
101
- # traverse envs looking for the first
102
- # manifest entry matching key
103
- envs.each do |env|
104
- if entry = entries(env).minimatch(key)
105
- next if block_given? && !yield(entry)
106
- return env_also ? [env, entry] : entry
107
- end
108
- end
109
-
110
- nil
111
- end
112
-
113
- # Unseek looks up the key identifying a specific entry. The entry is
114
- # identified by the block, which receives each entry (in order) until
115
- # the block returns true. Returns nil if no entry returns true.
116
- #
117
- # The env key will be prepended to the result if env_also is set to true.
118
- def unseek(env_also=false)
119
- self.env.each do |env|
120
- objects = entries(env)
121
- if value = objects.find {|entry| yield(entry) }
122
- key = objects.minihash(true)[value]
123
- return env_also ? "#{env.minihash(true)[env]}:#{key}" : key
124
- end
125
- end
126
-
127
- nil
128
- end
129
-
130
- # Generates a summary of the entries in self. Summarize uses the inspect
131
- # functionality of Env to format the entries for each env in order; the
132
- # results are concatenated.
133
- #
134
- # The template should be ERB; it will have the following local variables:
135
- #
136
- # env the current env being summarized
137
- # minimap an array of [key, entry] pairs representing
138
- # the minipaths and entries for the env
139
- # width the maximum width of any key across all envs
140
- # count the number of envs with at least one entry
141
- #
142
- # A block may be given to filter and pre-process minimap entries. Each
143
- # (key, entry) pair will be yielded to the block; the block return
144
- # replaces the entry and any pairs that return nil are removed.
145
- #
146
- def summarize(template=DEFAULT_TEMPLATE)
147
- env.inspect(template, :width => 11, :count => 0) do |templater, globals|
148
- width = globals[:width]
149
-
150
- minimap = entries(templater.env).minimap
151
-
152
- if block_given?
153
- minimap.collect! do |key, entry|
154
- entry = yield(entry)
155
- entry ? [key, entry] : nil
156
- end
157
- minimap.compact!
158
- end
159
-
160
- minimap.each do |key, entry|
161
- width = key.length if width < key.length
162
- end
163
-
164
- globals[:width] = width
165
- globals[:count] += 1 unless minimap.empty?
166
-
167
- templater.minimap = minimap
168
- end
169
- end
170
-
171
- private
172
-
173
- # helper to make obj into a minimap if necessary
174
- def ensure_minimap(obj) # :nodoc:
175
- obj.kind_of?(Minimap) ? obj : obj.extend(Minimap)
176
- end
177
- end
178
- end
179
- end
@@ -1,308 +0,0 @@
1
- module Tap
2
- class Env
3
-
4
- # Minimap adds minimization and search methods to an array of paths. The
5
- # minimized paths are refered to as 'minipaths' and represent the shortest
6
- # basename that uniquely identifies a path within a collection of paths.
7
- # File extensions and versions are removed when possible.
8
- #
9
- # paths = %w{
10
- # path/to/file-0.1.0.txt
11
- # path/to/file-0.2.0.txt
12
- # path/to/another_file.txt
13
- # }
14
- # paths.extend Env::Minimap
15
- #
16
- # paths.minimap
17
- # # => [
18
- # # ['file-0.1.0', 'path/to/file-0.1.0.txt'],
19
- # # ['file-0.2.0', 'path/to/file-0.2.0.txt'],
20
- # # ['another_file','path/to/another_file.txt']]
21
- #
22
- # Minipaths can be used as keys to uniquely match a path. Longer, more
23
- # complete paths may also be used (they add specificity, even though it
24
- # is not needed). Likewise shorter paths may be used; the minimatch
25
- # method returns the first matching path.
26
- #
27
- # paths.minimatch('file') # => 'path/to/file-0.1.0.txt'
28
- # paths.minimatch('file-0.2.0') # => 'path/to/file-0.2.0.txt'
29
- # paths.minimatch('to/another_file') # => 'path/to/another_file.txt'
30
- #
31
- # === Usage
32
- #
33
- # Minimap may extend any object responding to each, or be included in
34
- # classes that implement each. Non-string entries are converted to paths
35
- # by calling entry.path, if entry responds to path, or entry.to_s if it
36
- # does not. Override the entry_to_path method to change this default
37
- # behavior.
38
- #
39
- # class ConstantMap < Array
40
- # include Env::Minimap
41
- #
42
- # def entry_to_path(const)
43
- # const.underscore
44
- # end
45
- # end
46
- #
47
- # constants = ConstantMap[Tap::Env::Minimap, Tap::Env]
48
- # constants.minimatch('env') # => Tap::Env
49
- # constants.minimatch('minimap') # => Tap::Env::Minimap
50
- #
51
- module Minimap
52
-
53
- # Determines the minipaths for each entry in self and returns a mapping
54
- # of the minipaths to their corresponding entry.
55
- #
56
- # paths = %w{
57
- # path/to/file-0.1.0.txt
58
- # path/to/file-0.2.0.txt
59
- # path/to/another_file.txt
60
- # }.extend Minimap
61
- #
62
- # paths.minimap
63
- # # => [
64
- # # ['file-0.1.0', 'path/to/file-0.1.0.txt'],
65
- # # ['file-0.2.0', 'path/to/file-0.2.0.txt'],
66
- # # ['another_file','path/to/another_file.txt']]
67
- #
68
- def minimap
69
- hash = {}
70
- map = []
71
- each {|entry| map << (hash[entry_to_path(entry)] = [entry]) }
72
- minimize(hash.keys) do |key, mini_key|
73
- hash[key].unshift mini_key
74
- end
75
-
76
- map
77
- end
78
-
79
- # Returns the first entry that mini-matches the input, or nil if no such
80
- # entry exists.
81
- #
82
- # paths = %w{
83
- # path/to/file-0.1.0.txt
84
- # path/to/file-0.2.0.txt
85
- # path/to/another_file.txt
86
- # }.extend Minimap
87
- #
88
- # paths.minimatch('file-0.2.0') # => 'path/to/file-0.2.0.txt'
89
- # paths.minimatch('file-0.3.0') # => nil
90
- #
91
- def minimatch(key)
92
- key = key.to_s
93
- each do |entry|
94
- return entry if minimal_match?(entry_to_path(entry), key)
95
- end
96
- nil
97
- end
98
-
99
- # Returns minimap as a hash of (minipath, value) pairs.
100
- def minihash(reverse=false)
101
- hash = {}
102
- minimap.each do |key, value|
103
- if reverse
104
- hash[value] = key
105
- else
106
- hash[key] = value
107
- end
108
- end
109
- hash
110
- end
111
-
112
- protected
113
-
114
- # A hook to convert entries to paths. Returns entry.to_s by default,
115
- # or entry.path if the entry responds to path.
116
- def entry_to_path(entry)
117
- entry.respond_to?(:path) ? entry.path : entry.to_s
118
- end
119
-
120
- module_function
121
-
122
- # Determines the shortest basepaths that unqiuely identifies a path
123
- # within a collection of paths. The path extension and versions are
124
- # removed from the basepath if possible. For example:
125
- #
126
- # Minimap.minimize ['path/to/a.rb', 'path/to/b.rb']
127
- # # => ['a', 'b']
128
- #
129
- # Minimap.minimize ['path/to/a-0.1.0.rb', 'path/to/b-0.1.0.rb']
130
- # # => ['a', 'b']
131
- #
132
- # Minimap.minimize ['path/to/file.rb', 'path/to/file.txt']
133
- # # => ['file.rb', 'file.txt']
134
- #
135
- # Minimap.minimize ['path-0.1/to/file.rb', 'path-0.2/to/file.rb']
136
- # # => ['path-0.1/to/file', 'path-0.2/to/file']
137
- #
138
- # Minimized paths that carry their extension will always carry
139
- # their version as well, but the converse is not true; paths
140
- # can be minimized to carry just the version and not the path
141
- # extension.
142
- #
143
- # Minimap.minimize ['path/to/a-0.1.0.rb', 'path/to/a-0.1.0.txt']
144
- # # => ['a-0.1.0.rb', 'a-0.1.0.txt']
145
- #
146
- # Minimap.minimize ['path/to/a-0.1.0.rb', 'path/to/a-0.2.0.rb']
147
- # # => ['a-0.1.0', 'a-0.2.0']
148
- #
149
- # If a block is given, each (path, minipath) pair will be passed
150
- # to it after minimization.
151
- def minimize(paths) # :yields: path, minipath
152
- unless block_given?
153
- minipaths = []
154
- minimize(paths) {|path, minipath| minipaths << minipath }
155
- return minipaths
156
- end
157
-
158
- splits = paths.uniq.collect do |path|
159
- extname = File.extname(path)
160
- extname = '' if extname =~ /^\.\d+$/
161
- base = File.basename(path.chomp(extname))
162
- version = base =~ /(-\d+(\.\d+)*)$/ ? $1 : ''
163
-
164
- [dirname_or_array(path), base.chomp(version), extname, version, false, path]
165
- end
166
-
167
- while !splits.empty?
168
- index = 0
169
- splits = splits.collect do |(dir, base, extname, version, flagged, path)|
170
- index += 1
171
- case
172
- when !flagged && just_one?(splits, index, base)
173
-
174
- # found just one
175
- yield(path, base)
176
- nil
177
- when dir.kind_of?(Array)
178
-
179
- # no more path segments to use, try to add
180
- # back version and extname
181
- if dir.empty?
182
- dir << File.dirname(base)
183
- base = File.basename(base)
184
- end
185
-
186
- case
187
- when !version.empty?
188
- # add back version (occurs first)
189
- [dir, "#{base}#{version}", extname, '', false, path]
190
-
191
- when !extname.empty?
192
-
193
- # add back extension (occurs second)
194
- [dir, "#{base}#{extname}", '', version, false, path]
195
- else
196
-
197
- # nothing more to distinguish... path is minimized (occurs third)
198
- yield(path, min_join(dir[0], base))
199
- nil
200
- end
201
- else
202
-
203
- # shift path segment. dirname_or_array returns an
204
- # array if this is the last path segment to shift.
205
- [dirname_or_array(dir), min_join(File.basename(dir), base), extname, version, false, path]
206
- end
207
- end.compact
208
- end
209
- end
210
-
211
- # Returns true if the minipath matches path. Matching logic reverses
212
- # that of minimize:
213
- #
214
- # * a match occurs when path ends with minipath
215
- # * if minipath doesn't specify an extension, then minipath
216
- # must only match path up to the path extension
217
- # * if minipath doesn't specify a version, then minipath
218
- # must only match path up to the path basename (minus the
219
- # version and extname)
220
- #
221
- # For example:
222
- #
223
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'file') # => true
224
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'dir/file') # => true
225
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'file-0.1.0') # => true
226
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'file-0.1.0.rb') # => true
227
- #
228
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'file.rb') # => false
229
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'file-0.2.0') # => false
230
- # Minimap.minimal_match?('dir/file-0.1.0.rb', 'another') # => false
231
- #
232
- # In matching, partial basenames are not allowed but partial directories
233
- # are allowed. Hence:
234
- #
235
- # Minimap.minimal_match?('dir/file-0.1.0.txt', 'file') # => true
236
- # Minimap.minimal_match?('dir/file-0.1.0.txt', 'ile') # => false
237
- # Minimap.minimal_match?('dir/file-0.1.0.txt', 'r/file') # => true
238
- #
239
- def minimal_match?(path, minipath)
240
- extname = non_version_extname(minipath)
241
- version = minipath =~ /(-\d+(\.\d+)*)#{extname}$/ ? $1 : ''
242
-
243
- path = case
244
- when !extname.empty?
245
- # force full match
246
- path
247
- when !version.empty?
248
- # match up to version
249
- path.chomp(non_version_extname(path))
250
- else
251
- # match up to base
252
- path.chomp(non_version_extname(path)).sub(/(-\d+(\.\d+)*)$/, '')
253
- end
254
-
255
- # match if path ends with minipath. note the basename check ensures a full
256
- # path segment has been specified. (ex: 'ile' should not match 'file.txt')
257
- path[-minipath.length, minipath.length] == minipath && File.basename(path) == File.basename(minipath)
258
- end
259
-
260
- # utility method for minimize -- joins the
261
- # dir and path, preventing results like:
262
- #
263
- # "./path"
264
- # "//path"
265
- #
266
- def min_join(dir, path) # :nodoc:
267
- case dir
268
- when "." then path
269
- when "/" then "/#{path}"
270
- else "#{dir}/#{path}"
271
- end
272
- end
273
-
274
- # utility method for minimize -- returns the
275
- # dirname of path, or an array if the dirname
276
- # is effectively empty.
277
- def dirname_or_array(path) # :nodoc:
278
- dir = File.dirname(path)
279
- case dir
280
- when path, '.' then []
281
- else dir
282
- end
283
- end
284
-
285
- # utility method for minimize -- determines if there
286
- # is just one of the base in splits, while flagging
287
- # all matching entries.
288
- def just_one?(splits, index, base) # :nodoc:
289
- just_one = true
290
- index.upto(splits.length-1) do |i|
291
- if splits[i][1] == base
292
- splits[i][4] = true
293
- just_one = false
294
- end
295
- end
296
-
297
- just_one
298
- end
299
-
300
- # utility method for minimal_match -- returns a non-version
301
- # extname, or an empty string if the path ends in a version.
302
- def non_version_extname(path) # :nodoc:
303
- extname = File.extname(path)
304
- extname =~ /^\.\d+$/ ? '' : extname
305
- end
306
- end
307
- end
308
- end