tap 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/History +12 -0
  2. data/MIT-LICENSE +0 -2
  3. data/README +23 -32
  4. data/bin/rap +116 -0
  5. data/bin/tap +6 -9
  6. data/cgi/run.rb +67 -0
  7. data/cmd/console.rb +1 -1
  8. data/cmd/destroy.rb +4 -4
  9. data/cmd/generate.rb +4 -4
  10. data/cmd/manifest.rb +61 -53
  11. data/cmd/run.rb +8 -75
  12. data/doc/Class Reference +130 -121
  13. data/doc/Command Reference +76 -124
  14. data/doc/Syntax Reference +290 -0
  15. data/doc/Tutorial +305 -237
  16. data/lib/tap/app.rb +140 -467
  17. data/lib/tap/constants.rb +2 -2
  18. data/lib/tap/declarations.rb +211 -0
  19. data/lib/tap/env.rb +171 -193
  20. data/lib/tap/exe.rb +100 -21
  21. data/lib/tap/file_task.rb +3 -3
  22. data/lib/tap/generator/base.rb +1 -1
  23. data/lib/tap/generator/destroy.rb +10 -10
  24. data/lib/tap/generator/generate.rb +29 -18
  25. data/lib/tap/generator/generators/command/command_generator.rb +2 -2
  26. data/lib/tap/generator/generators/command/templates/command.erb +2 -2
  27. data/lib/tap/generator/generators/config/config_generator.rb +3 -3
  28. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  29. data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
  30. data/lib/tap/generator/generators/file_task/templates/task.erb +1 -1
  31. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  32. data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
  33. data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
  34. data/lib/tap/generator/generators/root/root_generator.rb +13 -13
  35. data/lib/tap/generator/generators/root/templates/README +0 -0
  36. data/lib/tap/generator/generators/root/templates/Rakefile +2 -2
  37. data/lib/tap/generator/generators/root/templates/gemspec +4 -5
  38. data/lib/tap/generator/generators/root/templates/tapfile +11 -8
  39. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  40. data/lib/tap/generator/generators/task/task_generator.rb +1 -3
  41. data/lib/tap/generator/generators/task/templates/test.erb +1 -3
  42. data/lib/tap/patches/optparse/summarize.rb +62 -0
  43. data/lib/tap/root.rb +41 -29
  44. data/lib/tap/support/aggregator.rb +16 -3
  45. data/lib/tap/support/assignments.rb +10 -9
  46. data/lib/tap/support/audit.rb +58 -64
  47. data/lib/tap/support/class_configuration.rb +33 -44
  48. data/lib/tap/support/combinator.rb +125 -0
  49. data/lib/tap/support/configurable.rb +13 -14
  50. data/lib/tap/support/configurable_class.rb +21 -43
  51. data/lib/tap/support/configuration.rb +55 -9
  52. data/lib/tap/support/constant.rb +87 -13
  53. data/lib/tap/support/constant_manifest.rb +116 -0
  54. data/lib/tap/support/dependencies.rb +54 -0
  55. data/lib/tap/support/dependency.rb +44 -0
  56. data/lib/tap/support/executable.rb +247 -32
  57. data/lib/tap/support/executable_queue.rb +1 -1
  58. data/lib/tap/support/gems/rake.rb +29 -8
  59. data/lib/tap/support/gems.rb +10 -30
  60. data/lib/tap/support/instance_configuration.rb +29 -3
  61. data/lib/tap/support/intern.rb +46 -0
  62. data/lib/tap/support/join.rb +143 -0
  63. data/lib/tap/support/joins/fork.rb +19 -0
  64. data/lib/tap/support/joins/merge.rb +22 -0
  65. data/lib/tap/support/joins/sequence.rb +21 -0
  66. data/lib/tap/support/joins/switch.rb +25 -0
  67. data/lib/tap/support/joins/sync_merge.rb +63 -0
  68. data/lib/tap/support/joins.rb +15 -0
  69. data/lib/tap/support/lazy_attributes.rb +17 -2
  70. data/lib/tap/support/lazydoc/comment.rb +503 -0
  71. data/lib/tap/support/lazydoc/config.rb +17 -0
  72. data/lib/tap/support/lazydoc/definition.rb +36 -0
  73. data/lib/tap/support/lazydoc/document.rb +152 -0
  74. data/lib/tap/support/lazydoc/method.rb +24 -0
  75. data/lib/tap/support/lazydoc.rb +269 -343
  76. data/lib/tap/support/manifest.rb +121 -103
  77. data/lib/tap/support/minimap.rb +90 -0
  78. data/lib/tap/support/node.rb +56 -0
  79. data/lib/tap/support/parser.rb +436 -0
  80. data/lib/tap/support/schema.rb +359 -0
  81. data/lib/tap/support/shell_utils.rb +3 -5
  82. data/lib/tap/support/string_ext.rb +60 -0
  83. data/lib/tap/support/tdoc.rb +7 -2
  84. data/lib/tap/support/templater.rb +30 -16
  85. data/lib/tap/support/validation.rb +77 -8
  86. data/lib/tap/task.rb +431 -143
  87. data/lib/tap/tasks/dump.rb +15 -10
  88. data/lib/tap/tasks/load.rb +112 -0
  89. data/lib/tap/tasks/rake.rb +4 -41
  90. data/lib/tap/test/assertions.rb +38 -0
  91. data/lib/tap/test/env_vars.rb +1 -1
  92. data/lib/tap/test/extensions.rb +79 -0
  93. data/lib/tap/test/file_test.rb +420 -0
  94. data/lib/tap/test/file_test_class.rb +12 -0
  95. data/lib/tap/test/regexp_escape.rb +87 -0
  96. data/lib/tap/test/script_test.rb +46 -0
  97. data/lib/tap/test/script_tester.rb +115 -0
  98. data/lib/tap/test/subset_test.rb +260 -0
  99. data/lib/tap/test/subset_test_class.rb +99 -0
  100. data/lib/tap/test/{tap_methods.rb → tap_test.rb} +45 -43
  101. data/lib/tap/test/utils.rb +231 -0
  102. data/lib/tap/test.rb +53 -26
  103. data/lib/tap.rb +3 -20
  104. metadata +50 -27
  105. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
  106. data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
  107. data/lib/tap/patches/rake/testtask.rb +0 -57
  108. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
  109. data/lib/tap/patches/ruby19/parsedate.rb +0 -16
  110. data/lib/tap/support/batchable.rb +0 -47
  111. data/lib/tap/support/batchable_class.rb +0 -107
  112. data/lib/tap/support/command_line.rb +0 -98
  113. data/lib/tap/support/comment.rb +0 -270
  114. data/lib/tap/support/constant_utils.rb +0 -127
  115. data/lib/tap/support/declarations.rb +0 -111
  116. data/lib/tap/support/framework.rb +0 -83
  117. data/lib/tap/support/framework_class.rb +0 -180
  118. data/lib/tap/support/run_error.rb +0 -39
  119. data/lib/tap/support/summary.rb +0 -30
  120. data/lib/tap/test/file_methods.rb +0 -377
  121. data/lib/tap/test/script_methods/script_test.rb +0 -98
  122. data/lib/tap/test/script_methods.rb +0 -107
  123. data/lib/tap/test/subset_methods.rb +0 -420
  124. data/lib/tap/workflow.rb +0 -200
data/doc/Tutorial CHANGED
@@ -1,237 +1,305 @@
1
- = Quick Start Tutorial
2
-
3
- === Basic Usage
4
-
5
- Begin by creating a tap directory structure:
6
-
7
- % tap generate root sample
8
- % cd sample
9
-
10
- Comes with a task:
11
-
12
- % tap run -T
13
- sample:
14
- goodnight # your basic goodnight moon task
15
- tap:
16
- dump # the default dump task
17
- rake # run rake tasks
18
-
19
- Test the task:
20
-
21
- % rake test
22
-
23
- Get help for the task:
24
-
25
- % tap run -- goodnight --help
26
- Goodnight -- your basic goodnight moon task
27
- --------------------------------------------------------------------------------
28
- Prints the input with a configurable message.
29
- --------------------------------------------------------------------------------
30
- usage: tap run -- goodnight INPUT
31
-
32
- configurations:
33
- --message MESSAGE
34
-
35
- options:
36
- -h, --help Print this help
37
- --name NAME Specify a name
38
- --use FILE Loads inputs from file
39
-
40
- Run the task:
41
-
42
- % tap run -- goodnight moon
43
- I[23:22:19] goodnight moon
44
-
45
- Run the task, setting the 'message' configuration:
46
-
47
- % tap run -- goodnight moon --message hello
48
- I[23:22:46] hello moon
49
-
50
- Run multiple tasks, or in this case the same task twice:
51
-
52
- % tap run -- goodnight moon -- goodnight opus
53
- I[23:23:06] goodnight moon
54
- I[23:23:06] goodnight opus
55
-
56
- Same as above, but now dump the results to a file:
57
-
58
- % tap run -- goodnight moon -- goodnight opus --+ dump output.yml
59
- I[23:23:26] goodnight moon
60
- I[23:23:26] goodnight opus
61
- I[23:23:26] dump output.yml
62
-
63
- The dump file contents look like this:
64
-
65
- # audit:
66
- # o-[] "opus"
67
- # o-[goodnight] "goodnight opus"
68
- #
69
- # o-[] "moon"
70
- # o-[goodnight] "goodnight moon"
71
- #
72
- # date: 2008-08-05 23:23:26
73
- ---
74
- goodnight (2769410):
75
- - goodnight opus
76
- goodnight (2780180):
77
- - goodnight moon
78
-
79
- The comments at the beginning are an audit trace of the run. In this case two
80
- separate tasks were run sequentially, hence you can see each task, the task inputs,
81
- and the task results as separate units. A YAML hash follows the audit with the
82
- aggregated task results, keyed by the task name and object id. Since the results
83
- are represented as a hash, the order of the tasks sometimes gets scrambled, as in
84
- this case.
85
-
86
- === Task Declaration
87
-
88
- Tap provides a declaration syntax a-la rake, accessible through the Tap module to
89
- prevent conflicts with rake. Declarations can get put in any <tt>.rb</tt> file
90
- under the lib directory or in <tt>tapfile.rb</tt>.
91
-
92
- [tapfile.rb]
93
- # Goodnight::manifest your basic goodnight moon task
94
- # Prints the input with a configurable message.
95
-
96
- Tap.task('goodnight', :message => 'goodnight') do |task, name|
97
- task.log task.message, name
98
- "#{task.message} #{name}"
99
- end
100
-
101
- The declaration makes a task class based on the name (ie namespaces are naturally
102
- supported by names like <tt>'nested/task'</tt>). The classes are ready for use in
103
- scripts:
104
-
105
- require 'tapfile'
106
- Goodnight.new.process('moon') # => 'goodnight moon'
107
-
108
- And from the command line, as above.
109
-
110
- === Task Definition
111
-
112
- Sometimes you need more than a block to define a task. Generate a task:
113
-
114
- % tap generate task hello
115
-
116
- Navigate to and open the <tt>lib/hello.rb</tt> file. Inside you can see the class
117
- definition. Notice configurations are mapped to methods, and the task documentation
118
- is located in the comments. Let's change it up a bit:
119
-
120
- [lib/hello.rb]
121
- # Hello::manifest your basic hello world task
122
- #
123
- # Prints hello to a number of things with a configurable,
124
- # reversible message.
125
- #
126
- class Hello < Tap::Task
127
-
128
- config :message, 'hello' # a greeting
129
- config :reverse, false, &c.flag # reverses the message
130
-
131
- def process(*names)
132
- names.collect do |name|
133
- log(reverse ? message.reverse : message, name)
134
- "#{message} #{name}"
135
- end
136
- end
137
- end
138
-
139
- The new configurations and documentation are immediately available:
140
-
141
- % tap run -- hello --help
142
- Hello -- your basic hello world task
143
- --------------------------------------------------------------------------------
144
- Prints hello to a number of things with a configurable, reversible message.
145
- --------------------------------------------------------------------------------
146
- usage: tap run -- hello NAMES...
147
-
148
- configurations:
149
- --message MESSAGE a greeting
150
- --reverse reverses the message
151
-
152
- options:
153
- -h, --help Print this help
154
- --name NAME Specify a name
155
- --use FILE Loads inputs from file
156
-
157
- And the task is ready to go:
158
-
159
- % tap run -- hello moon lamp 'little toy boat'
160
- I[23:29:26] hello moon
161
- I[23:29:26] hello lamp
162
- I[23:29:26] hello little toy boat
163
-
164
- % tap run -- hello mittens --reverse
165
- I[23:29:53] olleh mittens
166
-
167
- Now lets use the previous results; they get loaded and added to the end of the inputs:
168
-
169
- % tap run -- hello --use output.yml
170
- I[23:31:32] hello goodnight moon
171
- I[23:31:32] hello goodnight opus
172
-
173
- === Config Files
174
-
175
- So say you wanted static configs for a task. Make a configuration file:
176
-
177
- % tap generate config goodnight
178
-
179
- Set the configurations here and they get used by the task:
180
-
181
- [config/goodnight.yml]
182
- ###############################################################################
183
- # Goodnight configuration
184
- ###############################################################################
185
-
186
- message: good evening
187
-
188
- As can be seen here:
189
-
190
- % tap run -- goodnight moon
191
- I[23:40:39] good evening moon
192
-
193
- If you need to run a task with multiple sets of configurations, simply define an
194
- array of configurations in the config file:
195
-
196
- [config/goodnight.yml]
197
- - message: good afternoon
198
- - message: good evening
199
- - message: goodnight
200
-
201
- % tap run -- goodnight moon
202
- I[23:42:46] good afternoon moon
203
- I[23:42:46] good evening moon
204
- I[23:42:46] goodnight moon
205
-
206
- The --name option sets the config file used:
207
-
208
- % tap run -- goodnight moon --name no_config_file
209
- I[23:43:20] goodnight moon
210
-
211
- === Tap Configuration
212
-
213
- Tap itself is highly configurable. Say you think the run syntax is unnecessarily
214
- verbose; you can make command aliases to shorten it. Open the <tt>tap.yml</tt>
215
- file in your root directory and set the following:
216
-
217
- [tap.yml]
218
- alias:
219
- --: [run, --]
220
- -T: [run, -T]
221
-
222
- Now:
223
-
224
- % tap -- hello world
225
- I[23:43:59] hello world
226
-
227
- % tap -T
228
- sample:
229
- goodnight # your basic goodnight moon task
230
- hello # your basic hello world task
231
- tap:
232
- dump # the default dump task
233
- rake # run rake tasks
234
-
235
- Global configurations can go in the <tt>~/.tap.yml</tt> file. Using configurations,
236
- you can specify directory aliases, options, gems, and even additional paths to load
237
- as if they were gems.
1
+ = Tap (Task Application)
2
+
3
+ Tap is a framework for creating configurable, distributable tasks and workflows. Although scalable for complex workflows, at it simplest tap works like a supercharged rake. Using the rap executable, you can declare tasks using a syntax almost identical to rake, but with added support for configurations and documentation.
4
+
5
+ == Quickstart
6
+
7
+ If you've used rake, tap will be easy to pick up. To get started, make a Tapfile with a simple task declaration:
8
+
9
+ [Tapfile]
10
+
11
+ # ::desc your basic goodnight moon task
12
+ # Says goodnight with a configurable message.
13
+ Tap.task(:goodnight, :obj, :message => 'goodnight') do |task, args|
14
+ puts "#{task.message} #{args.obj}\n"
15
+ end
16
+
17
+ Now from the command line:
18
+
19
+ % rap goodnight moon
20
+ goodnight moon
21
+
22
+ % rap goodnight world --message hello
23
+ hello world
24
+
25
+ % rap goodnight --help
26
+ Goodnight -- your basic goodnight moon task
27
+ --------------------------------------------------------------------------------
28
+ Says goodnight with a configurable message.
29
+ --------------------------------------------------------------------------------
30
+ usage: tap run -- goodnight obj
31
+
32
+ configurations:
33
+ --message MESSAGE
34
+
35
+ options:
36
+ -h, --help Print this help
37
+ --name NAME Specify a name
38
+ --use FILE Loads inputs from file
39
+
40
+ Just like that you have a command-line application with inputs, configuration, and documentation.
41
+
42
+ The declaration syntax is obviously similar to rake; configurations are new but the task-block style is the same, as are inputs. Other rake constructs are available. Here is a similar goodnight task using dependencies, rake-style.
43
+
44
+ [Tapfile]
45
+
46
+ # make the declarations available everywhere
47
+ # (normally they're accessed via Tap, as above)
48
+ extend Tap::Declarations
49
+
50
+ namespace :example do
51
+ task(:say, :message) do |task, args|
52
+ print(args.message || 'goodnight')
53
+ end
54
+
55
+ desc "your basic goodnight moon task"
56
+ task({:goodnight => :say}, :obj) do |task, args|
57
+ puts " #{args.obj}\n"
58
+ end
59
+ end
60
+
61
+ And now from the command line:
62
+
63
+ % rap goodnight moon
64
+ goodnight moon
65
+
66
+ % rap goodnight world --* say hello
67
+ hello world
68
+
69
+ Unlike rake, rap inputs are written out individually and tasks are delimited by a modified double-dash. Aside from that, you can see rap is basically a supercharged rake. Furthermore, rap runs rake. Directly substitute rap for rake on the command line and your tasks should run as normal (see the {Syntax Reference}[link:files/doc/Syntax%20Reference.html] for more details).
70
+
71
+ However, supercharging rake isn't the point of Tap. Declarations bridge the gap between rake and tap, but tap itself is a more general framework. To get at other features like imperative workflows, testing, and distribution, we have to go beyond rap and take a look at what declarations do.
72
+
73
+ Spoiler: declarations make subclasses of Tap::Task.
74
+
75
+ == Beyond Rap
76
+
77
+ Going back to the first example, lets take a look at how a task declaration maps to a class definition:
78
+
79
+ [Tapfile]
80
+
81
+ # ::desc your basic goodnight moon task
82
+ # Says goodnight with a configurable message.
83
+ Tap.task(:goodnight, :obj, :message => 'goodnight') do
84
+ puts "#{task.message} #{args.obj}\n"
85
+ end
86
+
87
+ Here is a corresponding class:
88
+
89
+ # Goodnight::manifest your basic goodnight moon task
90
+ # Says goodnight with a configurable message.
91
+ class Goodnight < Tap::Task
92
+ config :message, 'goodnight'
93
+
94
+ def process(obj)
95
+ "#{message} #{obj}"
96
+ end
97
+ end
98
+
99
+ Simple enough; the name corresponds to the class, configurations (and dependencies, although they aren't show) are written out individually, and the block corresponds to process. There are a few differences, especially relating to process, but for the moment lets gloss over them and see how Goodnight works.
100
+
101
+ Goodnight.configurations.to_hash # => {:message => 'goodnight'}
102
+
103
+ goodnight = Goodnight.new
104
+ goodnight.message # => 'goodnight'
105
+ goodnight.process('moon') # => 'goodnight moon'
106
+
107
+ hello = Goodnight.new(:message => 'hello')
108
+ hello.message # => 'hello'
109
+ hello.process('world') # => 'hello world'
110
+
111
+ Totally straightforward. Goodnight stores the default configurations, each instance has accessors to the configurations, and the defaults may be overridden during initialization, or later. Class definitions allow validation/transformation blocks to be specified for configurations. These blocks process inputs (ex the string inputs from the command line), quite literally defining the writer for a configuration accessor. A set of standard blocks are available through +c+, an alias for the Tap::Support::Validation module.
112
+
113
+ [Tapfile]
114
+
115
+ # Goodnight::manifest a fancy goodnight moon task
116
+ # Says goodnight with a configurable message.
117
+ class Goodnight < Tap::Task
118
+ config :message, 'goodnight' # a goodnight message
119
+ config :reverse, false, &c.switch # reverses the message
120
+ config :n, 1, &c.integer # repeats message n times
121
+
122
+ def process(*objects)
123
+ print "#{reverse == true ? message.reverse : message} " * n
124
+ puts objects.join(', ')
125
+ puts
126
+ end
127
+ end
128
+
129
+ A few examples show a validation block in action:
130
+
131
+ goodnight = Goodnight.new
132
+
133
+ goodnight.n = 10
134
+ goodnight.n # => 10
135
+
136
+ goodnight.n = "100"
137
+ goodnight.n # => 100
138
+
139
+ goodnight.n = "not an integer" # !> ValidationError
140
+
141
+ Now from the command line:
142
+
143
+ % rap goodnight moon
144
+ goodnight moon
145
+
146
+ % rap goodnight moon mittens "little toy boat"
147
+ goodnight moon, mittens, little toy boat
148
+
149
+ % rap goodnight world --message hello --reverse --n 3
150
+ olleh olleh olleh world
151
+
152
+ % rap goodnight --help
153
+ Goodnight -- a fancy goodnight moon task
154
+ --------------------------------------------------------------------------------
155
+ Says goodnight with a configurable message.
156
+ --------------------------------------------------------------------------------
157
+ usage: tap run -- goodnight OBJECTS...
158
+
159
+ configurations:
160
+ --message MESSAGE a goodnight message
161
+ --[no-]reverse reverses the message
162
+ --n N repeats message n times
163
+
164
+ options:
165
+ -h, --help Print this help
166
+ --name NAME Specify a name
167
+ --use FILE Loads inputs from file
168
+
169
+ Take a quick look at the documentation. Class definitions can also map documentation and, in some cases, metadata to the command line; the configurations now have comments and reverse is a switch! Rich mapping allows tasks to act as an script interface, not unlike {OptionParser}[http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html] (surprise, tap uses OptionParser).
170
+
171
+ For example this is a stand-alone goodnight script:
172
+
173
+ [goodnight]
174
+
175
+ #!/usr/bin/env ruby
176
+
177
+ require 'rubygems'
178
+ require 'tap'
179
+
180
+ # Goodnight::manifest a goodnight moon script
181
+ # Says goodnight with a configurable message.
182
+ class Goodnight < Tap::Task
183
+ config :message, 'goodnight'
184
+
185
+ def process(obj)
186
+ puts "#{message} #{obj}\n"
187
+ end
188
+ end
189
+
190
+ instance, args = Goodnight.parse!(ARGV)
191
+ instance.execute(*args)
192
+
193
+ Now, from the command line:
194
+
195
+ % ./goodnight moon
196
+ goodnight moon
197
+
198
+ % ./goodnight --help
199
+ ...
200
+
201
+ As simple as it is to take a task to the command line, it's nice to note that tasks may be subclassed, tested, and distributed as usual. No magic, just convenience.
202
+
203
+ == Tap
204
+
205
+ Tap comes with two executables, rap and tap. The tap executable is more verbose than rap for running tasks, but it is more configurable, scalable, and logically pure. Tap comes with a number of {commands}[link:files/doc/Command%20Reference.html] but we'll focus on generate to make, test, and package a task library. Begin by creating a tap directory structure and a task:
206
+
207
+ % tap generate root sample
208
+ % cd sample
209
+ % tap generate task goodnight
210
+
211
+ Take a look at the task files an you find something like this:
212
+
213
+ [lib/goodnight.rb]
214
+
215
+ # Goodnight::manifest <replace with manifest summary>
216
+ # <replace with command line description>
217
+
218
+ # Goodnight Documentation
219
+ class Goodnight < Tap::Task
220
+
221
+ # <config file documentation>
222
+ config :message, 'goodnight' # a sample config
223
+
224
+ def process(name)
225
+ log message, name
226
+ "#{message} #{name}"
227
+ end
228
+ end
229
+
230
+ [test/goodnight_test.rb]
231
+
232
+ require File.join(File.dirname(__FILE__), 'tap_test_helper.rb')
233
+ require 'goodnight'
234
+
235
+ class GoodnightTest < Test::Unit::TestCase
236
+ acts_as_tap_test
237
+
238
+ def test_goodnight
239
+ task = Goodnight.new :message => "goodnight"
240
+
241
+ # a simple test
242
+ assert_equal({:message => 'goodnight'}, task.config)
243
+ assert_equal "goodnight moon", task.process("moon")
244
+
245
+ # a more complex test
246
+ task.enq("moon")
247
+ app.run
248
+
249
+ assert_equal ["goodnight moon"], app.results(task)
250
+ assert_audit_equal ExpAudit[[nil, "moon"], [task, "goodnight moon"]], app._results(task)[0]
251
+ end
252
+ end
253
+
254
+ Run the test:
255
+
256
+ % rap test
257
+
258
+ Run the task:
259
+
260
+ % rap goodnight moon
261
+ I[23:22:19] goodnight moon
262
+
263
+ Ok, lets share it. Print the current gemspec manifest:
264
+
265
+ % rap print_manifest
266
+ true README
267
+ Rakefile
268
+ lib/goodnight.rb
269
+ sample.gemspec
270
+ true tap.yml
271
+ test/goodnight_test.rb
272
+ true test/tap_test_helper.rb
273
+ true test/tap_test_suite.rb
274
+
275
+ As you can see, this needs an update to include the task file. Open up sample.gemspec and fix the manifest.
276
+
277
+ [sample.gemspec]
278
+
279
+ Gem::Specification.new do |s|
280
+ s.name = "sample"
281
+ s.version = "0.0.1"
282
+ s.platform = Gem::Platform::RUBY
283
+ s.summary = "sample"
284
+ s.require_path = "lib"
285
+ s.add_dependency("tap", ">= 0.11")
286
+ s.files = %W{
287
+ lib/goodnight.rb
288
+ tap.yml
289
+ }
290
+ end
291
+
292
+ Now package the gem and install it (gem may require sudo):
293
+
294
+ % rap gem
295
+ % gem install pkg/sample-0.0.1.gem
296
+
297
+ Now you can say goodnight anywhere, using 'tap run' or rap:
298
+
299
+ % cd ~/Desktop
300
+ % tap run -- goodnight moon
301
+ goodnight moon
302
+ % rap goodnight opus
303
+ goodnight opus
304
+
305
+ And that is that.