rap 0.12.0

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