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.
- data/History +100 -45
- data/MIT-LICENSE +1 -1
- data/README +95 -51
- data/bin/tap +11 -57
- data/bin/tapexe +84 -0
- data/doc/API +91 -139
- data/doc/Configuration +93 -0
- data/doc/Examples/Command Line +10 -42
- data/doc/Examples/Tapfile +124 -0
- data/doc/Ruby to Ruby +87 -0
- data/doc/Workflow Syntax +185 -0
- data/lib/tap.rb +74 -5
- data/lib/tap/app.rb +217 -310
- data/lib/tap/app/api.rb +44 -23
- data/lib/tap/app/queue.rb +11 -12
- data/lib/tap/app/stack.rb +4 -4
- data/lib/tap/declarations.rb +200 -0
- data/lib/tap/declarations/context.rb +31 -0
- data/lib/tap/declarations/description.rb +33 -0
- data/lib/tap/env.rb +133 -779
- data/lib/tap/env/cache.rb +87 -0
- data/lib/tap/env/constant.rb +94 -39
- data/lib/tap/env/path.rb +71 -0
- data/lib/tap/join.rb +42 -78
- data/lib/tap/joins/gate.rb +85 -0
- data/lib/tap/joins/switch.rb +4 -2
- data/lib/tap/joins/sync.rb +3 -3
- data/lib/tap/middleware.rb +5 -5
- data/lib/tap/middlewares/debugger.rb +18 -58
- data/lib/tap/parser.rb +115 -183
- data/lib/tap/root.rb +162 -239
- data/lib/tap/signal.rb +72 -0
- data/lib/tap/signals.rb +20 -2
- data/lib/tap/signals/class_methods.rb +38 -43
- data/lib/tap/signals/configure.rb +19 -0
- data/lib/tap/signals/help.rb +5 -7
- data/lib/tap/signals/load.rb +49 -0
- data/lib/tap/signals/module_methods.rb +1 -0
- data/lib/tap/task.rb +46 -275
- data/lib/tap/tasks/dump.rb +21 -16
- data/lib/tap/tasks/list.rb +184 -0
- data/lib/tap/tasks/load.rb +4 -4
- data/lib/tap/tasks/prompt.rb +128 -0
- data/lib/tap/tasks/signal.rb +42 -0
- data/lib/tap/tasks/singleton.rb +35 -0
- data/lib/tap/tasks/stream.rb +64 -0
- data/lib/tap/utils.rb +83 -0
- data/lib/tap/version.rb +2 -2
- data/lib/tap/workflow.rb +124 -0
- data/tap.yml +0 -0
- metadata +59 -24
- data/cmd/console.rb +0 -43
- data/cmd/manifest.rb +0 -118
- data/cmd/run.rb +0 -145
- data/doc/Examples/Workflow +0 -40
- data/lib/tap/app/node.rb +0 -29
- data/lib/tap/env/context.rb +0 -61
- data/lib/tap/env/gems.rb +0 -63
- data/lib/tap/env/manifest.rb +0 -179
- data/lib/tap/env/minimap.rb +0 -308
- data/lib/tap/intern.rb +0 -50
- data/lib/tap/joins.rb +0 -9
- data/lib/tap/prompt.rb +0 -36
- data/lib/tap/root/utils.rb +0 -220
- data/lib/tap/root/versions.rb +0 -138
- data/lib/tap/signals/signal.rb +0 -68
data/doc/Examples/Command Line
CHANGED
@@ -1,62 +1,30 @@
|
|
1
|
-
= Command Line
|
1
|
+
= Command Line
|
2
2
|
|
3
|
-
|
3
|
+
Tap can work in the context of a command line like any other executable. By
|
4
|
+
default the load/dump tasks read and write to stdin/stdout. These patterns
|
5
|
+
represent common ways to hook up a Tap workflow.
|
4
6
|
|
5
7
|
=== Read data from $stdin
|
6
8
|
# [goodnight.txt]
|
7
9
|
# goodnight moon
|
8
10
|
|
9
|
-
% tap
|
11
|
+
% tap load -: dump < goodnight.txt
|
10
12
|
goodnight moon
|
11
13
|
|
12
14
|
=== Pipe data from $stdin
|
13
|
-
% echo goodnight moon | tap
|
15
|
+
% echo goodnight moon | tap load -: dump
|
14
16
|
goodnight moon
|
15
17
|
|
16
|
-
===
|
17
|
-
% tap
|
18
|
+
=== Manually specify data with an argument
|
19
|
+
% tap load 'goodnight moon' -: dump
|
18
20
|
goodnight moon
|
19
21
|
|
20
22
|
=== Dump data to $stdout
|
21
|
-
% tap
|
23
|
+
% tap load 'goodnight moon' -: dump > goodnight.txt
|
22
24
|
% more goodnight.txt
|
23
25
|
goodnight moon
|
24
26
|
|
25
27
|
=== Pipe data via $stdout
|
26
|
-
% tap
|
28
|
+
% tap load 'goodnight moon' -: dump | more
|
27
29
|
goodnight moon
|
28
30
|
|
29
|
-
== Setup
|
30
|
-
|
31
|
-
=== Use an ENV variable to setup the Tap::Env
|
32
|
-
|
33
|
-
% TAP_GEMS= tap run -T
|
34
|
-
% TAP_GEMS=:all tap run -T
|
35
|
-
% TAP_GEMS=:latest tap run -T
|
36
|
-
% TAP_GEMS="[rap, tap-tasks]" tap run -T
|
37
|
-
|
38
|
-
== Signals
|
39
|
-
|
40
|
-
The run command will bring up a signal prompt with the --prompt flag, or by
|
41
|
-
sending and interrupt signal. To illustrate the latter, setup an infinite
|
42
|
-
loop and hit ctl-c to enter the prompt. To exit, signal stop as shown here:
|
43
|
-
|
44
|
-
% tap run -- dump --[app][0]q --/0/enq 'hello world'
|
45
|
-
hello world
|
46
|
-
hello world
|
47
|
-
hello world
|
48
|
-
... (this will continue to print until you press ctl-c) ...
|
49
|
-
|
50
|
-
starting prompt (enter for help):
|
51
|
-
--/
|
52
|
-
=>
|
53
|
-
run # run the app
|
54
|
-
stop # stop the app
|
55
|
-
terminate # terminate the app
|
56
|
-
info # prints app status
|
57
|
-
enque
|
58
|
-
build
|
59
|
-
use
|
60
|
-
--//info
|
61
|
-
=> state: 1 (RUN) queue: 0
|
62
|
-
--//stop
|
@@ -0,0 +1,124 @@
|
|
1
|
+
= Tapfile
|
2
|
+
|
3
|
+
Tapfiles can be used to define tasks and workflows. Typically using the
|
4
|
+
Tap::Declarations module which provides a syntax reminiscent of
|
5
|
+
{Rake}[http://rake.rubyforge.org/].
|
6
|
+
|
7
|
+
[tapfile]
|
8
|
+
# A task declaration looks like this. The declaration creates a subclass of
|
9
|
+
# Tap::Task, literally this:
|
10
|
+
#
|
11
|
+
# class Goodnight < Tap::Task
|
12
|
+
# config :msg, 'goodnight'
|
13
|
+
# def process(thing)
|
14
|
+
# "#{msg} #{thing}!"
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# The 'config' passed to the block is actually the task instance but it's
|
19
|
+
# useful to think of it as a source of configs. Note these comments are
|
20
|
+
# meaningful, if present they become the task help.
|
21
|
+
|
22
|
+
desc "a goodnight task"
|
23
|
+
task :goodnight, :msg => 'goodnight' do |config, thing|
|
24
|
+
"#{config.msg} #{thing}!"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Use namespace to set tasks within a module.
|
28
|
+
namespace :example do
|
29
|
+
desc "concat files"
|
30
|
+
task :cat do |config, *paths|
|
31
|
+
paths.collect {|path| File.read(path) }.join
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "sort a string by line"
|
35
|
+
task :sort, :reverse => false do |config, str|
|
36
|
+
lines = str.split("\n").sort
|
37
|
+
config.reverse ? lines.reverse : lines
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Use workflow to create a subclass of Tap::Workflow. Access any tasks you
|
42
|
+
# define in the workflow using node and return the tasks you want to use as
|
43
|
+
# the entry/exit points for the workflow.
|
44
|
+
|
45
|
+
desc "sort the lines of a file"
|
46
|
+
work :sort_file, %q{
|
47
|
+
- cat
|
48
|
+
-:a sort
|
49
|
+
-:i dump
|
50
|
+
},{
|
51
|
+
:reverse => false
|
52
|
+
} do |config|
|
53
|
+
n0 = node(0) # cat
|
54
|
+
n1 = node(1) # sort
|
55
|
+
n1.reverse = config.reverse
|
56
|
+
[n0, n1]
|
57
|
+
end
|
58
|
+
|
59
|
+
# Tasks defined in a singleton block will only execute once (given a set
|
60
|
+
# of inputs) and can be used to make dependency-based workflows.
|
61
|
+
|
62
|
+
singleton do
|
63
|
+
task(:a) { puts 'a' }
|
64
|
+
task(:b => :a) { puts 'b' }
|
65
|
+
task(:c => [:b, :a]) { puts 'c' }
|
66
|
+
end
|
67
|
+
|
68
|
+
Declaration tasks are available for use in workflows:
|
69
|
+
|
70
|
+
% tap goodnight moon -: dump
|
71
|
+
goodnight moon!
|
72
|
+
% tap goodnight world --msg hello -: dump
|
73
|
+
hello world!
|
74
|
+
|
75
|
+
And documented:
|
76
|
+
|
77
|
+
% tap goodnight --help
|
78
|
+
Tapfile::Goodnight -- a goodnight task
|
79
|
+
--------------------------------------------------------------------------------
|
80
|
+
A task declaration looks like this. The declaration creates a subclass of
|
81
|
+
Tap::Task, literally this:
|
82
|
+
|
83
|
+
class Goodnight < Tap::Task
|
84
|
+
config :msg, 'goodnight'
|
85
|
+
def process(thing)
|
86
|
+
"#{msg} #{thing}!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
The 'config' passed to the block is actually the task instance but it's
|
91
|
+
useful to think of it as a source of configs. Note these comments are
|
92
|
+
meaningful, if present they become the task help.
|
93
|
+
--------------------------------------------------------------------------------
|
94
|
+
usage: tap tapfile/goodnight arg
|
95
|
+
|
96
|
+
configurations:
|
97
|
+
--msg MSG
|
98
|
+
|
99
|
+
options:
|
100
|
+
--help Print this help
|
101
|
+
--config FILE Specifies a config file
|
102
|
+
|
103
|
+
Workflows work just like tasks:
|
104
|
+
|
105
|
+
% tap sort_file tapfile --reverse true
|
106
|
+
work :sort_file, :reverse => false do |config|
|
107
|
+
task :goodnight, :msg => 'goodnight' do |config, thing|
|
108
|
+
...
|
109
|
+
|
110
|
+
% order c a b
|
111
|
+
a b c
|
112
|
+
|
113
|
+
Singleton tasks can be used to create dependency-based workflows that function
|
114
|
+
much like rake tasks in practice:
|
115
|
+
|
116
|
+
% tap c
|
117
|
+
a
|
118
|
+
b
|
119
|
+
c
|
120
|
+
% tap b -- a
|
121
|
+
a
|
122
|
+
b
|
123
|
+
|
124
|
+
See Tap::Declarations for syntax details.
|
data/doc/Ruby to Ruby
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
= Ruby (1.8.*) to Ruby (1.9.*)
|
2
|
+
|
3
|
+
Tap runs on at least these interpreters without problem:
|
4
|
+
|
5
|
+
* ruby-1.8.7
|
6
|
+
* ruby-1.9.1
|
7
|
+
* jruby-1.4.0
|
8
|
+
|
9
|
+
However there are suble and important changes in ruby-1.9.* that affect how
|
10
|
+
you construct workflows and what outputs you see on the command line. The
|
11
|
+
most noticeable changes are related to arrays and strings.
|
12
|
+
|
13
|
+
== Array#to_s
|
14
|
+
|
15
|
+
In 1.9 Array#to_s is more like Array#inspect in 1.8. There's no real harm in
|
16
|
+
the to_s change, but it does change the output of dumps and in many cases
|
17
|
+
makes dumps more clear:
|
18
|
+
|
19
|
+
# 1.8
|
20
|
+
% tap load string -: dump
|
21
|
+
string
|
22
|
+
|
23
|
+
% tap load/yaml [array] -: dump
|
24
|
+
array
|
25
|
+
|
26
|
+
# 1.9
|
27
|
+
% tap load string -: dump
|
28
|
+
string
|
29
|
+
|
30
|
+
% tap load/yaml [array] -: dump
|
31
|
+
["array"]
|
32
|
+
|
33
|
+
== String.to_a
|
34
|
+
|
35
|
+
In 1.9 this method goes away, whereas in 1.8 to_a will split a string along
|
36
|
+
newlines into an array. Seems inconsequential but it has big ramifications for
|
37
|
+
objects that splat a string into a helper method. One example is Tap::Task
|
38
|
+
itself, which splats the call input to process.
|
39
|
+
|
40
|
+
class Tap::Task
|
41
|
+
def call(inputs)
|
42
|
+
process(*inputs)
|
43
|
+
end
|
44
|
+
|
45
|
+
def process(*inputs)
|
46
|
+
inputs
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Declaration tasks do the same thing, such that arguments to the block are
|
51
|
+
populated by a splat. Say you made a couple tasks:
|
52
|
+
|
53
|
+
[tapfile]
|
54
|
+
require 'tap/declarations'
|
55
|
+
extend Tap::Declarations
|
56
|
+
|
57
|
+
task(:one) {|config, a, b, c| "#{a}\n#{b}\n#{c}" }
|
58
|
+
task(:two) {|config, input| puts input }
|
59
|
+
|
60
|
+
On 1.9 you can directly join one to two without problem:
|
61
|
+
|
62
|
+
# 1.9
|
63
|
+
% tap one 1 2 3 -: two
|
64
|
+
1
|
65
|
+
2
|
66
|
+
3
|
67
|
+
|
68
|
+
Now see what happens on 1.8:
|
69
|
+
|
70
|
+
# 1.8
|
71
|
+
% tap one 1 2 3 -: two
|
72
|
+
1
|
73
|
+
|
74
|
+
The string created by one has newlines so it gets splatted into an array
|
75
|
+
before being passed into two. Task two only takes one argument and so all that
|
76
|
+
it receives is the first argument of the new array (ie '1'). Totally lousy,
|
77
|
+
but easy to fix. Just be sure to arrayify outputs if the target splats it's
|
78
|
+
input.
|
79
|
+
|
80
|
+
# 1.8
|
81
|
+
% tap one 1 2 3 -:a two
|
82
|
+
1
|
83
|
+
2
|
84
|
+
3
|
85
|
+
|
86
|
+
Note that arrayification is less necessary 1.9, it works fine either way, but
|
87
|
+
cross-ruby workflows should consider this a best practice.
|
data/doc/Workflow Syntax
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
= Workflow Syntax
|
2
|
+
|
3
|
+
Tap uses a custom syntax for specifying workflows. The syntax consists of
|
4
|
+
argument vectors separated by various breaks (ex '-', '--', '-:'). The
|
5
|
+
argument vectors define tasks, joins, and other workflow objects, while the
|
6
|
+
breaks signify various things to do with the objects.
|
7
|
+
|
8
|
+
*Note* this documentation is written from the perspective of ruby-1.9.*, which
|
9
|
+
changes the output of Array#to_s (among other things). See the {Ruby to
|
10
|
+
Ruby}[link:files/doc/Ruby%20to%20Ruby.html] document for more details.
|
11
|
+
|
12
|
+
== Basics
|
13
|
+
|
14
|
+
Argument vectors start with a constant identifier and subsequent arguments
|
15
|
+
indicate inputs and/or options. Inputs are passed to the task as an array
|
16
|
+
while options are parsed out as configurations.
|
17
|
+
|
18
|
+
% tap dump 'goodnight moon'
|
19
|
+
["goodnight moon"]
|
20
|
+
|
21
|
+
% tap dump --help
|
22
|
+
Tap::Tasks::Dump -- dump data
|
23
|
+
...
|
24
|
+
|
25
|
+
Multiple objects can be specified using delimiters where a single-dash (-)
|
26
|
+
delimits, and a double-dash (--) enques. The first object is implicitly
|
27
|
+
enqued, but that behavior can be changed by manually setting a delimiter.
|
28
|
+
|
29
|
+
% tap dump a - dump b -- dump c
|
30
|
+
ignoring args: ["b"]
|
31
|
+
["a"]
|
32
|
+
["c"]
|
33
|
+
|
34
|
+
% tap - dump a -- dump b - dump c
|
35
|
+
ignoring args: ["a"]
|
36
|
+
ignoring args: ["c"]
|
37
|
+
["b"]
|
38
|
+
|
39
|
+
Each object in a workflow is stored in the application by index, allowing them
|
40
|
+
to be referenced from contexts that specifically need them, such as during
|
41
|
+
joins or in signaling (note the context chooses when this happens; normally
|
42
|
+
indexes like 0 are just another character).
|
43
|
+
|
44
|
+
% tap - dump -/0/enq 'enqued by a signal'
|
45
|
+
["enqued by a signal"]
|
46
|
+
|
47
|
+
Constants are identified by matching strings right-to-left as if the constant
|
48
|
+
were underscored into a path. Alternatively, the full constant name can be
|
49
|
+
provided. These all resolve to Tap::Tasks::Load.
|
50
|
+
|
51
|
+
% tap load
|
52
|
+
% tap tap/tasks/load
|
53
|
+
% tap /tap/tasks/load
|
54
|
+
% tap Tap::Tasks::Load
|
55
|
+
|
56
|
+
In addition a left:right identifier can be specified to match both sides of
|
57
|
+
the constant path:
|
58
|
+
|
59
|
+
% tap tap:load
|
60
|
+
% tap /tap/tasks:tasks/load
|
61
|
+
% tap /tap/tasks/load:
|
62
|
+
% tap :/tap/tasks/load
|
63
|
+
|
64
|
+
The workflow syntax reserves dash and all dash-nonword pairs as breaks. Use
|
65
|
+
the escape begin (-.) and escape end (.-) sequences to provide a breaks as
|
66
|
+
inputs.
|
67
|
+
|
68
|
+
% tap dump begin -. -- - -- --- -: -/ --/ .- end
|
69
|
+
["begin", "-", "--", "---", "-:", "-/", "--/", "end"]
|
70
|
+
|
71
|
+
Not all possible breaks are used, but reserving them all makes for one simple
|
72
|
+
rule. The various breaks and common use cases are described below.
|
73
|
+
|
74
|
+
== Sequence (-:)
|
75
|
+
|
76
|
+
Objects can be linked into sequences using a -: break. Here load processes the
|
77
|
+
input into a string, which gets passed to dump and printed (hence the output
|
78
|
+
looks like a string, not an array).
|
79
|
+
|
80
|
+
% tap load 'goodnight moon' -: dump
|
81
|
+
goodnight moon
|
82
|
+
|
83
|
+
The sequence break is a convenient shorthand for manually building two objects
|
84
|
+
and a join.
|
85
|
+
|
86
|
+
% tap load 'goodnight moon' - dump - join 0 1
|
87
|
+
goodnight moon
|
88
|
+
|
89
|
+
The longer syntax supports multi-way joins like fork and merge.
|
90
|
+
|
91
|
+
% tap load 'goodnight moon' - dump - dump - join 0 1,2
|
92
|
+
goodnight moon
|
93
|
+
goodnight moon
|
94
|
+
|
95
|
+
% tap load goodnight -- load moon - dump - join 0,1 2
|
96
|
+
goodnight
|
97
|
+
moon
|
98
|
+
|
99
|
+
It also allows for more complex join types. For example this is a gate join
|
100
|
+
where the outputs are collected into a size-limited array before being passed
|
101
|
+
along.
|
102
|
+
|
103
|
+
% tap load a -- load b -- load c - dump - gate 0,1,2 3 --limit 2
|
104
|
+
["a", "b"]
|
105
|
+
["c"]
|
106
|
+
|
107
|
+
=== Variations
|
108
|
+
|
109
|
+
Joins can iterate or arrayify outputs before passing them to join targets.
|
110
|
+
These options are useful for changing the input/output signatures of objects
|
111
|
+
across a join. For example (borrowing the yaml loading task from tap-tasks):
|
112
|
+
|
113
|
+
% tap load/yaml "[1, 2, 3]" - dump - join 0 1
|
114
|
+
[1, 2, 3]
|
115
|
+
|
116
|
+
% tap load/yaml "[1, 2, 3]" - dump - join 0 1 --iterate
|
117
|
+
1
|
118
|
+
2
|
119
|
+
3
|
120
|
+
|
121
|
+
Sequences can specify flags and a join class like '-:flags.class'. For
|
122
|
+
example, these are equivalent workflows:
|
123
|
+
|
124
|
+
% tap load/yaml "[1, 2, 3]" - dump - dump - join 0 1 --iterate - gate 1 2
|
125
|
+
1
|
126
|
+
2
|
127
|
+
3
|
128
|
+
[1, 2, 3]
|
129
|
+
|
130
|
+
% tap load/yaml "[1, 2, 3]" -:i dump -:.gate dump
|
131
|
+
1
|
132
|
+
2
|
133
|
+
3
|
134
|
+
[1, 2, 3]
|
135
|
+
|
136
|
+
== Signals (-/, --/)
|
137
|
+
|
138
|
+
Internally tap parses workflows into signals that build and control workflow
|
139
|
+
objects. These signals can be specified manually on the command line.
|
140
|
+
|
141
|
+
% tap -/set 0 load -/set 1 dump -/bld join 0 1 -/enq 0 'goodnight moon'
|
142
|
+
goodnight moon
|
143
|
+
|
144
|
+
Invoked from a prompt.
|
145
|
+
|
146
|
+
% tap prompt
|
147
|
+
/set 0 load
|
148
|
+
/set 1 dump
|
149
|
+
/bld join 0 1
|
150
|
+
/enq 0 'goodnight moon'
|
151
|
+
/run
|
152
|
+
goodnight moon
|
153
|
+
|
154
|
+
Or specified in a taprc file, one or more of which can be loaded with a
|
155
|
+
triple-dash. Complex workflows are normally written in this way when they
|
156
|
+
become too cumbersome to write in the single-line syntax.
|
157
|
+
|
158
|
+
[taprc]
|
159
|
+
set 0 load
|
160
|
+
set 1 dump
|
161
|
+
bld join 0 1
|
162
|
+
enq 0 'goodnight moon'
|
163
|
+
|
164
|
+
% tap --- taprc
|
165
|
+
goodnight moon
|
166
|
+
|
167
|
+
% tap --- taprc taprc taprc
|
168
|
+
goodnight moon
|
169
|
+
goodnight moon
|
170
|
+
goodnight moon
|
171
|
+
|
172
|
+
Signals are the basis for controlling apps and objects. As mentioned before,
|
173
|
+
objects in the application space can be signaled directly by name.
|
174
|
+
|
175
|
+
% tap - dump -/0/exe 'goodnight moon'
|
176
|
+
["goodnight moon"]
|
177
|
+
|
178
|
+
Note that the dash-slash break (-/) enques signals, and as such they will run
|
179
|
+
in order, as declared in the workflow. To execute a signal immediately, use a
|
180
|
+
double-dash-slash (--/).
|
181
|
+
|
182
|
+
% tap -- dump a -/0/exe b --/0/exe c
|
183
|
+
["c"]
|
184
|
+
["a"]
|
185
|
+
["b"]
|