tap 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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