rap 0.12.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.
- data/History +8 -0
- data/MIT-LICENSE +19 -0
- data/README +117 -0
- data/bin/rap +116 -0
- data/doc/Command Reference +22 -0
- data/doc/Syntax Reference +82 -0
- data/lib/rap/declaration_task.rb +114 -0
- data/lib/rap/declarations.rb +213 -0
- data/lib/rap/description.rb +32 -0
- data/lib/rap/rake.rb +54 -0
- data/lib/rap/rake_app.rb +107 -0
- data/tap.yml +0 -0
- metadata +81 -0
data/History
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
== 0.12.0 / 2009-02-17
|
2
|
+
|
3
|
+
As of the 0.12.0 release, Tap is distributed as several independent modules.
|
4
|
+
This is the rap module. The core classes have been cleaned up significantly
|
5
|
+
since the 0.11 series, and some changes are not backwards compatible.
|
6
|
+
|
7
|
+
* Significant cleanup of declarations
|
8
|
+
* Refactored Tap::Declarations as Rap::Declarations
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009, Regents of the University of Colorado.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
4
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
5
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
6
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
7
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
+
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
10
|
+
substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
16
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
17
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
19
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
= {Rap (Rakish App)}[http://tap.rubyforge.org/rap]
|
2
|
+
|
3
|
+
rap v. a quick, sharp knock or blow
|
4
|
+
rakish adj. having a dashing, jaunty, or slightly disreputable quality or appearance
|
5
|
+
|
6
|
+
A rakish extension to {Tap}[http://tap.rubyforge.org/rdoc].
|
7
|
+
|
8
|
+
== Description
|
9
|
+
|
10
|
+
Rap supercharges the syntax of Rake by adding configurations, extended
|
11
|
+
documentation, and class-based tasks that are easy to test.
|
12
|
+
|
13
|
+
Rap is a part of the {Tap-Suite}[http://tap.rubyforge.org/tap-suite].
|
14
|
+
Check out these links for documentation, development, and bug tracking.
|
15
|
+
|
16
|
+
* Website[http://tap.rubyforge.org]
|
17
|
+
* Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/9908-tap-task-application/tickets]
|
18
|
+
* Github[http://github.com/bahuvrihi/tap/tree/master]
|
19
|
+
* {Google Group}[http://groups.google.com/group/ruby-on-tap]
|
20
|
+
|
21
|
+
== Usage
|
22
|
+
|
23
|
+
Usage is much like {rake}[http://rake.rubyforge.org/]:
|
24
|
+
|
25
|
+
[Rapfile]
|
26
|
+
require 'rap/declarations'
|
27
|
+
include Rap::Declarations
|
28
|
+
|
29
|
+
desc "your basic goodnight moon task"
|
30
|
+
|
31
|
+
# Says goodnight with a configurable message.
|
32
|
+
task(:goodnight, :obj, :message => 'goodnight') do |task, args|
|
33
|
+
puts "#{task.message} #{args.obj}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
Now from the command line:
|
37
|
+
|
38
|
+
% rap goodnight moon
|
39
|
+
goodnight moon
|
40
|
+
|
41
|
+
% rap goodnight world --message hello
|
42
|
+
hello world
|
43
|
+
|
44
|
+
% rap goodnight --help
|
45
|
+
Goodnight -- your basic goodnight moon task
|
46
|
+
--------------------------------------------------------------------------------
|
47
|
+
Says goodnight with a configurable message.
|
48
|
+
--------------------------------------------------------------------------------
|
49
|
+
usage: rap goodnight OBJ
|
50
|
+
|
51
|
+
configurations:
|
52
|
+
--message MESSAGE
|
53
|
+
|
54
|
+
options:
|
55
|
+
-h, --help Print this help
|
56
|
+
--name NAME Specify a name
|
57
|
+
--use FILE Loads inputs from file
|
58
|
+
|
59
|
+
For testing, load the Rapfile and access the task as a constant.
|
60
|
+
|
61
|
+
[test.rb]
|
62
|
+
load 'Rapfile'
|
63
|
+
require 'test/unit'
|
64
|
+
require 'stringio'
|
65
|
+
|
66
|
+
class RapfileTest < Test::Unit::TestCase
|
67
|
+
def test_the_goodnight_task
|
68
|
+
$stdout = StringIO.new
|
69
|
+
|
70
|
+
task = Goodnight.new
|
71
|
+
assert_equal 'goodnight', task.message
|
72
|
+
|
73
|
+
task.process('moon')
|
74
|
+
assert_equal "goodnight moon", $stdout.string
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
The test passes:
|
79
|
+
|
80
|
+
% ruby test.rb
|
81
|
+
Loaded suite test
|
82
|
+
Started
|
83
|
+
.
|
84
|
+
Finished in 0.004921 seconds.
|
85
|
+
|
86
|
+
1 tests, 2 assertions, 0 failures, 0 errors
|
87
|
+
|
88
|
+
Generally speaking, the rap executable is a shorthand for 'tap run --' so you
|
89
|
+
can use rap to quickly launch workflows as well. See the
|
90
|
+
{Command}[link:files/doc/Command%20Reference.html] and
|
91
|
+
{Syntax}[link:files/doc/Syntax%20Reference.html] References for more information.
|
92
|
+
|
93
|
+
=== Limitations
|
94
|
+
|
95
|
+
Rap is not a pure replacement of Rake. Rap does not support builds by default,
|
96
|
+
classes like FileList are not included, and namespace lookup is slightly
|
97
|
+
different (see the {Syntax Reference}[link:files/doc/Syntax%20Reference.html]).
|
98
|
+
|
99
|
+
== Installation
|
100
|
+
|
101
|
+
Rap is available as a gem on RubyForge[http://rubyforge.org/projects/tap]. Use:
|
102
|
+
|
103
|
+
% gem install rap
|
104
|
+
|
105
|
+
Rap requires an updated version of RubyGems[http://docs.rubygems.org/]
|
106
|
+
(>= 1.2.0). To check the version and update RubyGems:
|
107
|
+
|
108
|
+
% gem --version
|
109
|
+
% gem --update system
|
110
|
+
|
111
|
+
== Info
|
112
|
+
|
113
|
+
Copyright (c) 2009, Regents of the University of Colorado.
|
114
|
+
Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com], {Biomolecular Structure Program}[http://biomol.uchsc.edu/], {Hansen Lab}[http://hsc-proteomics.uchsc.edu/hansenlab/]
|
115
|
+
Support:: CU Denver School of Medicine Deans Academic Enrichment Fund
|
116
|
+
Licence:: {MIT-Style}[link:files/MIT-LICENSE.html]
|
117
|
+
|
data/bin/rap
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# usage: rap taskname {options} [args]
|
3
|
+
|
4
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
5
|
+
require 'rap/declarations'
|
6
|
+
|
7
|
+
# setup the environment
|
8
|
+
begin
|
9
|
+
|
10
|
+
# handle super options
|
11
|
+
$DEBUG = true if ARGV.delete('-d-')
|
12
|
+
env = Tap::Exe.instantiate
|
13
|
+
env.unshift(Rap::Declarations.env)
|
14
|
+
|
15
|
+
Dir.glob('[TtRr]apfile{,.rb}').each do |task_file|
|
16
|
+
task_file = File.expand_path(task_file)
|
17
|
+
next unless File.file?(task_file)
|
18
|
+
|
19
|
+
env.loads.unshift(task_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
rescue(Tap::Env::ConfigError)
|
23
|
+
# catch errors and exit gracefully
|
24
|
+
# (errors usu from gem loading errors)
|
25
|
+
puts $!.message
|
26
|
+
exit(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# setup after script
|
31
|
+
#
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
begin
|
35
|
+
eval(env.after) if env.after != nil
|
36
|
+
rescue(Exception)
|
37
|
+
puts "Error in after script."
|
38
|
+
env.handle_error($!)
|
39
|
+
exit(1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# run before script
|
45
|
+
#
|
46
|
+
|
47
|
+
begin
|
48
|
+
eval(env.before) if env.before != nil
|
49
|
+
rescue(Exception)
|
50
|
+
puts "Error in before script."
|
51
|
+
env.handle_error($!)
|
52
|
+
exit(1)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# run rap
|
57
|
+
#
|
58
|
+
|
59
|
+
module Rap
|
60
|
+
autoload(:Rake, 'rap/rake')
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
env.activate
|
65
|
+
|
66
|
+
case ARGV[0]
|
67
|
+
when '--help', nil, '-T'
|
68
|
+
rap_template = %Q{<% if count > 1 && !entries.empty? %>
|
69
|
+
<%= env_name %>:
|
70
|
+
<% end %>
|
71
|
+
<% entries.each do |name, const| %>
|
72
|
+
<% desc = if const.require_path == nil # should be a declaration %>
|
73
|
+
<% manifest = const.constantize.manifest %>
|
74
|
+
<% next if manifest == nil || manifest.empty? %>
|
75
|
+
<% manifest %>
|
76
|
+
<% else %>
|
77
|
+
<% const.document[const.name]['manifest'] %>
|
78
|
+
<% end %>
|
79
|
+
<%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
|
80
|
+
<% end %>}
|
81
|
+
|
82
|
+
puts Lazydoc.usage(__FILE__)
|
83
|
+
puts
|
84
|
+
puts "=== tap tasks ==="
|
85
|
+
puts env.summarize(:tasks, rap_template)
|
86
|
+
puts
|
87
|
+
puts "=== rake tasks ==="
|
88
|
+
Rap::Rake.new.enq('-T')
|
89
|
+
Tap::App.instance.run
|
90
|
+
|
91
|
+
# this is not currently reached as rake exits on -T
|
92
|
+
puts
|
93
|
+
puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
|
94
|
+
exit
|
95
|
+
else
|
96
|
+
env.set_signals
|
97
|
+
env.build(ARGV) do |args|
|
98
|
+
warn "warning: implict rake for [#{args.join(' ')}]"
|
99
|
+
Rap::Rake
|
100
|
+
end
|
101
|
+
ARGV.clear
|
102
|
+
|
103
|
+
app = env.app
|
104
|
+
if app.queue.empty?
|
105
|
+
puts "no task specified"
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
|
109
|
+
app.run
|
110
|
+
end
|
111
|
+
|
112
|
+
rescue
|
113
|
+
env.handle_error($!)
|
114
|
+
end
|
115
|
+
|
116
|
+
exit(0)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
= Command Reference
|
2
|
+
|
3
|
+
Rap comes the rap executable. For help on the command line, type:
|
4
|
+
|
5
|
+
% rap --help
|
6
|
+
|
7
|
+
The rap executable is basically a shorthand for 'tap run --'. Specifying tasks
|
8
|
+
for rap is no different than 'tap run' (see the Tap {Command Reference}[http://tap.rubyforge.org/rdoc/files/doc/Command%20Reference.html]).
|
9
|
+
The only exception occurs when the task can't be found; unknown tasks are run
|
10
|
+
as if by rake. For instance all of these are the same:
|
11
|
+
|
12
|
+
Run a rake task with inputs and an ENV config:
|
13
|
+
|
14
|
+
% rake task_name[1,2,3] key=value
|
15
|
+
|
16
|
+
Explicitly run a Rap::Rake task using the same inputs:
|
17
|
+
|
18
|
+
% rap rake task_name[1,2,3] key=value
|
19
|
+
|
20
|
+
Implicitly run the Rap::Rake task:
|
21
|
+
|
22
|
+
% rap task_name[1,2,3] key=value
|
@@ -0,0 +1,82 @@
|
|
1
|
+
= Syntax Reference
|
2
|
+
|
3
|
+
== Task Declarations
|
4
|
+
|
5
|
+
A task declaration:
|
6
|
+
|
7
|
+
# name:: the name of the task, either alone or as the
|
8
|
+
# key of a {key => dependencies} hash
|
9
|
+
# dependencies:: an array of task names (optional)
|
10
|
+
# arg_names:: an array of argument names (optional)
|
11
|
+
# configurations:: a hash of {key => default} pairs (optional)
|
12
|
+
|
13
|
+
task({<name> => [<dependencies...>]}, <arg_names...>, {<configs>}) do |task, args|
|
14
|
+
# arguments are available through args:
|
15
|
+
args.arg_name
|
16
|
+
|
17
|
+
# configurations are available through task
|
18
|
+
task.key
|
19
|
+
end
|
20
|
+
|
21
|
+
A namespace declaration:
|
22
|
+
|
23
|
+
namespace(<name>) { task ... }
|
24
|
+
|
25
|
+
Simple documentation:
|
26
|
+
|
27
|
+
desc "description"
|
28
|
+
task ...
|
29
|
+
|
30
|
+
Extended documentation:
|
31
|
+
|
32
|
+
# ::desc description
|
33
|
+
# Extended documentation may span multiple lines, and
|
34
|
+
# supports
|
35
|
+
#
|
36
|
+
# code indentation
|
37
|
+
# like this.
|
38
|
+
#
|
39
|
+
# Lines are justified and wrapped on the command line.
|
40
|
+
task ...
|
41
|
+
|
42
|
+
Pains were taken to make task declarations for rap work the similar to rake
|
43
|
+
tasks. In both cases (noting that in general, beyond rap, task classes are
|
44
|
+
not limited in these ways):
|
45
|
+
|
46
|
+
* tasks are singleton instances that may be extended across multiple
|
47
|
+
declarations
|
48
|
+
* tasks do not pass inputs from one task to the next
|
49
|
+
* tasks only execute once
|
50
|
+
|
51
|
+
A few syntactical differences between rake and rap must to be noted, as they
|
52
|
+
can cause errors if you try to migrate rake tasks to tap.
|
53
|
+
|
54
|
+
==== no needs
|
55
|
+
|
56
|
+
Rap does not support :needs as a way to specify dependencies. For instance,
|
57
|
+
this will declare a ':needs' configuration with the default value ':another',
|
58
|
+
not a task which depends on another:
|
59
|
+
|
60
|
+
Rap.task :name, :needs => :another
|
61
|
+
|
62
|
+
==== immediate namespace lookup
|
63
|
+
|
64
|
+
Within a namespace, task will look for a literal match to the dependency first.
|
65
|
+
If it doesn't find one, it will declare it within the namespace; one way or the
|
66
|
+
other the dependency is resolved to a constant immediately. Hence, in this
|
67
|
+
example the nested task depends on the non-nested task.
|
68
|
+
|
69
|
+
task :outer { print 'non-nested' }
|
70
|
+
namespace :nest do
|
71
|
+
task :inner => :outer { puts 'was executed' }
|
72
|
+
task :outer { print 'nested' }
|
73
|
+
end
|
74
|
+
|
75
|
+
By contrast, rake waits to resolve dependencies and will always use a match
|
76
|
+
within a namespace in preference to a literal match. For these tasks rap and
|
77
|
+
rake produce different results:
|
78
|
+
|
79
|
+
% rap nest/inner
|
80
|
+
non-nested was executed
|
81
|
+
% rake nest:inner
|
82
|
+
nested was executed
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'tap'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'rap/description'
|
4
|
+
|
5
|
+
module Rap
|
6
|
+
|
7
|
+
# DeclarationTasks are a singleton version of tasks. DeclarationTasks only
|
8
|
+
# have one instance (DeclarationTask.instance) and the instance is
|
9
|
+
# registered as a dependency, so it will only execute once.
|
10
|
+
class DeclarationTask < Tap::Task
|
11
|
+
class << self
|
12
|
+
attr_writer :actions
|
13
|
+
|
14
|
+
# An array of actions (blocks) associated with this class. Each of the
|
15
|
+
# actions is called during process, with the instance and any args
|
16
|
+
# passed to process organized into an OpenStruct.
|
17
|
+
def actions
|
18
|
+
@actions ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_writer :arg_names
|
22
|
+
|
23
|
+
# The argument names pulled from a task declaration.
|
24
|
+
def arg_names
|
25
|
+
@arg_names ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a Lazydoc::Arguments constructed from arg_names.
|
29
|
+
def args
|
30
|
+
args = Lazydoc::Arguments.new
|
31
|
+
arg_names.each {|name| args.arguments << name.to_s }
|
32
|
+
args
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initializes instance and registers it as a dependency.
|
36
|
+
def new(*args)
|
37
|
+
@instance ||= super
|
38
|
+
@instance.app.dependencies.register(@instance)
|
39
|
+
@instance
|
40
|
+
end
|
41
|
+
|
42
|
+
# Looks up or creates the DeclarationTask subclass specified by name
|
43
|
+
# (nested within declaration_base), and adds the configs and dependencies.
|
44
|
+
# Declare also registers the subclass in the declaration_env tasks
|
45
|
+
# manifest.
|
46
|
+
#
|
47
|
+
# Configurations are always validated using the yaml transformation block
|
48
|
+
# (see {Configurable::Validation.yaml}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]).
|
49
|
+
#
|
50
|
+
def subclass(const_name, configs={}, dependencies=[])
|
51
|
+
# lookup or generate the subclass
|
52
|
+
subclass = Tap::Support::Constant.constantize(const_name.to_s) do |base, constants|
|
53
|
+
subclass_const = constants.pop
|
54
|
+
constants.inject(base) do |namespace, const|
|
55
|
+
# nesting Task classes into other Task classes is required
|
56
|
+
# for namespaces with the same name as a task
|
57
|
+
namespace.const_set(const, Class.new(DeclarationTask))
|
58
|
+
end.const_set(subclass_const, Class.new(self))
|
59
|
+
end
|
60
|
+
|
61
|
+
# check a correct class was found
|
62
|
+
unless subclass.ancestors.include?(self)
|
63
|
+
raise "not a #{self}: #{subclass}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# append configuration (note that specifying a desc
|
67
|
+
# prevents lazydoc registration of these lines)
|
68
|
+
convert_to_yaml = Configurable::Validation.yaml
|
69
|
+
configs.each_pair do |key, value|
|
70
|
+
subclass.send(:config, key, value, :desc => "", &convert_to_yaml)
|
71
|
+
end
|
72
|
+
|
73
|
+
# add dependencies
|
74
|
+
dependencies.each do |dependency|
|
75
|
+
dependency_name = File.basename(dependency.default_name)
|
76
|
+
subclass.send(:depends_on, dependency_name, dependency)
|
77
|
+
end
|
78
|
+
|
79
|
+
subclass
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# overridden to provide self as the declaration_class
|
85
|
+
def declaration_class # :nodoc:
|
86
|
+
self
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Collects the inputs into an OpenStruct according to the class arg_names,
|
91
|
+
# and calls each class action in turn. This behavior echoes the behavior
|
92
|
+
# of Rake tasks.
|
93
|
+
def process(*inputs)
|
94
|
+
# collect inputs to make a rakish-args object
|
95
|
+
args = {}
|
96
|
+
self.class.arg_names.each do |arg_name|
|
97
|
+
break if inputs.empty?
|
98
|
+
args[arg_name] = inputs.shift
|
99
|
+
end
|
100
|
+
args = OpenStruct.new(args)
|
101
|
+
|
102
|
+
# execute each block assciated with this task
|
103
|
+
self.class.actions.each do |action|
|
104
|
+
case action.arity
|
105
|
+
when 0 then action.call()
|
106
|
+
when 1 then action.call(self)
|
107
|
+
else action.call(self, args)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'rap/declaration_task'
|
2
|
+
require 'tap/support/shell_utils'
|
3
|
+
|
4
|
+
module Rap
|
5
|
+
|
6
|
+
# Defines the rakish task declaration methods. They may be included at the
|
7
|
+
# top level (like Rake) or, since they included as a part of the API, used
|
8
|
+
# through Rap.
|
9
|
+
#
|
10
|
+
# Unlike rake, task will define actual task classes according to the task
|
11
|
+
# names. Task classes may be nested within modules using namespace. It's
|
12
|
+
# VERY important to realize this is the case both to aid in thing like
|
13
|
+
# testing and to prevent namespace conflicts. For example:
|
14
|
+
#
|
15
|
+
# Rap.task(:sample) # => Sample.instance
|
16
|
+
# Rap.namespace(:nested) do
|
17
|
+
# Rap.task(:sample) # => Nested::Sample.instance
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Normally all declared tasks are subclasses of DeclarationTask. An easy
|
21
|
+
# way to use an existing subclasses of DeclarationTask as a base task is
|
22
|
+
# to call declare on the subclass. This feature is only available to
|
23
|
+
# subclasses of DeclarationTask, but can be used within namespaces, and in
|
24
|
+
# conjunction with desc.
|
25
|
+
#
|
26
|
+
# class Alt < DeclarationTask
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# include Rap::Declarations
|
30
|
+
#
|
31
|
+
# desc "task one, a subclass of DeclarationTask"
|
32
|
+
# o = Rap.task(:one)
|
33
|
+
# o.class # => One
|
34
|
+
# o.class.superclass # => DeclarationTask
|
35
|
+
# o.class.manifest.desc # => "task one, a subclass of DeclarationTask"
|
36
|
+
#
|
37
|
+
# namespace(:nest) do
|
38
|
+
#
|
39
|
+
# desc "task two, a nested subclass of Alt"
|
40
|
+
# t = Alt.declare(:two)
|
41
|
+
# t.class # => Nest::Two
|
42
|
+
# t.class.superclass # => Alt
|
43
|
+
# t.class.manifest.desc # => "task two, a nested subclass of Alt"
|
44
|
+
#
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# See the {Syntax Reference}[link:files/doc/Syntax%20Reference.html] for usage.
|
48
|
+
module Declarations
|
49
|
+
include Tap::Support::ShellUtils
|
50
|
+
|
51
|
+
# The environment in which declared task classes are registered.
|
52
|
+
# By default the Tap::Env for Dir.pwd.
|
53
|
+
def Declarations.env() @@env ||= Tap::Env.instantiate(Dir.pwd); end
|
54
|
+
|
55
|
+
# Sets the declaration environment.
|
56
|
+
def Declarations.env=(env) @@env=env; end
|
57
|
+
|
58
|
+
# The base constant for all task declarations, prepended to the task name.
|
59
|
+
def Declarations.current_namespace() @@current_namespace; end
|
60
|
+
@@current_namespace = ''
|
61
|
+
|
62
|
+
# Tracks the current description, which will be used to
|
63
|
+
# document the next task declaration.
|
64
|
+
def Declarations.current_desc() @@current_desc; end
|
65
|
+
@@current_desc = nil
|
66
|
+
|
67
|
+
# Declares a task with a rake-like syntax. Task generates a subclass of
|
68
|
+
# DeclarationTask, nested within the current namespace.
|
69
|
+
def task(*args, &action)
|
70
|
+
# resolve arguments and declare unknown dependencies
|
71
|
+
name, configs, dependencies, arg_names = resolve_args(args) do |dependency|
|
72
|
+
register DeclarationTask.subclass(dependency)
|
73
|
+
end
|
74
|
+
|
75
|
+
# generate the task class
|
76
|
+
const_name = File.join(@@current_namespace, name.to_s).camelize
|
77
|
+
task_class = register declaration_class.subclass(const_name, configs, dependencies)
|
78
|
+
|
79
|
+
# register documentation
|
80
|
+
manifest = Lazydoc.register_caller(Description)
|
81
|
+
manifest.desc = @@current_desc
|
82
|
+
@@current_desc = nil
|
83
|
+
|
84
|
+
task_class.arg_names = arg_names
|
85
|
+
task_class.manifest = manifest
|
86
|
+
task_class.source_file = manifest.document.source_file
|
87
|
+
|
88
|
+
# add the action
|
89
|
+
task_class.actions << action if action
|
90
|
+
|
91
|
+
# return the instance
|
92
|
+
task_class.instance
|
93
|
+
end
|
94
|
+
|
95
|
+
# Nests tasks within the named module for the duration of the block.
|
96
|
+
# Namespaces may be nested.
|
97
|
+
def namespace(name)
|
98
|
+
previous_namespace = @@current_namespace
|
99
|
+
@@current_namespace = File.join(previous_namespace, name.to_s.underscore)
|
100
|
+
yield
|
101
|
+
@@current_namespace = previous_namespace
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets the description for use by the next task declaration.
|
105
|
+
def desc(str)
|
106
|
+
@@current_desc = str
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# A helper to resolve the arguments for a task; returns the array
|
112
|
+
# [task_name, configs, needs, arg_names].
|
113
|
+
#
|
114
|
+
# Adapted from Rake 0.8.3
|
115
|
+
# Changes:
|
116
|
+
# - no :needs support for the trailing Hash (which is now config)
|
117
|
+
def resolve_args(args)
|
118
|
+
task_name = args.shift
|
119
|
+
arg_names = args
|
120
|
+
configs = {}
|
121
|
+
needs = []
|
122
|
+
|
123
|
+
# resolve hash task_names, for the syntax:
|
124
|
+
# task :name => [dependencies]
|
125
|
+
if task_name.is_a?(Hash)
|
126
|
+
hash = task_name
|
127
|
+
case hash.length
|
128
|
+
when 0
|
129
|
+
task_name = nil
|
130
|
+
when 1
|
131
|
+
task_name = hash.keys[0]
|
132
|
+
needs = hash[task_name]
|
133
|
+
else
|
134
|
+
raise ArgumentError, "multiple task names specified: #{hash.keys.inspect}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# ensure a task name is specified
|
139
|
+
if task_name == nil
|
140
|
+
raise ArgumentError, "no task name specified" if args.empty?
|
141
|
+
end
|
142
|
+
|
143
|
+
# pop off configurations, if present, using the syntax:
|
144
|
+
# task :name, :one, :two, {configs...}
|
145
|
+
if arg_names.last.is_a?(Hash)
|
146
|
+
configs = arg_names.pop
|
147
|
+
end
|
148
|
+
|
149
|
+
needs = needs.respond_to?(:to_ary) ? needs.to_ary : [needs]
|
150
|
+
needs = needs.compact.collect do |need|
|
151
|
+
|
152
|
+
unless need.kind_of?(Class)
|
153
|
+
# lookup or declare non-class dependencies
|
154
|
+
name = normalize_name(need).camelize
|
155
|
+
need = Tap::Support::Constant.constantize(name) do |base, constants|
|
156
|
+
const = block_given? ? yield(name) : nil
|
157
|
+
const or raise ArgumentError, "unknown task class: #{name}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
unless need.ancestors.include?(Tap::Task)
|
162
|
+
raise ArgumentError, "not a task class: #{need}"
|
163
|
+
end
|
164
|
+
|
165
|
+
need
|
166
|
+
end
|
167
|
+
|
168
|
+
[normalize_name(task_name), configs, needs, arg_names]
|
169
|
+
end
|
170
|
+
|
171
|
+
# helper to translate rake-style names to tap-style names, ie
|
172
|
+
#
|
173
|
+
# normalize_name('nested:name') # => "nested/name"
|
174
|
+
# normalize_name(:symbol) # => "symbol"
|
175
|
+
#
|
176
|
+
def normalize_name(name)
|
177
|
+
name.to_s.tr(":", "/")
|
178
|
+
end
|
179
|
+
|
180
|
+
# The class of task declared by task, by default DeclarationTask.
|
181
|
+
# Used as a hook to set the declaring class in including modules
|
182
|
+
# (such as DeclarationTask itself).
|
183
|
+
def declaration_class
|
184
|
+
DeclarationTask
|
185
|
+
end
|
186
|
+
|
187
|
+
# Registers a task class with the Declarations.env, if necessary.
|
188
|
+
# Returns task_class.
|
189
|
+
def register(task_class)
|
190
|
+
tasks = Declarations.env.tasks
|
191
|
+
const_name = task_class.to_s
|
192
|
+
unless tasks.entries.any? {|const| const.name == const_name }
|
193
|
+
tasks.entries << Tap::Support::Constant.new(const_name)
|
194
|
+
end
|
195
|
+
|
196
|
+
task_class
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class DeclarationTask
|
201
|
+
class << self
|
202
|
+
include Declarations
|
203
|
+
|
204
|
+
# alias task as declare, so that DeclarationTask and subclasses
|
205
|
+
# may directly declare subclasses of themselves
|
206
|
+
|
207
|
+
alias declare task
|
208
|
+
private :task, :desc, :namespace
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
extend Declarations
|
213
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Rap
|
2
|
+
|
3
|
+
# :::-
|
4
|
+
# A special type of Lazydoc::Comment designed to handle the comment syntax
|
5
|
+
# for task declarations.
|
6
|
+
#
|
7
|
+
# Description instances can be assigned a description, or they may parse
|
8
|
+
# one directly from the comment. Comment lines with the constant attribute
|
9
|
+
# '::desc' will have the value set as desc.
|
10
|
+
# :::+
|
11
|
+
class Description < Lazydoc::Comment
|
12
|
+
|
13
|
+
# The description for self.
|
14
|
+
attr_accessor :desc
|
15
|
+
|
16
|
+
# Parses in-comment descriptions from prepended lines, if present.
|
17
|
+
def prepend(line)
|
18
|
+
if line =~ /::desc\s+(.*?)\s*$/
|
19
|
+
self.desc = $1
|
20
|
+
false
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Resolves and returns the description.
|
27
|
+
def to_s
|
28
|
+
resolve
|
29
|
+
desc.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/rap/rake.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rap/rake_app'
|
2
|
+
|
3
|
+
module Rap
|
4
|
+
|
5
|
+
# :startdoc::manifest run rake tasks
|
6
|
+
#
|
7
|
+
# Simply enques the specified rake task(s) for execution. Useful when a
|
8
|
+
# rake task needs to be executed within a workflow. For example these
|
9
|
+
# are equivalent:
|
10
|
+
#
|
11
|
+
# % tap run -- rake test
|
12
|
+
# % rake test
|
13
|
+
#
|
14
|
+
# The only exeception is in the use of the --help option. Use --rake-help
|
15
|
+
# to access the rake help, and --help to access this help.
|
16
|
+
#
|
17
|
+
class Rake < Tap::Task
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Overrides Tap::Support::FrameworkClass#parse! to do
|
21
|
+
# nothing so that all args get passed forward to rake.
|
22
|
+
def parse!(argv, app=Tap::App.instance) # => instance, argv
|
23
|
+
if argv.include?('--help')
|
24
|
+
puts help
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
[new({}, default_name, app), argv.collect {|arg| arg == '--rake-help' ? '--help' : arg}]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def enq(*argv)
|
32
|
+
rake = ::Rake.application
|
33
|
+
|
34
|
+
# run as if from command line using argv
|
35
|
+
current_argv = ARGV.dup
|
36
|
+
begin
|
37
|
+
ARGV.clear
|
38
|
+
ARGV.concat(argv)
|
39
|
+
|
40
|
+
# now follow the same protocol as
|
41
|
+
# in run, handling options
|
42
|
+
rake.init
|
43
|
+
rake.load_rakefile
|
44
|
+
ensure
|
45
|
+
ARGV.clear
|
46
|
+
ARGV.concat(current_argv)
|
47
|
+
end
|
48
|
+
|
49
|
+
rake.enq_top_level(app)
|
50
|
+
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/rap/rake_app.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'tap'
|
4
|
+
|
5
|
+
module Rap
|
6
|
+
class RakeManifest < Tap::Support::Manifest
|
7
|
+
def initialize(env)
|
8
|
+
@env = env
|
9
|
+
rake = ::Rake.application
|
10
|
+
super(rake.have_rakefile(env.root.root) ? [rake.instance_variable_get(:@rakefile)] : [])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module RakeApp
|
15
|
+
def self.extended(base)
|
16
|
+
Tap::Env.instantiate(Dir.pwd).activate unless Tap::Env.instance
|
17
|
+
base.env = Tap::Env.instance
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_accessor :env
|
21
|
+
|
22
|
+
def enq_top_level(app)
|
23
|
+
# takes the place of rake.top_level
|
24
|
+
if options.show_tasks
|
25
|
+
display_tasks_and_comments
|
26
|
+
exit
|
27
|
+
elsif options.show_prereqs
|
28
|
+
display_prerequisites
|
29
|
+
exit
|
30
|
+
else
|
31
|
+
top_level_tasks.each do |task_string|
|
32
|
+
name, args = parse_task_string(task_string)
|
33
|
+
task = self[name]
|
34
|
+
app.mq(task, :invoke, *args)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def collect_tasks(*args)
|
40
|
+
# a little song and dance for compliance with
|
41
|
+
# rake pre- and post-0.8.2
|
42
|
+
argv = args.empty? ? ARGV : args[0]
|
43
|
+
argv.collect! do |arg|
|
44
|
+
next(arg) unless arg =~ /^:([a-z_\d]+):(.*)$/
|
45
|
+
env_pattern = $1
|
46
|
+
rake_task = $2
|
47
|
+
|
48
|
+
next(arg) unless entry = env.find(:envs, env_pattern, false)
|
49
|
+
|
50
|
+
mini_path, env = entry
|
51
|
+
root_path = env.root.root
|
52
|
+
|
53
|
+
if have_rakefile(root_path)
|
54
|
+
# load sequence echos that in raw_load_rakefile
|
55
|
+
puts "(in #{root_path})" unless options.silent
|
56
|
+
current_global_rakefile = $rakefile
|
57
|
+
$rakefile = @rakefile
|
58
|
+
|
59
|
+
namespaces = Tap::Root.split(mini_path, false).delete_if do |segment|
|
60
|
+
segment.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
#if @rakefile != ''
|
64
|
+
eval nest_namespace(%Q{load "#{File.join(root_path, @rakefile)}"}, namespaces.dup)
|
65
|
+
#end
|
66
|
+
|
67
|
+
$rakefile = current_global_rakefile
|
68
|
+
@rakefile = nil
|
69
|
+
|
70
|
+
namespaces << rake_task
|
71
|
+
namespaces.join(":")
|
72
|
+
else
|
73
|
+
fail "No Rakefile found for '#{env_pattern}' (looking for: #{@rakefiles.join(', ')})"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
def have_rakefile(dir=nil)
|
81
|
+
return super() if dir == nil
|
82
|
+
Tap::Root.chdir(dir) { super() }
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
NAMESPACE_STR = %Q{
|
88
|
+
namespace(:'%s') do
|
89
|
+
%s
|
90
|
+
end
|
91
|
+
}.strip
|
92
|
+
|
93
|
+
def nest_namespace(nest_str, namespaces)
|
94
|
+
return nest_str if namespaces.empty?
|
95
|
+
|
96
|
+
NAMESPACE_STR % [
|
97
|
+
namespaces.shift,
|
98
|
+
namespaces.empty? ? nest_str : nest_namespace(nest_str, namespaces)
|
99
|
+
]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
Rake.application.extend Rap::RakeApp
|
105
|
+
Tap::Env.manifest(:rakefiles) do |env|
|
106
|
+
Rap::RakeManifest.new(env)
|
107
|
+
end
|
data/tap.yml
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.12.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Chiang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-17 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: tap
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.12.0
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: simon.a.chiang@gmail.com
|
27
|
+
executables:
|
28
|
+
- rap
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- MIT-LICENSE
|
34
|
+
- History
|
35
|
+
- doc/Command Reference
|
36
|
+
- doc/Syntax Reference
|
37
|
+
files:
|
38
|
+
- lib/rap/declaration_task.rb
|
39
|
+
- lib/rap/declarations.rb
|
40
|
+
- lib/rap/description.rb
|
41
|
+
- lib/rap/rake_app.rb
|
42
|
+
- lib/rap/rake.rb
|
43
|
+
- tap.yml
|
44
|
+
- README
|
45
|
+
- MIT-LICENSE
|
46
|
+
- History
|
47
|
+
- doc/Command Reference
|
48
|
+
- doc/Syntax Reference
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://tap.rubyforge.org
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --main
|
54
|
+
- README
|
55
|
+
- -S
|
56
|
+
- -N
|
57
|
+
- --title
|
58
|
+
- Rap (Rakish App)
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project: tap
|
76
|
+
rubygems_version: 1.3.1
|
77
|
+
signing_key:
|
78
|
+
specification_version: 2
|
79
|
+
summary: A rakish extension to tap.
|
80
|
+
test_files: []
|
81
|
+
|