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 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
+