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,62 +1,30 @@
1
- = Command Line Examples
1
+ = Command Line
2
2
 
3
- == Basic Input/Output
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 run -- load --: dump < goodnight.txt
11
+ % tap load -: dump < goodnight.txt
10
12
  goodnight moon
11
13
 
12
14
  === Pipe data from $stdin
13
- % echo goodnight moon | tap run -- load --: dump
15
+ % echo goodnight moon | tap load -: dump
14
16
  goodnight moon
15
17
 
16
- === Load data from argument
17
- % tap run -- load 'goodnight moon' --: dump
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 run -- load 'goodnight moon' --: dump > goodnight.txt
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 run -- load 'goodnight moon' --: dump | more
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.
@@ -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.
@@ -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"]