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