tap 0.12.4 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/History +34 -0
  2. data/README +62 -41
  3. data/bin/tap +36 -40
  4. data/cmd/console.rb +14 -6
  5. data/cmd/manifest.rb +62 -58
  6. data/cmd/run.rb +49 -31
  7. data/doc/API +84 -0
  8. data/doc/Class Reference +83 -115
  9. data/doc/Examples/Command Line +36 -0
  10. data/doc/Examples/Workflow +40 -0
  11. data/lib/tap/app.rb +293 -214
  12. data/lib/tap/app/node.rb +43 -0
  13. data/lib/tap/app/queue.rb +77 -0
  14. data/lib/tap/app/stack.rb +16 -0
  15. data/lib/tap/app/state.rb +22 -0
  16. data/lib/tap/constants.rb +2 -2
  17. data/lib/tap/env.rb +400 -314
  18. data/lib/tap/env/constant.rb +227 -0
  19. data/lib/tap/env/gems.rb +63 -0
  20. data/lib/tap/env/manifest.rb +89 -0
  21. data/lib/tap/env/minimap.rb +292 -0
  22. data/lib/tap/{support → env}/string_ext.rb +2 -2
  23. data/lib/tap/exe.rb +113 -125
  24. data/lib/tap/join.rb +175 -0
  25. data/lib/tap/joins.rb +9 -0
  26. data/lib/tap/joins/switch.rb +44 -0
  27. data/lib/tap/joins/sync.rb +99 -0
  28. data/lib/tap/root.rb +100 -491
  29. data/lib/tap/root/utils.rb +220 -0
  30. data/lib/tap/{support → root}/versions.rb +31 -29
  31. data/lib/tap/schema.rb +248 -0
  32. data/lib/tap/schema/parser.rb +413 -0
  33. data/lib/tap/schema/utils.rb +82 -0
  34. data/lib/tap/support/intern.rb +19 -6
  35. data/lib/tap/support/templater.rb +8 -3
  36. data/lib/tap/task.rb +175 -171
  37. data/lib/tap/tasks/dump.rb +58 -0
  38. data/lib/tap/tasks/load.rb +62 -0
  39. metadata +30 -73
  40. data/cmd/destroy.rb +0 -27
  41. data/cmd/generate.rb +0 -27
  42. data/doc/Command Reference +0 -105
  43. data/doc/Syntax Reference +0 -234
  44. data/doc/Tutorial +0 -348
  45. data/lib/tap/dump.rb +0 -142
  46. data/lib/tap/file_task.rb +0 -384
  47. data/lib/tap/generator/arguments.rb +0 -13
  48. data/lib/tap/generator/base.rb +0 -176
  49. data/lib/tap/generator/destroy.rb +0 -60
  50. data/lib/tap/generator/generate.rb +0 -93
  51. data/lib/tap/generator/generators/command/command_generator.rb +0 -21
  52. data/lib/tap/generator/generators/command/templates/command.erb +0 -32
  53. data/lib/tap/generator/generators/config/config_generator.rb +0 -98
  54. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -37
  55. data/lib/tap/generator/generators/generator/templates/task.erb +0 -27
  56. data/lib/tap/generator/generators/generator/templates/test.erb +0 -26
  57. data/lib/tap/generator/generators/root/root_generator.rb +0 -84
  58. data/lib/tap/generator/generators/root/templates/MIT-LICENSE +0 -22
  59. data/lib/tap/generator/generators/root/templates/README +0 -14
  60. data/lib/tap/generator/generators/root/templates/Rakefile +0 -84
  61. data/lib/tap/generator/generators/root/templates/Rapfile +0 -11
  62. data/lib/tap/generator/generators/root/templates/gemspec +0 -27
  63. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -3
  64. data/lib/tap/generator/generators/task/task_generator.rb +0 -25
  65. data/lib/tap/generator/generators/task/templates/task.erb +0 -14
  66. data/lib/tap/generator/generators/task/templates/test.erb +0 -19
  67. data/lib/tap/generator/manifest.rb +0 -20
  68. data/lib/tap/generator/preview.rb +0 -69
  69. data/lib/tap/load.rb +0 -64
  70. data/lib/tap/spec.rb +0 -41
  71. data/lib/tap/support/aggregator.rb +0 -65
  72. data/lib/tap/support/audit.rb +0 -333
  73. data/lib/tap/support/constant.rb +0 -143
  74. data/lib/tap/support/constant_manifest.rb +0 -126
  75. data/lib/tap/support/dependencies.rb +0 -54
  76. data/lib/tap/support/dependency.rb +0 -44
  77. data/lib/tap/support/executable.rb +0 -198
  78. data/lib/tap/support/executable_queue.rb +0 -125
  79. data/lib/tap/support/gems.rb +0 -43
  80. data/lib/tap/support/join.rb +0 -144
  81. data/lib/tap/support/joins.rb +0 -12
  82. data/lib/tap/support/joins/switch.rb +0 -27
  83. data/lib/tap/support/joins/sync_merge.rb +0 -38
  84. data/lib/tap/support/manifest.rb +0 -171
  85. data/lib/tap/support/minimap.rb +0 -90
  86. data/lib/tap/support/node.rb +0 -176
  87. data/lib/tap/support/parser.rb +0 -450
  88. data/lib/tap/support/schema.rb +0 -385
  89. data/lib/tap/support/shell_utils.rb +0 -67
  90. data/lib/tap/test.rb +0 -77
  91. data/lib/tap/test/assertions.rb +0 -38
  92. data/lib/tap/test/env_vars.rb +0 -29
  93. data/lib/tap/test/extensions.rb +0 -73
  94. data/lib/tap/test/file_test.rb +0 -362
  95. data/lib/tap/test/file_test_class.rb +0 -15
  96. data/lib/tap/test/regexp_escape.rb +0 -87
  97. data/lib/tap/test/script_test.rb +0 -46
  98. data/lib/tap/test/script_tester.rb +0 -115
  99. data/lib/tap/test/subset_test.rb +0 -260
  100. data/lib/tap/test/subset_test_class.rb +0 -99
  101. data/lib/tap/test/tap_test.rb +0 -109
  102. data/lib/tap/test/utils.rb +0 -231
data/doc/Tutorial DELETED
@@ -1,348 +0,0 @@
1
- = Tap (Task Application)
2
-
3
- Tap is a framework for creating configurable, distributable tasks and workflows.
4
- Although scalable for complex workflows, at it simplest tap works like a
5
- supercharged rake. Using the rap executable, you can declare tasks using a
6
- syntax almost identical to rake, but with added support for configurations and
7
- documentation.
8
-
9
- Note: this tutorial spans several modules in the {Tap-Suite}[http://tap.rubyforge.org/tap-suite].
10
- Be sure to install both tap and rap (or the full suite) beforehand.
11
-
12
- % gem install tap-suite
13
-
14
- == Quickstart
15
-
16
- If you've used rake, tap will be easy to pick up. To get started, make a
17
- Rapfile with a simple task declaration:
18
-
19
- [Rapfile]
20
-
21
- # ::desc your basic goodnight moon task
22
- # Says goodnight with a configurable message.
23
- Rap.task(:goodnight, :obj, :message => 'goodnight') do |task, args|
24
- puts "#{task.message} #{args.obj}\n"
25
- end
26
-
27
- Now from the command line:
28
-
29
- % rap goodnight moon
30
- goodnight moon
31
-
32
- % rap goodnight world --message hello
33
- hello world
34
-
35
- % rap goodnight --help
36
- Goodnight -- your basic goodnight moon task
37
- --------------------------------------------------------------------------------
38
- Says goodnight with a configurable message.
39
- --------------------------------------------------------------------------------
40
- usage: rap goodnight OBJ
41
-
42
- configurations:
43
- --message MESSAGE
44
-
45
- options:
46
- -h, --help Print this help
47
- --name NAME Specify a name
48
- --use FILE Loads inputs from file
49
-
50
- Just like that you have a command-line application with inputs, configuration,
51
- and documentation.
52
-
53
- The declaration syntax is obviously similar to rake; configurations are new but
54
- the task-block style is the same, as are inputs. Other rake constructs are
55
- available. Here is a similar goodnight task using dependencies, rake-style.
56
-
57
- [Rapfile]
58
-
59
- # make the declarations available everywhere
60
- # (normally they're accessed via Tap, as above)
61
- include Rap::Declarations
62
-
63
- namespace :example do
64
- task(:say, :message) do |task, args|
65
- print(args.message || 'goodnight')
66
- end
67
-
68
- desc "your basic goodnight moon task"
69
- task({:goodnight => 'example:say'}, :obj) do |task, args|
70
- puts " #{args.obj}\n"
71
- end
72
- end
73
-
74
- And now from the command line:
75
-
76
- % rap goodnight moon
77
- goodnight moon
78
-
79
- % rap goodnight world --* say hello
80
- hello world
81
-
82
- Unlike rake, rap inputs are written out individually and tasks are delimited
83
- by a modified double-dash. Aside from that, you can see rap is basically a
84
- supercharged rake. Furthermore, rap runs rake. Directly substitute rap for
85
- rake on the command line and your tasks should run as normal (see the Rap
86
- {Syntax Reference}[http://tap.rubyforge.org/rap/files/doc/Syntax%20Reference.html]
87
- for more details).
88
-
89
- However, supercharging rake isn't the point of Tap. Declarations bridge the
90
- gap between rake and tap, but tap itself is a more general framework. To get
91
- at other features like imperative workflows, testing, and distribution, we
92
- have to go beyond rap and take a look at what declarations do.
93
-
94
- Spoiler: declarations make subclasses of Tap::Task.
95
-
96
- == Beyond Rap
97
-
98
- Going back to the first example, lets take a look at how a task declaration
99
- maps to a class definition:
100
-
101
- [Rapfile]
102
-
103
- # ::desc your basic goodnight moon task
104
- # Says goodnight with a configurable message.
105
- Rap.task(:goodnight, :obj, :message => 'goodnight') do
106
- puts "#{task.message} #{args.obj}\n"
107
- end
108
-
109
- Here is a corresponding class:
110
-
111
- # Goodnight::manifest your basic goodnight moon task
112
- # Says goodnight with a configurable message.
113
- class Goodnight < Tap::Task
114
- config :message, 'goodnight'
115
-
116
- def process(obj)
117
- "#{message} #{obj}"
118
- end
119
- end
120
-
121
- Simple enough; the name corresponds to the class, configurations (and
122
- dependencies, although they aren't show) are written out individually, and the
123
- block corresponds to process. There are a few differences, especially relating
124
- to process, but for the moment lets gloss over them and see how Goodnight works.
125
-
126
- goodnight = Goodnight.new
127
- goodnight.message # => 'goodnight'
128
- goodnight.process('moon') # => 'goodnight moon'
129
-
130
- hello = Goodnight.new(:message => 'hello')
131
- hello.message # => 'hello'
132
- hello.process('world') # => 'hello world'
133
-
134
- Totally straightforward. Goodnight stores the default configurations, each
135
- instance has accessors to the configurations, and the defaults may be overridden
136
- during initialization, or later. Class definitions allow validation/transformation
137
- blocks to be specified for configurations. These blocks process inputs (ex the
138
- string inputs from the command line), quite literally defining the writer for a
139
- configuration accessor. A set of standard blocks are available through +c+, an
140
- alias for the {Configurable::Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]
141
- module.
142
-
143
- [lib/goodnight.rb]
144
-
145
- # Goodnight::manifest a fancy goodnight moon task
146
- # Says goodnight with a configurable message.
147
- class Goodnight < Tap::Task
148
- config :message, 'goodnight' # a goodnight message
149
- config :reverse, false, &c.switch # reverses the message
150
- config :n, 1, &c.integer # repeats message n times
151
-
152
- def process(*objects)
153
- print "#{reverse == true ? message.reverse : message} " * n
154
- puts objects.join(', ')
155
- puts
156
- end
157
- end
158
-
159
- A few examples show a validation block in action:
160
-
161
- goodnight = Goodnight.new
162
-
163
- goodnight.n = 10
164
- goodnight.n # => 10
165
-
166
- goodnight.n = "100"
167
- goodnight.n # => 100
168
-
169
- goodnight.n = "not an integer" # !> ValidationError
170
-
171
- Now from the command line:
172
-
173
- % rap goodnight moon
174
- goodnight moon
175
-
176
- % rap goodnight moon mittens "little toy boat"
177
- goodnight moon, mittens, little toy boat
178
-
179
- % rap goodnight world --message hello --reverse --n 3
180
- olleh olleh olleh world
181
-
182
- % rap goodnight --help
183
- Goodnight -- a fancy goodnight moon task
184
- --------------------------------------------------------------------------------
185
- Says goodnight with a configurable message.
186
- --------------------------------------------------------------------------------
187
- usage: rap goodnight OBJECTS...
188
-
189
- configurations:
190
- --message MESSAGE a goodnight message
191
- --[no-]reverse reverses the message
192
- --n N repeats message n times
193
-
194
- options:
195
- -h, --help Print this help
196
- --name NAME Specify a name
197
- --use FILE Loads inputs from file
198
-
199
- Take a quick look at the documentation. Class definitions map documentation
200
- and, in some cases, metadata to the command line; the configurations now have
201
- comments and reverse is a switch! Rich mapping allows tasks to act as an
202
- script interface, not unlike {OptionParser}[http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html]
203
- (check out the {Configurable}[http://tap.rubyforge.org/configurable/] gem and
204
- specifically {ConfigParser}[http://tap.rubyforge.org/configurable/classes/ConfigParser.html]
205
- for more details).
206
-
207
- This is a stand-alone goodnight script:
208
-
209
- [goodnight]
210
-
211
- #!/usr/bin/env ruby
212
-
213
- require 'rubygems'
214
- require 'tap'
215
-
216
- # Goodnight::manifest a goodnight moon script
217
- # Says goodnight with a configurable message.
218
- class Goodnight < Tap::Task
219
- config :message, 'goodnight'
220
-
221
- def process(obj)
222
- puts "#{message} #{obj}\n"
223
- end
224
- end
225
-
226
- instance, args = Goodnight.parse!(ARGV)
227
- instance.execute(*args)
228
-
229
- Now, from the command line:
230
-
231
- % ./goodnight moon
232
- goodnight moon
233
-
234
- % ./goodnight --help
235
- ...
236
-
237
- As simple as it is to take a task to the command line, it's nice to note that
238
- tasks may be subclassed, tested, and distributed as usual. No magic, just
239
- convenience.
240
-
241
- == Tap
242
-
243
- Tap comes with two executables, rap and tap. The tap executable is more
244
- verbose than rap for running tasks, but it is more configurable, scalable, and
245
- logically pure. Tap comes with a number of {commands}[link:/files/doc/Command%20Reference.html]
246
- but we'll focus on generate to make, test, and package a task library. Begin
247
- by creating a tap directory structure and a task:
248
-
249
- % tap generate root sample
250
- % cd sample
251
- % tap generate task goodnight
252
-
253
- Take a look at the task files and you find something like this:
254
-
255
- [lib/goodnight.rb]
256
-
257
- # Goodnight::manifest <replace with manifest summary>
258
- # <replace with command line description>
259
-
260
- # Goodnight Documentation
261
- class Goodnight < Tap::Task
262
-
263
- # <config file documentation>
264
- config :message, 'goodnight' # a sample config
265
-
266
- def process(name)
267
- log message, name
268
- "#{message} #{name}"
269
- end
270
- end
271
-
272
- [test/goodnight_test.rb]
273
-
274
- require File.join(File.dirname(__FILE__), 'tap_test_helper.rb')
275
- require 'goodnight'
276
-
277
- class GoodnightTest < Test::Unit::TestCase
278
- acts_as_tap_test
279
-
280
- def test_goodnight
281
- task = Goodnight.new :message => "goodnight"
282
-
283
- # a simple test
284
- assert_equal({:message => 'goodnight'}, task.config)
285
- assert_equal "goodnight moon", task.process("moon")
286
-
287
- # a more complex test
288
- task.enq("moon")
289
- app.run
290
-
291
- assert_equal ["goodnight moon"], app.results(task)
292
- assert_audit_equal [[nil, "moon"], [task, "goodnight moon"]], app._results(task)[0]
293
- end
294
- end
295
-
296
- Run the test:
297
-
298
- % rap test
299
-
300
- Run the task:
301
-
302
- % rap goodnight moon
303
- I[23:22:19] goodnight moon
304
-
305
- Ok, lets share it. Print the current gemspec manifest:
306
-
307
- % rap print_manifest
308
- true README
309
- Rakefile
310
- lib/goodnight.rb
311
- sample.gemspec
312
- true tap.yml
313
- test/goodnight_test.rb
314
- true test/tap_test_helper.rb
315
- true test/tap_test_suite.rb
316
-
317
- As you can see, this needs an update to include the task file. Open up
318
- sample.gemspec and fix the manifest.
319
-
320
- [sample.gemspec]
321
-
322
- Gem::Specification.new do |s|
323
- s.name = "sample"
324
- s.version = "0.0.1"
325
- s.platform = Gem::Platform::RUBY
326
- s.summary = "sample"
327
- s.require_path = "lib"
328
- s.add_dependency("tap")
329
- s.files = %W{
330
- lib/goodnight.rb
331
- tap.yml
332
- }
333
- end
334
-
335
- Now package the gem and install it (gem may require sudo):
336
-
337
- % rap gem
338
- % gem install pkg/sample-0.0.1.gem
339
-
340
- Now you can say goodnight anywhere, using 'tap run' or rap:
341
-
342
- % cd ~/Desktop
343
- % tap run -- goodnight moon
344
- goodnight moon
345
- % rap goodnight opus
346
- goodnight opus
347
-
348
- And that is that.
data/lib/tap/dump.rb DELETED
@@ -1,142 +0,0 @@
1
- module Tap
2
-
3
- # :startdoc::manifest the default dump task
4
- #
5
- # A dump task to output results. Unlike most tasks, dump does not enque
6
- # arguments from the command line; instead command line arguments are only
7
- # used to setup the dump. Specifically dump accepts a filepath.
8
- #
9
- # % tap run -- [task] --: dump FILEPATH
10
- #
11
- # Results that come to dump are appended to the file. Dump only accepts
12
- # one object at a time, so joins that produce an array need to iterate
13
- # outputs to dump:
14
- #
15
- # % tap run -- load hello -- load world "--2(0,1)i" dump
16
- #
17
- # Note that dump uses $stdout by default so you can pipe or redirect dumps
18
- # as normal.
19
- #
20
- # % tap run -- load hello --: dump | cat
21
- # hello
22
- #
23
- # % tap run -- load hello --: dump 1> results.txt
24
- # % cat results.txt
25
- # hello
26
- #
27
- # :startdoc::manifest-
28
- #
29
- # Dump serves as a baseclass for more complicated dump tasks. A YAML dump
30
- # task (see {tap-tasks}[http://tap.rubyforge.org/tap-tasks]) looks like this:
31
- #
32
- # class Yaml < Tap::Dump
33
- # def dump(obj, io)
34
- # YAML.dump(obj, io)
35
- # end
36
- # end
37
- #
38
- # === Implementation Notes
39
- #
40
- # Dump passes on the command line arguments to setup rather than process.
41
- # Moreover, process will always receive the audits passed to _execute, rather
42
- # than the audit values. This allows a user to provide setup arguments (such
43
- # as a dump path) on the command line, and provides dump the opportunity to
44
- # inspect audit trails within process.
45
- #
46
- class Dump < Tap::Task
47
- class << self
48
-
49
- # Same as an ordinary parse!, except the arguments normally reserved for
50
- # executing the task are used to call setup. The return will always be
51
- # an instance and an empty array.
52
- def parse!(argv=ARGV, app=Tap::App.instance)
53
- instance, args = super
54
- instance.setup(*args)
55
- [instance, []]
56
- end
57
- end
58
-
59
- lazy_attr :args, :setup
60
- lazy_register :setup, Lazydoc::Arguments
61
-
62
- config :date_format, '%Y-%m-%d %H:%M:%S' # The date format
63
- config :audit, false, &c.switch # Include the audit trails
64
- config :date, false, &c.switch # Include a date
65
-
66
- # The dump target, by default $stdout. Target may be a filepath,
67
- # in which case dumps append the file.
68
- attr_accessor :target
69
-
70
- def initialize(config={}, name=nil, app=App.instance)
71
- super(config, name, app)
72
- @target = $stdout
73
- end
74
-
75
- # Setup self with the input target. Setup receives arguments passed from
76
- # the command line, via parse!
77
- def setup(output=$stdout)
78
- @target = output
79
- self
80
- end
81
-
82
- # Overrides the standard _execute to send process the audits and not
83
- # the audit values. This allows process to inspect audit trails.
84
- def _execute(input)
85
- resolve_dependencies
86
-
87
- previous = input.kind_of?(Support::Audit) ? input : Support::Audit.new(nil, input)
88
- input = previous.value
89
-
90
- # this is the overridden part
91
- audit = Support::Audit.new(self, input, app.audit ? previous : nil)
92
- send(method_name, audit)
93
-
94
- if complete_block = on_complete_block || app.on_complete_block
95
- complete_block.call(audit)
96
- else
97
- app.aggregator.store(audit)
98
- end
99
-
100
- audit
101
- end
102
-
103
- # The default process prints dump headers as specified in the config,
104
- # then append the audit value to io.
105
- def process(_audit)
106
- open_io(target) do |io|
107
- if date
108
- io.puts "# date: #{Time.now.strftime(date_format)}"
109
- end
110
-
111
- if audit
112
- io.puts "# audit:"
113
- io.puts "# #{_audit.dump.gsub("\n", "\n# ")}"
114
- end
115
-
116
- dump(_audit.value, io)
117
- end
118
- end
119
-
120
- # Dumps the object to io, by default dump puts (not prints) obj.to_s.
121
- def dump(obj, io)
122
- io.puts obj.to_s
123
- end
124
-
125
- protected
126
-
127
- # helper to open and yield the io specified by target. open_io
128
- # ensures file targets are closed when the block returns.
129
- def open_io(io) # :nodoc:
130
- case io
131
- when IO, StringIO
132
- yield(io)
133
- when String
134
- dir = File.dirname(io)
135
- FileUtils.mkdir_p(dir) unless File.directory?(dir)
136
- File.open(io, 'a') {|file| yield(file) }
137
- else
138
- raise "cannot open io: #{target.inspect}"
139
- end
140
- end
141
- end
142
- end