tap 0.18.0 → 0.19.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.
@@ -1,330 +0,0 @@
1
- = Class Reference
2
-
3
- This is a ground-up overview of the main classes and modules used by Tap,
4
- specifically Tasks, Apps, and Envs.
5
-
6
- == Tasks
7
-
8
- ==== Tap::App::Node
9
-
10
- http://tap.rubyforge.org/images/Node.png
11
-
12
- Nodes are the building blocks of workflows. Nodes are essentially a method
13
- with an array of joins to call when the method completes. Any object
14
- responding to <tt>call</tt> may be turned into a node, so any method may be
15
- used in a workflow.
16
-
17
- Tasks are constructed so that <tt>call</tt> forwards arguments to
18
- <tt>process</tt>. This allows hooks and callbacks to be inserted as needed in
19
- subclasses.
20
-
21
- ==== {Configurable}[http://tap.rubyforge.org/configurable/]
22
-
23
- http://tap.rubyforge.org/images/Configurable.png
24
-
25
- Tap uses the {Configurable}[http://tap.rubyforge.org/configurable/] module to
26
- declare class configurations and make them available on the command line.
27
- Configurations provide a shorthand to define attributes with a default value.
28
- For instance:
29
-
30
- class ConfigClass
31
- include Configurable
32
-
33
- config :key, 'value' do |input|
34
- input.upcase
35
- end
36
-
37
- def initialize
38
- initialize_config
39
- end
40
- end
41
-
42
- Is basically the same as:
43
-
44
- class RegularClass
45
- attr_reader :key
46
-
47
- def key=(input)
48
- @key = input.upcase
49
- end
50
-
51
- def initialize
52
- self.key = 'value'
53
- end
54
- end
55
-
56
- Configurations may be accessed through a hash-like config object, as you can
57
- see here:
58
-
59
- c = ConfigClass.new
60
- c.key # => 'VALUE'
61
-
62
- c.config[:key] = 'new value'
63
- c.key # => 'NEW VALUE'
64
-
65
- c.key = 'another value'
66
- c.config[:key] # => 'ANOTHER VALUE'
67
-
68
- This setup is both fast and convenient. See the
69
- {Configurable}[http://tap.rubyforge.org/configurable] documentation for more
70
- information.
71
-
72
- ==== {Configurable::Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]
73
-
74
- When configurations are set from the command line, the config writer
75
- inevitably receives a string, even though you may want a non-string input. The
76
- {Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]
77
- module provides standard blocks to validate and transform inputs. These blocks
78
- may be accessed through the shortcut method <tt>c</tt> (ex: <tt>c.integer</tt>
79
- or <tt>c.regexp</tt>). Validation blocks generally load string inputs as
80
- YAML and validate that the result is the correct class; non-string inputs are
81
- simply validated.
82
-
83
- class ValidatingClass
84
- include Configurable
85
-
86
- config :int, 1, &c.integer # assures the input is an integer
87
- config :int_or_nil, 1, &c.integer_or_nil # integer or nil only
88
- config :array, [], &c.array # you get the idea
89
- end
90
-
91
- vc = ValidatingClass.new
92
-
93
- vc.array = [:a, :b, :c]
94
- vc.array # => [:a, :b, :c]
95
-
96
- vc.array = "[1, 2, 3]"
97
- vc.array # => [1, 2, 3]
98
-
99
- vc.array = "string" # !> ValidationError
100
-
101
- Validation blocks sometimes imply metadata. For instance <tt>c.flag</tt> makes
102
- a config into a flag on the command line.
103
-
104
- ==== {Lazydoc}[http://tap.rubyforge.org/lazydoc]
105
-
106
- {Lazydoc}[http://tap.rubyforge.org/lazydoc] fits into the space between live
107
- code and code documentation. Lazydoc scans files to pull documentation into
108
- the object space, and uses a syntax like this:
109
-
110
- # Constant::key value
111
- # comment
112
-
113
- For example:
114
-
115
- [lazydoc_file.rb]
116
- # Const::Name::key value
117
- #
118
- # This is an extended,
119
- # multiline comment.
120
- #
121
-
122
- require 'tap'
123
-
124
- lazydoc = Lazydoc[__FILE__]
125
- lazydoc.resolve
126
-
127
- lazydoc['Const::Name']['key'].value # => "value"
128
- lazydoc['Const::Name']['key'].comment # => "This is an extended, multiline comment."
129
-
130
- Lazydoc can also register specific lines for documentation, such as method
131
- definitions or configurations. Tap uses Lazydoc to identify files that contain
132
- resources like tasks and joins, to extract config documentation, and to infer
133
- the arguments a task receives from the command line. Here is an example of
134
- information gleaned from a task definition:
135
-
136
- # Sample::task a summary of the task
137
- class Sample < Tap::Task
138
- config :key, 'value' # a simple configuration
139
-
140
- def process(a, b='B', *c)
141
- end
142
- end
143
-
144
- Sample::desc.to_s # => "a summary of the task"
145
- Sample::args.to_s # => "A B='B' C..."
146
-
147
- key = Sample.configurations[:key]
148
- key.attributes[:desc].to_s # => "a simple configuration"
149
-
150
- See the {Lazydoc}[http://tap.rubyforge.org/lazydoc] documentation for more
151
- information.
152
-
153
- === Tap::Task
154
-
155
- http://tap.rubyforge.org/images/Task.png
156
-
157
- Tasks are the bread and butter of Tap. Tasks serve as nodes in workflows and
158
- map to the command line as miniature applications. Tasks are also useful as
159
- ordinary objects.
160
-
161
- Tasks may be dynamically generated on an app using the <tt>task</tt> method. This provides a quick way of sketching out a workflow.
162
-
163
- app = Tap::App.instance
164
- t = app.task {|task| 1 + 2 }
165
- t.process # => 3
166
-
167
- t = app.task {|task, x, y| x + y }
168
- t.process(1, 2) # => 3
169
-
170
- Tasks can be configured and joined into workflows.
171
-
172
- runlist = []
173
- results = []
174
-
175
- t1 = app.task(:key => 'one') do |task, input|
176
- runlist << task
177
- "#{input}:#{task.config[:key]}"
178
- end
179
-
180
- t2 = app.task do |task, input|
181
- runlist << task
182
- "#{input}:two"
183
- end
184
-
185
- t2.on_complete do |result|
186
- results << result
187
- end
188
-
189
- t1.sequence(t2)
190
-
191
- Results may be collected by the underlying Tap::App.
192
-
193
- app.enq(t1)
194
- app.run
195
-
196
- runlist # => [t1, t2]
197
- results # => ["input:one:two"]
198
-
199
- == Apps
200
-
201
- ==== Tap::App::Queue
202
-
203
- http://tap.rubyforge.org/images/Queue.png
204
-
205
- Apps coordinate the execution of nodes through a queue. The queue is just a
206
- stack of nodes and inputs; during a run the nodes are sequentially executed
207
- with the inputs.
208
-
209
- === Tap::App
210
-
211
- http://tap.rubyforge.org/images/App.png
212
-
213
- Instances of Tap::App coordinate the execution of nodes.
214
-
215
- Task initialization requires an App, which is by default Tap::App.instance.
216
- Tasks use their app for logging, dependency-resolution, checks, and to enque
217
- themselves.
218
-
219
- results = []
220
- app = Tap::App.new {|result| results << result }
221
- t = app.task {|task, *inputs| inputs }
222
- t.enq(1)
223
- t.enq(2,3)
224
-
225
- app.queue.to_a # => [[t, [1]], [t, [2,3]]]
226
- app.run
227
- results # => [[1], [2,3]]
228
-
229
- == Envs
230
-
231
- ==== Tap::Root
232
-
233
- http://tap.rubyforge.org/images/Root.png
234
-
235
- A Root represents the base of a directory structure. Roots allow you to alias
236
- relative paths, basically allowing you to develop code for a conceptual
237
- directory structure that can be defined later.
238
-
239
- root = Tap::Root.new '/path/to/root'
240
- root.root # => '/path/to/root'
241
- root['config'] # => '/path/to/root/config'
242
- root.path('config', 'sample.yml') # => '/path/to/root/config/sample.yml'
243
-
244
- While simple, this ability to alias paths is useful, powerful, and forms the
245
- basis of the Tap environment.
246
-
247
- ==== Tap::Env
248
-
249
- http://tap.rubyforge.org/images/Env.png
250
-
251
- Envs generate manifests of various resources (tasks, generators, etc) and
252
- provide methods to uniquely identify resources using minimized base paths.
253
- In this directory structure:
254
-
255
- path
256
- `- to
257
- |- another
258
- | `- file.rb
259
- |- file-0.1.0.rb
260
- |- file-0.2.0.rb
261
- `- file.rb
262
-
263
- The minimal paths that uniquely identify these files are (respectively):
264
-
265
- 'another/file'
266
- 'file-0.1.0'
267
- 'file-0.2.0'
268
- 'file.rb'
269
-
270
- Envs facilitate mapping a minimal path to an actual path, and hence to a
271
- resource. Envs can be nested so that manifests span multiple directories.
272
- Indeed, this is how tap accesses tasks and generators within gems; the gem
273
- directories are initialized as Envs and nested within the Env for the working
274
- directory.
275
-
276
- http://tap.rubyforge.org/images/Nested-Env.png
277
-
278
- To prevent conflicts between similarly-named resources under different Envs,
279
- Env allows selection of Envs, also by minimized paths. Say you installed the
280
- 'tap-tasks' gem.
281
-
282
- % tap manifest
283
- --------------------------------------------------------------------------------
284
- Desktop: (/Users/username/Desktop)
285
- --------------------------------------------------------------------------------
286
- tap-tasks: (/Library/Ruby/Gems/1.8/gems/tap-tasks-0.1.0)
287
- tasks
288
- argv (lib/tap/tasks/argv.rb)
289
- inspect (lib/tap/tasks/dump/inspect.rb)
290
- dump/yaml (lib/tap/tasks/dump/yaml.rb)
291
- load/yaml (lib/tap/tasks/load/yaml.rb)
292
- --------------------------------------------------------------------------------
293
- tap: (/Library/Ruby/Gems/1.8/gems/tap-0.12.4)
294
- commands
295
- console (cmd/console.rb)
296
- destroy (cmd/destroy.rb)
297
- generate (cmd/generate.rb)
298
- manifest (cmd/manifest.rb)
299
- run (cmd/run.rb)
300
- generators
301
- command (lib/tap/generator/generators/command/command_generator.rb)
302
- config (lib/tap/generator/generators/config/config_generator.rb)
303
- generator (lib/tap/generator/generators/generator/generator_generator.rb)
304
- root (lib/tap/generator/generators/root/root_generator.rb)
305
- task (lib/tap/generator/generators/task/task_generator.rb)
306
- tasks
307
- dump (lib/tap/dump.rb)
308
- load (lib/tap/load.rb)
309
- --------------------------------------------------------------------------------
310
-
311
- Desktop
312
- |- tap-tasks
313
- `- tap
314
-
315
- In this printout of the manifest, you can see the resources available to tap
316
- on the Desktop (none), in the tap-tasks gem, and in tap itself. In most cases
317
- the minipath of any of the tasks is sufficient for identification:
318
-
319
- % tap run -- load --: dump/yaml
320
-
321
- If there were a conflict, you'd have to specify the environment minipath like:
322
-
323
- % tap run -- tap:load --: tap-tasks:dump/yaml
324
-
325
- ==== Tap::Exe
326
-
327
- http://tap.rubyforge.org/images/Run-Env.png
328
-
329
- Tap::Exe adds methods for building and executing workflows from command line
330
- inputs.
@@ -1,130 +0,0 @@
1
- require 'tap/env'
2
- require 'tap/task'
3
- require 'tap/schema'
4
-
5
- module Tap
6
- module Exe
7
-
8
- # Adapted from Gem.find_home
9
- # def self.user_home
10
- # ['HOME', 'USERPROFILE'].each do |homekey|
11
- # return ENV[homekey] if ENV[homekey]
12
- # end
13
- #
14
- # if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
15
- # return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
16
- # end
17
- #
18
- # begin
19
- # File.expand_path("~")
20
- # rescue
21
- # File::ALT_SEPARATOR ? "C:/" : "/"
22
- # end
23
- # end
24
-
25
- # Setup an execution environment.
26
- def self.setup(options={}, argv=ARGV, env=ENV)
27
- if argv[-1] == "-d-"
28
- argv.pop
29
- $DEBUG = true
30
- end
31
-
32
- options = {
33
- :dir => Dir.pwd,
34
- :config_file => CONFIG_FILE
35
- }.merge(options)
36
-
37
- # load configurations
38
- dir = options.delete(:dir)
39
- config_file = options.delete(:config_file)
40
- user_config_file = config_file ? File.join(dir, config_file) : nil
41
-
42
- user = Env.load_config(user_config_file)
43
- global = {}
44
- env.each_pair do |key, value|
45
- if key =~ /\ATAP_(.*)\z/
46
- global[$1.downcase] = value
47
- end
48
- end
49
-
50
- config = {
51
- 'root' => dir,
52
- 'gems' => :all
53
- }.merge(global).merge(user).merge(options)
54
-
55
- # keys must be symbolize as they are immediately
56
- # used to initialize the Env configs
57
- config = config.inject({}) do |options, (key, value)|
58
- options[key.to_sym || key] = value
59
- options
60
- end
61
-
62
- # instantiate
63
- exe = Env.new(config, :basename => config_file).extend(Exe)
64
-
65
- exe.register('command') do |env|
66
- env.root.glob(:cmd, "**/*.rb")
67
- end
68
-
69
- # add the tap env if necessary
70
- unless exe.any? {|env| env.root.root == TAP_HOME }
71
- exe.push Env.new(TAP_HOME, exe.context)
72
- end
73
-
74
- exe
75
- end
76
-
77
- # The config file path
78
- CONFIG_FILE = "tap.yml"
79
-
80
- # The home directory for Tap
81
- TAP_HOME = File.expand_path("#{File.dirname(__FILE__)}/../..")
82
-
83
- def launch(argv=ARGV)
84
- case command = argv.shift.to_s
85
- when '', '--help'
86
- yield
87
- else
88
- if path = seek('command', command)
89
- load path # run the command, if it exists
90
- else
91
- puts "Unknown command: '#{command}'"
92
- puts "Type 'tap --help' for usage information."
93
- end
94
- end
95
- end
96
-
97
- def self.set_signals(app)
98
- # info signal -- Note: some systems do
99
- # not support the INFO signal
100
- # (windows, fedora, at least)
101
- signals = Signal.list.keys
102
- Signal.trap("INFO") do
103
- puts app.info
104
- end if signals.include?("INFO")
105
-
106
- # interuption signal
107
- Signal.trap("INT") do
108
- puts " interrupted!"
109
- # prompt for decision
110
- while true
111
- print "stop, terminate, exit, or resume? (s/t/e/r):"
112
- case gets.strip
113
- when /s(top)?/i
114
- app.stop
115
- break
116
- when /t(erminate)?/i
117
- app.terminate
118
- break
119
- when /e(xit)?/i
120
- exit
121
- when /r(esume)?/i
122
- break
123
- else
124
- puts "unexpected response..."
125
- end
126
- end
127
- end if signals.include?("INT")
128
- end
129
- end
130
- end