tap 0.18.0 → 0.19.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.
- data/History +21 -0
- data/MIT-LICENSE +17 -15
- data/README +13 -30
- data/bin/tap +19 -24
- data/cmd/console.rb +1 -12
- data/cmd/manifest.rb +14 -19
- data/cmd/run.rb +96 -86
- data/doc/API +194 -54
- data/doc/Examples/Command Line +27 -1
- data/lib/tap.rb +2 -1
- data/lib/tap/app.rb +613 -166
- data/lib/tap/app/api.rb +115 -0
- data/lib/tap/app/queue.rb +36 -37
- data/lib/tap/app/state.rb +2 -1
- data/lib/tap/env.rb +454 -270
- data/lib/tap/env/constant.rb +83 -33
- data/lib/tap/env/context.rb +61 -0
- data/lib/tap/env/manifest.rb +140 -50
- data/lib/tap/env/minimap.rb +55 -39
- data/lib/tap/join.rb +71 -53
- data/lib/tap/joins/sync.rb +3 -1
- data/lib/tap/middleware.rb +4 -25
- data/lib/tap/middlewares/debugger.rb +75 -0
- data/lib/tap/parser.rb +268 -0
- data/lib/tap/prompt.rb +36 -0
- data/lib/tap/root.rb +3 -3
- data/lib/tap/signals.rb +26 -0
- data/lib/tap/signals/class_methods.rb +222 -0
- data/lib/tap/signals/help.rb +40 -0
- data/lib/tap/signals/module_methods.rb +20 -0
- data/lib/tap/signals/signal.rb +68 -0
- data/lib/tap/task.rb +28 -79
- data/lib/tap/tasks/dump.rb +6 -0
- data/lib/tap/tasks/load.rb +9 -37
- data/lib/tap/templater.rb +12 -1
- data/lib/tap/version.rb +1 -1
- metadata +22 -16
- data/doc/Class Reference +0 -330
- data/lib/tap/exe.rb +0 -130
- data/lib/tap/schema.rb +0 -374
- data/lib/tap/schema/parser.rb +0 -425
- data/lib/tap/schema/utils.rb +0 -56
data/lib/tap/env/minimap.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module Tap
|
2
2
|
class Env
|
3
3
|
|
4
|
-
# Minimap adds minimization and search methods to an array of paths.
|
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.
|
5
8
|
#
|
6
9
|
# paths = %w{
|
7
10
|
# path/to/file-0.1.0.txt
|
@@ -10,20 +13,33 @@ module Tap
|
|
10
13
|
# }
|
11
14
|
# paths.extend Env::Minimap
|
12
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
|
+
#
|
13
27
|
# paths.minimatch('file') # => 'path/to/file-0.1.0.txt'
|
14
28
|
# paths.minimatch('file-0.2.0') # => 'path/to/file-0.2.0.txt'
|
15
|
-
# paths.minimatch('another_file')
|
29
|
+
# paths.minimatch('to/another_file') # => 'path/to/another_file.txt'
|
30
|
+
#
|
31
|
+
# === Usage
|
16
32
|
#
|
17
|
-
#
|
18
|
-
# Non-string entries are
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
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.
|
22
38
|
#
|
23
39
|
# class ConstantMap < Array
|
24
40
|
# include Env::Minimap
|
25
41
|
#
|
26
|
-
# def
|
42
|
+
# def entry_to_path(const)
|
27
43
|
# const.underscore
|
28
44
|
# end
|
29
45
|
# end
|
@@ -34,7 +50,8 @@ module Tap
|
|
34
50
|
#
|
35
51
|
module Minimap
|
36
52
|
|
37
|
-
#
|
53
|
+
# Determines the minipaths for each entry in self and returns a mapping
|
54
|
+
# of the minipaths to their corresponding entry.
|
38
55
|
#
|
39
56
|
# paths = %w{
|
40
57
|
# path/to/file-0.1.0.txt
|
@@ -51,7 +68,7 @@ module Tap
|
|
51
68
|
def minimap
|
52
69
|
hash = {}
|
53
70
|
map = []
|
54
|
-
each {|entry| map << (hash[
|
71
|
+
each {|entry| map << (hash[entry_to_path(entry)] = [entry]) }
|
55
72
|
minimize(hash.keys) do |key, mini_key|
|
56
73
|
hash[key].unshift mini_key
|
57
74
|
end
|
@@ -59,8 +76,8 @@ module Tap
|
|
59
76
|
map
|
60
77
|
end
|
61
78
|
|
62
|
-
# Returns the first entry
|
63
|
-
#
|
79
|
+
# Returns the first entry that mini-matches the input, or nil if no such
|
80
|
+
# entry exists.
|
64
81
|
#
|
65
82
|
# paths = %w{
|
66
83
|
# path/to/file-0.1.0.txt
|
@@ -74,12 +91,12 @@ module Tap
|
|
74
91
|
def minimatch(key)
|
75
92
|
key = key.to_s
|
76
93
|
each do |entry|
|
77
|
-
return entry if minimal_match?(
|
94
|
+
return entry if minimal_match?(entry_to_path(entry), key)
|
78
95
|
end
|
79
96
|
nil
|
80
97
|
end
|
81
98
|
|
82
|
-
# Returns minimap as a hash of (
|
99
|
+
# Returns minimap as a hash of (minipath, value) pairs.
|
83
100
|
def minihash(reverse=false)
|
84
101
|
hash = {}
|
85
102
|
minimap.each do |key, value|
|
@@ -94,17 +111,17 @@ module Tap
|
|
94
111
|
|
95
112
|
protected
|
96
113
|
|
97
|
-
# A hook to convert entries to
|
98
|
-
# or entry.
|
99
|
-
def
|
100
|
-
entry.respond_to?(:
|
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
|
101
118
|
end
|
102
119
|
|
103
120
|
module_function
|
104
121
|
|
105
|
-
#
|
106
|
-
#
|
107
|
-
# the basepath if possible. For example:
|
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:
|
108
125
|
#
|
109
126
|
# Minimap.minimize ['path/to/a.rb', 'path/to/b.rb']
|
110
127
|
# # => ['a', 'b']
|
@@ -129,13 +146,13 @@ module Tap
|
|
129
146
|
# Minimap.minimize ['path/to/a-0.1.0.rb', 'path/to/a-0.2.0.rb']
|
130
147
|
# # => ['a-0.1.0', 'a-0.2.0']
|
131
148
|
#
|
132
|
-
# If a block is given, each (path,
|
149
|
+
# If a block is given, each (path, minipath) pair will be passed
|
133
150
|
# to it after minimization.
|
134
|
-
def minimize(paths) # :yields: path,
|
151
|
+
def minimize(paths) # :yields: path, minipath
|
135
152
|
unless block_given?
|
136
|
-
|
137
|
-
minimize(paths) {|
|
138
|
-
return
|
153
|
+
minipaths = []
|
154
|
+
minimize(paths) {|path, minipath| minipaths << minipath }
|
155
|
+
return minipaths
|
139
156
|
end
|
140
157
|
|
141
158
|
splits = paths.uniq.collect do |path|
|
@@ -191,13 +208,13 @@ module Tap
|
|
191
208
|
end
|
192
209
|
end
|
193
210
|
|
194
|
-
# Returns true if the
|
211
|
+
# Returns true if the minipath matches path. Matching logic reverses
|
195
212
|
# that of minimize:
|
196
213
|
#
|
197
|
-
# * a match occurs when path ends with
|
198
|
-
# * if
|
214
|
+
# * a match occurs when path ends with minipath
|
215
|
+
# * if minipath doesn't specify an extension, then minipath
|
199
216
|
# must only match path up to the path extension
|
200
|
-
# * if
|
217
|
+
# * if minipath doesn't specify a version, then minipath
|
201
218
|
# must only match path up to the path basename (minus the
|
202
219
|
# version and extname)
|
203
220
|
#
|
@@ -219,11 +236,11 @@ module Tap
|
|
219
236
|
# Minimap.minimal_match?('dir/file-0.1.0.txt', 'ile') # => false
|
220
237
|
# Minimap.minimal_match?('dir/file-0.1.0.txt', 'r/file') # => true
|
221
238
|
#
|
222
|
-
def minimal_match?(path,
|
223
|
-
extname = non_version_extname(
|
224
|
-
version =
|
239
|
+
def minimal_match?(path, minipath)
|
240
|
+
extname = non_version_extname(minipath)
|
241
|
+
version = minipath =~ /(-\d+(\.\d+)*)#{extname}$/ ? $1 : ''
|
225
242
|
|
226
|
-
|
243
|
+
path = case
|
227
244
|
when !extname.empty?
|
228
245
|
# force full match
|
229
246
|
path
|
@@ -231,14 +248,13 @@ module Tap
|
|
231
248
|
# match up to version
|
232
249
|
path.chomp(non_version_extname(path))
|
233
250
|
else
|
234
|
-
# match up base
|
251
|
+
# match up to base
|
235
252
|
path.chomp(non_version_extname(path)).sub(/(-\d+(\.\d+)*)$/, '')
|
236
253
|
end
|
237
254
|
|
238
|
-
#
|
239
|
-
#
|
240
|
-
|
241
|
-
match_path[-mini_path.length, mini_path.length] == mini_path && File.basename(match_path) == File.basename(mini_path)
|
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)
|
242
258
|
end
|
243
259
|
|
244
260
|
# utility method for minimize -- joins the
|
data/lib/tap/join.rb
CHANGED
@@ -15,39 +15,8 @@ module Tap
|
|
15
15
|
# results to m outputs. Flags can augment how the results are passed, in
|
16
16
|
# particular for array results.
|
17
17
|
#
|
18
|
-
class Join
|
18
|
+
class Join < App::Api
|
19
19
|
class << self
|
20
|
-
def inherited(child) # :nodoc:
|
21
|
-
unless child.instance_variable_defined?(:@source_file)
|
22
|
-
caller[0] =~ Lazydoc::CALLER_REGEXP
|
23
|
-
child.instance_variable_set(:@source_file, File.expand_path($1))
|
24
|
-
end
|
25
|
-
super
|
26
|
-
end
|
27
|
-
|
28
|
-
# Parses the argv into an instance of self.
|
29
|
-
def parse(argv=ARGV, app=Tap::App.instance)
|
30
|
-
parse!(argv.dup, app)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Same as parse, but removes arguments destructively.
|
34
|
-
def parse!(argv=ARGV, app=Tap::App.instance)
|
35
|
-
opts = ConfigParser.new
|
36
|
-
opts.separator "configurations:"
|
37
|
-
opts.add(configurations)
|
38
|
-
|
39
|
-
args = opts.parse!(argv, :add_defaults => false)
|
40
|
-
|
41
|
-
instantiate({
|
42
|
-
:config => opts.nested_config,
|
43
|
-
:args => args
|
44
|
-
}, app)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Instantiates an instance of self.
|
48
|
-
def instantiate(argh, app=Tap::App.instance)
|
49
|
-
new(argh[:config] || {}, app)
|
50
|
-
end
|
51
20
|
|
52
21
|
# Instantiates a new join with the input arguments and overrides
|
53
22
|
# call with the block. The block will be called with the join
|
@@ -63,23 +32,58 @@ module Tap
|
|
63
32
|
instance
|
64
33
|
end
|
65
34
|
|
35
|
+
def parse!(argv=ARGV, app=Tap::App.instance)
|
36
|
+
parser = self.parser
|
37
|
+
argv = parser.parse!(argv, :add_defaults => false)
|
38
|
+
instance = build({
|
39
|
+
'config' => parser.nested_config,
|
40
|
+
'inputs' => argv.shift,
|
41
|
+
'outputs' => argv.shift
|
42
|
+
}, app)
|
43
|
+
|
44
|
+
[instance, argv]
|
45
|
+
end
|
46
|
+
|
47
|
+
def build(spec={}, app=Tap::App.instance)
|
48
|
+
inputs = resolve(spec['inputs']) do |var|
|
49
|
+
app.get(var) or raise "missing join input: #{var}"
|
50
|
+
end
|
51
|
+
|
52
|
+
outputs = resolve(spec['outputs']) do |var|
|
53
|
+
app.get(var) or raise "missing join output: #{var}"
|
54
|
+
end
|
55
|
+
|
56
|
+
new(spec['config'] || {}, app).join(inputs, outputs)
|
57
|
+
end
|
58
|
+
|
66
59
|
protected
|
67
60
|
|
68
|
-
def
|
69
|
-
case
|
61
|
+
def resolve(refs) # :nodoc:
|
62
|
+
refs = case refs
|
63
|
+
when String then parse_indicies(refs)
|
70
64
|
when nil then []
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
else refs
|
66
|
+
end
|
67
|
+
|
68
|
+
refs.collect! do |var|
|
69
|
+
if var.kind_of?(String)
|
70
|
+
yield(var)
|
71
|
+
else
|
72
|
+
var
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# parses an str along commas, and collects the indicies as integers
|
78
|
+
def parse_indicies(str) # :nodoc:
|
79
|
+
str.split(",").delete_if do |n|
|
80
|
+
n.empty?
|
74
81
|
end
|
75
82
|
end
|
76
83
|
end
|
77
|
-
include Configurable
|
78
84
|
|
79
|
-
|
80
|
-
|
81
|
-
# Causes the targets to be enqued rather than executed immediately.
|
82
|
-
config :enq, false, :short => 'q', &c.flag
|
85
|
+
# Causes the outputs to be enqued rather than executed immediately.
|
86
|
+
config :enq, false, :short => 'q', &c.flag # Enque output nodes
|
83
87
|
|
84
88
|
# Splats the result to the outputs, allowing a many-to-one join
|
85
89
|
# from the perspective of the results.
|
@@ -88,7 +92,7 @@ module Tap
|
|
88
92
|
# # outputs: call(*inputs)
|
89
93
|
# app.execute(output, *result)
|
90
94
|
#
|
91
|
-
config :splat, false, :short => 's', &c.flag
|
95
|
+
config :splat, false, :short => 's', &c.flag # Splat results to outputs
|
92
96
|
|
93
97
|
# Iterates the results to the outputs, allowing a many-to-one join
|
94
98
|
# from the perspective of the results. Non-array results are converted
|
@@ -104,10 +108,21 @@ module Tap
|
|
104
108
|
# # outputs: call(*inputs)
|
105
109
|
# result.to_ary.each {|r| app.execute(output, *r) }
|
106
110
|
#
|
107
|
-
config :iterate, false, :short => 'i', &c.flag
|
111
|
+
config :iterate, false, :short => 'i', &c.flag # Iterate results to outputs
|
108
112
|
|
109
|
-
|
110
|
-
|
113
|
+
signal :join do |sig, (inputs, outputs)|
|
114
|
+
app = sig.obj.app
|
115
|
+
|
116
|
+
inputs = resolve(inputs) do |var|
|
117
|
+
app.get(var) or raise "missing join input: #{var}"
|
118
|
+
end
|
119
|
+
|
120
|
+
outputs = resolve(outputs) do |var|
|
121
|
+
app.get(var) or raise "missing join output: #{var}"
|
122
|
+
end
|
123
|
+
|
124
|
+
[inputs, outputs]
|
125
|
+
end
|
111
126
|
|
112
127
|
# An array of input nodes, or nil if the join has not been set.
|
113
128
|
attr_reader :inputs
|
@@ -117,10 +132,9 @@ module Tap
|
|
117
132
|
|
118
133
|
# Initializes a new join with the specified configuration.
|
119
134
|
def initialize(config={}, app=Tap::App.instance)
|
120
|
-
@app = app
|
121
135
|
@inputs = nil
|
122
136
|
@outputs = nil
|
123
|
-
|
137
|
+
super
|
124
138
|
end
|
125
139
|
|
126
140
|
# Sets self as a join between the inputs and outputs.
|
@@ -147,11 +161,15 @@ module Tap
|
|
147
161
|
end
|
148
162
|
end
|
149
163
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
164
|
+
def associations
|
165
|
+
[inputs + outputs]
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_spec
|
169
|
+
spec = super
|
170
|
+
spec['inputs'] = inputs.collect {|node| app.var(node) }
|
171
|
+
spec['outputs'] = outputs.collect {|node| app.var(node) }
|
172
|
+
spec
|
155
173
|
end
|
156
174
|
|
157
175
|
protected
|
data/lib/tap/joins/sync.rb
CHANGED
data/lib/tap/middleware.rb
CHANGED
@@ -1,34 +1,13 @@
|
|
1
|
-
require '
|
1
|
+
require 'tap/app'
|
2
2
|
|
3
3
|
module Tap
|
4
|
-
class Middleware
|
4
|
+
class Middleware < App::Api
|
5
5
|
class << self
|
6
|
-
|
7
|
-
|
8
|
-
# as middleware.
|
9
|
-
def parse(argv=ARGV, app=Tap::App.instance)
|
10
|
-
parse!(argv.dup, app)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Same as parse, but removes arguments destructively.
|
14
|
-
def parse!(argv=ARGV, app=Tap::App.instance)
|
15
|
-
opts = ConfigParser.new
|
16
|
-
opts.separator "configurations:"
|
17
|
-
opts.add(configurations)
|
18
|
-
|
19
|
-
args = opts.parse!(argv, :add_defaults => false)
|
20
|
-
instantiate({:config => opts.nested_config}, app)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Instantiates an instance of self and causes app to use the instance
|
24
|
-
# as middleware.
|
25
|
-
def instantiate(argh, app=Tap::App.instance)
|
26
|
-
app.use(self, argh[:config] || {})
|
6
|
+
def build(spec={}, app=Tap::App.instance)
|
7
|
+
new(app.stack, spec['config'] || {})
|
27
8
|
end
|
28
9
|
end
|
29
10
|
|
30
|
-
include Configurable
|
31
|
-
|
32
11
|
# The call stack.
|
33
12
|
attr_reader :stack
|
34
13
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'tap/middleware'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Middlewares
|
5
|
+
|
6
|
+
# :startdoc::middleware the default debugger
|
7
|
+
class Debugger < Middleware
|
8
|
+
module Utils
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def arity_ok?(arity, n)
|
12
|
+
n == arity || (arity < 0 && (-1-n) <= arity)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
include Utils
|
17
|
+
|
18
|
+
config :verbose, false, &c.flag
|
19
|
+
config :output, $stderr, &c.io
|
20
|
+
|
21
|
+
def call(node, inputs=[])
|
22
|
+
open_io(output) do |io|
|
23
|
+
io.puts "- - #{node.class}"
|
24
|
+
io.puts " - #{summarize(inputs)}"
|
25
|
+
end
|
26
|
+
|
27
|
+
check_signature(node, inputs)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def summarize(inputs)
|
32
|
+
unless verbose
|
33
|
+
inputs = inputs.collect do |input|
|
34
|
+
input.class
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
inputs.inspect
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_signature(node, inputs)
|
42
|
+
n = inputs.length
|
43
|
+
|
44
|
+
call_arity = node.method(:call).arity
|
45
|
+
unless arity_ok?(call_arity, n)
|
46
|
+
raise InvalidSignatureError.new(node, inputs, :call, call_arity)
|
47
|
+
end
|
48
|
+
|
49
|
+
if node.kind_of?(Task)
|
50
|
+
process_arity = node.method(:process).arity
|
51
|
+
unless arity_ok?(process_arity, n)
|
52
|
+
raise InvalidSignatureError.new(node, inputs, :process, process_arity)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if node.kind_of?(Intern)
|
57
|
+
process_block_arity = node.process_block
|
58
|
+
unless arity_ok?(process_block_arity, n)
|
59
|
+
raise InvalidSignatureError.new(node, inputs, :process_block, process_block_arity)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
class InvalidSignatureError < StandardError
|
66
|
+
def initialize(node, inputs, method, arity)
|
67
|
+
lines = []
|
68
|
+
lines << "Invalid input signature to: #{node.class} (#{method})"
|
69
|
+
lines << "Expected #{arity} input but was given #{inputs.length}"
|
70
|
+
super(lines.join("\n"))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|