tap 0.19.0 → 1.3.0

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