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,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"]