rap 0.12.3 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
data/History CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.13.0 / 2009-05-25
2
+
3
+ Updates to use Tap-0.17.0.
4
+
5
+ * added Test task
6
+ * added Manifest task
7
+
1
8
  == 0.12.3 / 2009-03-23
2
9
 
3
10
  Update executable to use Tap-0.12.4. No significant changes.
data/README CHANGED
@@ -1,7 +1,7 @@
1
1
  = {Rap (Rakish App)}[http://tap.rubyforge.org/rap]
2
2
 
3
3
  rap v. a quick, sharp knock or blow
4
- rakish adj. having a dashing, jaunty, or slightly disreputable quality or appearance
4
+ rak.ish adj. having a dashing, jaunty, or slightly disreputable quality or appearance
5
5
 
6
6
  A rakish extension to {Tap}[http://tap.rubyforge.org/rdoc].
7
7
 
@@ -20,16 +20,13 @@ Check out these links for documentation, development, and bug tracking.
20
20
 
21
21
  == Usage
22
22
 
23
- Usage is much like {rake}[http://rake.rubyforge.org/]:
23
+ Usage is much like {Rake}[http://rake.rubyforge.org/]:
24
24
 
25
25
  [Rapfile]
26
- require 'rap/declarations'
27
- include Rap::Declarations
28
-
29
- desc "your basic goodnight moon task"
30
26
 
27
+ # ::desc your basic goodnight moon task
31
28
  # Says goodnight with a configurable message.
32
- task(:goodnight, :obj, :message => 'goodnight') do |task, args|
29
+ Rap.task(:goodnight, :obj, :message => 'goodnight') do |task, args|
33
30
  puts "#{task.message} #{args.obj}\n"
34
31
  end
35
32
 
@@ -52,13 +49,14 @@ Now from the command line:
52
49
  --message MESSAGE
53
50
 
54
51
  options:
55
- -h, --help Print this help
56
- --name NAME Specify a name
57
- --use FILE Loads inputs from file
52
+ --help Print this help
53
+ --name NAME Specifies the task name
54
+ --config FILE Specifies a config file
58
55
 
59
56
  For testing, load the Rapfile and access the task as a constant.
60
57
 
61
58
  [test.rb]
59
+ require 'rap'
62
60
  load 'Rapfile'
63
61
  require 'test/unit'
64
62
  require 'stringio'
@@ -86,19 +84,39 @@ The test passes:
86
84
  1 tests, 2 assertions, 0 failures, 0 errors
87
85
 
88
86
  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.
87
+ can use rap to launch workflows as well.
88
+
89
+ == Limitations
90
+
91
+ Rap is not a pure replacement of Rake, nor do the Rap tasks behave exactly
92
+ like standard Tap tasks.
93
+
94
+ ==== Regarding Rake:
95
+
96
+ * Rap does not support builds by default
97
+ * Classes like FileList are not available
98
+ * Namespace lookup is slightly different (see the {Syntax Reference}[link:files/doc/Syntax%20Reference.html])
99
+
100
+ That said, many rakefiles can be renamed as rapfiles and they'll work with
101
+ minor and sometimes no changes.
102
+
103
+ ==== Regarding Tap
104
+
105
+ Rap tasks (ie subclasses of Rap::DeclarationTask) are designed to behave like
106
+ Rake tasks. As such Rap tasks:
92
107
 
93
- === Limitations
108
+ * return nil and pass nil in workflows
109
+ * only execute once
110
+ * are effectively singletons
94
111
 
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]).
112
+ This makes rap tasks useful in dependency-based workflows but fairly useless
113
+ in imperative workflows. However, other tasks behave as normal and any
114
+ workflow you can run with 'tap run' can be run without alteration by rap.
98
115
 
99
116
  == Installation
100
117
 
101
- Rap is available as a gem on RubyForge[http://rubyforge.org/projects/tap]. Use:
118
+ Rap is available as a gem on RubyForge[http://rubyforge.org/projects/tap].
119
+ Use:
102
120
 
103
121
  % gem install rap
104
122
 
data/bin/rap CHANGED
@@ -2,20 +2,14 @@
2
2
  # usage: rap taskname {options} [args] [-d-]
3
3
 
4
4
  $:.unshift "#{File.dirname(__FILE__)}/../lib"
5
- require 'rap/declarations'
5
+ require 'rap'
6
6
 
7
7
  # setup the environment
8
8
  begin
9
9
 
10
- env = Tap::Exe.setup(ARGV)
11
- env.unshift(Rap::Declarations.env)
12
-
13
- Dir.glob('[TtRr]apfile{,.rb}').each do |task_file|
14
- task_file = File.expand_path(task_file)
15
- next unless File.file?(task_file)
16
-
17
- env.loads.unshift(task_file)
18
- end
10
+ env = Tap::Exe.setup
11
+ Rap::Declarations.env = env
12
+ env.activate
19
13
 
20
14
  rescue(Tap::Env::ConfigError)
21
15
  # catch errors and exit gracefully
@@ -24,92 +18,58 @@ rescue(Tap::Env::ConfigError)
24
18
  exit(1)
25
19
  end
26
20
 
27
- #
28
- # setup after script
29
- #
30
-
31
- at_exit do
32
- begin
33
- eval(env.after) if env.after != nil
34
- rescue(Exception)
35
- puts "Error in after script."
36
- env.handle_error($!)
37
- exit(1)
38
- end
39
- end
40
-
41
- #
42
- # run before script
43
- #
44
-
45
- begin
46
- eval(env.before) if env.before != nil
47
- rescue(Exception)
48
- puts "Error in before script."
49
- env.handle_error($!)
50
- exit(1)
51
- end
52
-
53
21
  #
54
22
  # run rap
55
23
  #
56
24
 
57
- module Rap
58
- autoload(:Rake, 'rap/rake')
25
+ Dir.glob('[TtRr]apfile{,.rb}').each do |rapfile|
26
+ next unless File.file?(rapfile)
27
+ load rapfile
59
28
  end
60
29
 
61
- begin
62
- env.activate
30
+ case ARGV[0]
31
+ when '--help', nil, '-T'
63
32
 
64
- case ARGV[0]
65
- when '--help', nil, '-T'
66
- rap_template = %Q{<% if count > 1 && !entries.empty? %>
67
- <%= env_name %>:
33
+ # same as normal summarize, but pass over tasks that have no comment
34
+ summary_template = %Q{<% entries.delete_if {|key, const| const.comment.kind_of?(Rap::Description) && const.comment.resolve.desc == nil } %>
35
+ <% if !entries.empty? && count > 1 %>
36
+ <%= env_key %>:
68
37
  <% end %>
69
- <% entries.each do |name, const| %>
70
- <% desc = if const.require_path == nil # should be a declaration %>
71
- <% manifest = const.constantize.manifest %>
72
- <% next if manifest == nil || manifest.empty? %>
73
- <% manifest %>
74
- <% else %>
75
- <% const.document[const.name]['manifest'] %>
76
- <% end %>
77
- <%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
78
- <% end %>}
79
-
80
- puts Lazydoc.usage(__FILE__)
81
- puts
82
- puts "=== tap tasks ==="
83
- puts env.summarize(:tasks, rap_template)
38
+ <% entries.each do |key, const| %>
39
+ <%= key.ljust(width) %> # <%= const.comment %>
40
+ <% end %>
41
+ }
42
+
43
+ puts Lazydoc.usage(__FILE__)
44
+ puts
45
+ puts "=== tap tasks ==="
46
+ puts env.manifest(:task).summarize(summary_template)
47
+
48
+ if Rap::Rake.has_rakefile?
84
49
  puts
85
50
  puts "=== rake tasks ==="
86
- Rap::Rake.new.enq('-T')
87
- Tap::App.instance.run
88
-
89
- # this is not currently reached as rake exits on -T
90
- puts
91
- puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
92
- exit
93
- else
94
- app = Tap::App.instance
95
- schema = Tap::Support::Schema.parse(ARGV)
96
- ARGV.clear
97
- env.build(schema, app) do |args|
98
- warn "warning: implict rake for [#{args.join(' ')}]"
99
- Rap::Rake
100
- end
101
-
102
- if app.queue.empty?
103
- puts "no task specified"
104
- exit
105
- end
106
-
107
- env.set_signals
108
- app.run
51
+ Rap::Rake.new.execute('-T')
109
52
  end
110
53
 
111
- rescue
112
- env.handle_error($!)
54
+ puts
55
+ puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
56
+ else
57
+ begin
58
+ schema = Tap::Schema.parse(ARGV)
59
+ env.run(schema) do |type, key, metadata|
60
+ if type == :task && Rap::Rake.has_rakefile?
61
+ warn "warning: implict rake for '#{metadata.join(' ')}'"
62
+ metadata.unshift(key)
63
+ Rap::Rake
64
+ else
65
+ nil
66
+ end
67
+ end
68
+ rescue
69
+ raise if $DEBUG
70
+ puts $!.message
71
+ exit(1)
72
+ end
113
73
  end
114
74
 
115
75
  exit(0)
@@ -4,13 +4,7 @@
4
4
 
5
5
  A task declaration:
6
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|
7
+ task(<name>, <arg_names...>, {<configs>}) do |task, args|
14
8
  # arguments are available through args:
15
9
  args.arg_name
16
10
 
@@ -18,6 +12,10 @@ A task declaration:
18
12
  task.key
19
13
  end
20
14
 
15
+ A task declaration with dependencies:
16
+
17
+ task({<name> => [<dependencies...>]}, <arg_names...>, {<configs>}) { task ... }
18
+
21
19
  A namespace declaration:
22
20
 
23
21
  namespace(<name>) { task ... }
@@ -39,19 +37,19 @@ Extended documentation:
39
37
  # Lines are justified and wrapped on the command line.
40
38
  task ...
41
39
 
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):
40
+ Pains were taken to make task declarations for Rap work the similar to Rake
41
+ tasks. For both Rake and Rap (noting that in general task classes are not
42
+ limited in these ways):
45
43
 
46
44
  * tasks are singleton instances that may be extended across multiple
47
45
  declarations
48
46
  * tasks do not pass inputs from one task to the next
49
47
  * tasks only execute once
50
48
 
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.
49
+ A few syntactical differences between Rake and Rap must to be noted, as they
50
+ can cause errors during migration.
53
51
 
54
- ==== no needs
52
+ ==== No :needs
55
53
 
56
54
  Rap does not support :needs as a way to specify dependencies. For instance,
57
55
  this will declare a ':needs' configuration with the default value ':another',
@@ -59,24 +57,34 @@ not a task which depends on another:
59
57
 
60
58
  Rap.task :name, :needs => :another
61
59
 
62
- ==== immediate namespace lookup
60
+ ==== Namespace Lookup
63
61
 
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.
62
+ Rap immediately resolves dependencies relative to the top level namespace,
63
+ which is very different from Rake. Rake waits to resolve dependencies and will
64
+ use a match within a namespace if it becomes available. For these tasks rap
65
+ and rake produce different results:
68
66
 
69
- task :outer { print 'non-nested' }
67
+ [Rapfile/Rakfile]
68
+
69
+ task(:outer) { print 'non-nested' }
70
70
  namespace :nest do
71
- task :inner => :outer { puts 'was executed' }
72
- task :outer { print 'nested' }
71
+ task(:inner1 => :outer) { puts ' was executed' }
72
+ task(:inner2 => 'nest:outer') { puts ' was executed' }
73
+ task(:outer) { print 'nested' }
73
74
  end
74
75
 
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:
76
+ Rap resolves the dependencies literally:
78
77
 
79
- % rap nest/inner
78
+ % rap nest/inner1
80
79
  non-nested was executed
81
- % rake nest:inner
82
- nested was executed
80
+
81
+ % rap nest/inner2
82
+ nested was executed
83
+
84
+ Rake resolves the dependencies relative to the namespace:
85
+
86
+ % rake nest:inner1
87
+ nested was executed
88
+
89
+ % rake nest:inner2
90
+ nested was executed
@@ -0,0 +1,6 @@
1
+ require 'tap'
2
+ require 'rap/declarations'
3
+
4
+ module Rap
5
+ autoload(:Rake, 'rap/rake')
6
+ end
@@ -1,14 +1,41 @@
1
- require 'tap'
1
+ require 'tap/task'
2
+ require 'tap/env'
2
3
  require 'ostruct'
3
4
  require 'rap/description'
4
5
 
5
6
  module Rap
6
7
 
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.
8
+ # DeclarationTasks are a special breed of Tap::Task designed to behave much
9
+ # like Rake tasks. As such, declaration tasks:
10
+ #
11
+ # * return nil and pass nil in workflows
12
+ # * only execute once
13
+ # * are effectively singletons (one instance per app)
14
+ # * allow for multiple actions
15
+ #
16
+ # The DeclarationTask class partially includes Declarations so subclasses
17
+ # may directly declare tasks. A few alias acrobatics makes it so that ONLY
18
+ # Declarations#task is made available (desc cannot be used because Task
19
+ # classes already use that method for documentation, and namespace
20
+ # would be silly).
21
+ #
22
+ # Weird? Yes, but it leads to this syntax:
23
+ #
24
+ # # [Rapfile]
25
+ # # class Subclass < Rap::DeclarationTask
26
+ # # def helper(); "help"; end
27
+ # # end
28
+ # #
29
+ # # # ::desc a help task
30
+ # # Subclass.task(:help) {|task, args| puts "got #{task.helper}"}
31
+ #
32
+ # % rap help
33
+ # got help
34
+ #
10
35
  class DeclarationTask < Tap::Task
11
36
  class << self
37
+
38
+ # Sets actions.
12
39
  attr_writer :actions
13
40
 
14
41
  # An array of actions (blocks) associated with this class. Each of the
@@ -18,6 +45,7 @@ module Rap
18
45
  @actions ||= []
19
46
  end
20
47
 
48
+ # Sets argument names
21
49
  attr_writer :arg_names
22
50
 
23
51
  # The argument names pulled from a task declaration.
@@ -32,24 +60,43 @@ module Rap
32
60
  args
33
61
  end
34
62
 
35
- # Initializes instance and registers it as a dependency.
36
- def new(*args)
37
- @instance ||= super
38
- @instance.app.dependencies.register(@instance)
39
- @instance
63
+ # Instantiates the instance of self for app and reconfigures it using
64
+ # argh. Configurations are set, the task name is set, and the
65
+ # arguments are stored on the instance. The arguments are returned
66
+ # as normal in the [instance, args] result.
67
+ #
68
+ # These atypical behaviors handle various situations on the command
69
+ # line. Setting the args this way, for example, allows arguments to
70
+ # be specified on dependency tasks:
71
+ #
72
+ # # [Rapfile]
73
+ # # Rap.task(:a, :obj) {|t, a| puts "A #{a.obj}"}
74
+ # # Rap.task({:b => :a}, :obj) {|t, a| puts "B #{a.obj}"}
75
+ #
76
+ # % rap b world -- a hello
77
+ # A hello
78
+ # B world
79
+ #
80
+ def instantiate(argh={}, app=Tap::App.instance)
81
+ config = argh[:config]
82
+ config_file = argh[:config_file]
83
+
84
+ instance = self.instance(app)
85
+ instance.reconfigure(load_config(config_file)) if config_file
86
+ instance.reconfigure(config) if config
87
+ instance.args = argh[:args]
88
+
89
+ [instance, instance.args]
40
90
  end
41
91
 
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]).
92
+ # Looks up or creates the DeclarationTask subclass specified by const_name
93
+ # and adds the configs and dependencies.
49
94
  #
95
+ # Configurations are always validated using the yaml transformation block
96
+ # (see {Configurable::Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]).
50
97
  def subclass(const_name, configs={}, dependencies=[])
51
98
  # lookup or generate the subclass
52
- subclass = Tap::Support::Constant.constantize(const_name.to_s) do |base, constants|
99
+ subclass = Tap::Env::Constant.constantize(const_name.to_s) do |base, constants|
53
100
  subclass_const = constants.pop
54
101
  constants.inject(base) do |namespace, const|
55
102
  # nesting Task classes into other Task classes is required
@@ -72,19 +119,74 @@ module Rap
72
119
 
73
120
  # add dependencies
74
121
  dependencies.each do |dependency|
75
- dependency_name = File.basename(dependency.default_name)
122
+ dependency_name = File.basename(dependency.to_s.underscore)
123
+
124
+ # this suppresses 'method redefined' warnings
125
+ if subclass.method_defined?(dependency_name)
126
+ subclass.send(:undef_method, dependency_name)
127
+ end
128
+
76
129
  subclass.send(:depends_on, dependency_name, dependency)
77
130
  end
78
131
 
79
132
  subclass
80
133
  end
134
+ end
135
+
136
+ # The result of self, set by call.
137
+ attr_reader :result
138
+
139
+ # The arguments assigned to self during call.
140
+ attr_accessor :args
141
+
142
+ def initialize(config={}, app=Tap::App.instance)
143
+ super
144
+ @resolved = false
145
+ @result = nil
146
+ @args = nil
147
+ end
148
+
149
+ # Conditional call to the super call; only calls once. Returns result.
150
+ def call(*args)
81
151
 
82
- private
152
+ # Declaration tasks function as dependencies, but unlike normal
153
+ # dependencies, they CAN take arguments from the command line.
154
+ # Such arguments will be set as args, and be used to enque the
155
+ # task.
156
+ #
157
+ # If the task executes from the queue first, args will be
158
+ # provided to call and they should equal self.args. If the task
159
+ # executes as a dependency first, call will not receive args and
160
+ # in that case self.args will be used.
161
+ #
162
+ # This warns for cases that odd workflows can produce where the
163
+ # args have been set and DIFFERENT args are used to enque the task.
164
+ # In these cases always go with the pre-set args but warn the issue.
165
+ self.args ||= args
166
+ unless self.args == args
167
+ if @resolved
168
+ warn "warn: ignorning dependency task inputs #{args.inspect} (#{self})"
169
+ else
170
+ warn "warn: invoking dependency task with preset args #{self.args.inspect} and not inputs #{args.inspect} (#{self})"
171
+ end
172
+ end
83
173
 
84
- # overridden to provide self as the declaration_class
85
- def declaration_class # :nodoc:
86
- self
174
+ unless @resolved
175
+ @resolved = true
176
+ @result = super(*self.args)
87
177
  end
178
+ result
179
+ end
180
+
181
+ # Returns true if already resolved by call.
182
+ def resolved?
183
+ @resolved
184
+ end
185
+
186
+ # Resets self so call will call again. Also sets result to nil.
187
+ def reset
188
+ @resolved = false
189
+ @result = nil
88
190
  end
89
191
 
90
192
  # Collects the inputs into an OpenStruct according to the class arg_names,
@@ -1,27 +1,28 @@
1
1
  require 'rap/declaration_task'
2
- require 'tap/support/shell_utils'
2
+ require 'rap/utils'
3
3
 
4
4
  module Rap
5
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.
6
+ # Defines the Rap task declaration methods. They may be included at the
7
+ # top level (like Rake) or used through Rap.
9
8
  #
10
- # Unlike rake, task will define actual task classes according to the task
9
+ # === Usage
10
+ #
11
+ # Unlike in rake, task will define actual task classes according to the task
11
12
  # names. Task classes may be nested within modules using namespace. It's
12
13
  # VERY important to realize this is the case both to aid in thing like
13
14
  # testing and to prevent namespace conflicts. For example:
14
15
  #
15
- # Rap.task(:sample) # => Sample.instance
16
+ # t = Rap.task(:sample)
17
+ # t.class # => Sample
18
+ #
16
19
  # Rap.namespace(:nested) do
17
- # Rap.task(:sample) # => Nested::Sample.instance
20
+ # t = Rap.task(:sample)
21
+ # t.class # => Nested::Sample
18
22
  # end
19
23
  #
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.
24
+ # Normally all declared tasks are subclasses of DeclarationTask, but
25
+ # subclasses of DeclarationTask can declare tasks as well.
25
26
  #
26
27
  # class Alt < DeclarationTask
27
28
  # end
@@ -30,31 +31,41 @@ module Rap
30
31
  #
31
32
  # desc "task one, a subclass of DeclarationTask"
32
33
  # o = Rap.task(:one)
33
- # o.class # => One
34
- # o.class.superclass # => DeclarationTask
35
- # o.class.manifest.desc # => "task one, a subclass of DeclarationTask"
34
+ # o.class # => One
35
+ # o.class.superclass # => DeclarationTask
36
+ # o.class.desc.to_s # => "task one, a subclass of DeclarationTask"
36
37
  #
37
38
  # namespace(:nest) do
38
- #
39
39
  # desc "task two, a nested subclass of Alt"
40
- # t = Alt.declare(:two)
40
+ # t = Alt.task(:two)
41
41
  # t.class # => Nest::Two
42
42
  # t.class.superclass # => Alt
43
- # t.class.manifest.desc # => "task two, a nested subclass of Alt"
44
- #
43
+ # t.class.desc.to_s # => "task two, a nested subclass of Alt"
45
44
  # end
46
45
  #
47
- # See the {Syntax Reference}[link:files/doc/Syntax%20Reference.html] for usage.
46
+ # This feature is only available to subclasses of DeclarationTask and can
47
+ # be very useful for creating inheritance hierarchies. Note that other
48
+ # declaration methods like 'desc' and 'namespace' are not available on
49
+ # DeclarationTask or subclasses, just 'task'.
50
+ #
51
+ # See the {Syntax Reference}[link:files/doc/Syntax%20Reference.html] for more
52
+ # information.
48
53
  module Declarations
49
- include Tap::Support::ShellUtils
54
+ include Utils
50
55
 
51
56
  # 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
57
+ # By default a Tap::Env for Dir.pwd.
58
+ def Declarations.env() @@env ||= Tap::Env.new; end
54
59
 
55
60
  # Sets the declaration environment.
56
61
  def Declarations.env=(env) @@env=env; end
57
62
 
63
+ # The declaration App (default Tap::App.instance)
64
+ def Declarations.app() @@app ||= Tap::App.instance; end
65
+
66
+ # Sets the declaration App.
67
+ def Declarations.app=(app) @@app=app; end
68
+
58
69
  # The base constant for all task declarations, prepended to the task name.
59
70
  def Declarations.current_namespace() @@current_namespace; end
60
71
  @@current_namespace = ''
@@ -64,6 +75,11 @@ module Rap
64
75
  def Declarations.current_desc() @@current_desc; end
65
76
  @@current_desc = nil
66
77
 
78
+ # Returns the instance of the task class in app.
79
+ def Declarations.instance(tasc)
80
+ tasc.instance(Declarations.app)
81
+ end
82
+
67
83
  # Declares a task with a rake-like syntax. Task generates a subclass of
68
84
  # DeclarationTask, nested within the current namespace.
69
85
  def task(*args, &action)
@@ -74,22 +90,27 @@ module Rap
74
90
 
75
91
  # generate the task class
76
92
  const_name = File.join(@@current_namespace, name.to_s).camelize
77
- task_class = register declaration_class.subclass(const_name, configs, dependencies)
93
+ tasc = declaration_class.subclass(const_name, configs, dependencies)
78
94
 
79
95
  # register documentation
80
- manifest = Lazydoc.register_caller(Description)
81
- manifest.desc = @@current_desc
96
+ desc = Lazydoc.register_caller(Description)
97
+ desc.desc = @@current_desc
82
98
  @@current_desc = nil
83
99
 
84
- task_class.arg_names = arg_names
85
- task_class.manifest = manifest
86
- task_class.source_file = manifest.document.source_file
100
+ tasc.arg_names = arg_names
101
+ tasc.desc = desc
102
+ tasc.source_file = desc.document.source_file
87
103
 
88
104
  # add the action
89
- task_class.actions << action if action
105
+ tasc.actions << action if action
106
+
107
+ # register
108
+ register tasc
90
109
 
91
110
  # return the instance
92
- task_class.instance
111
+ instance = Declarations.instance(tasc)
112
+ instance.config.bind(instance, true)
113
+ instance
93
114
  end
94
115
 
95
116
  # Nests tasks within the named module for the duration of the block.
@@ -152,7 +173,7 @@ module Rap
152
173
  unless need.kind_of?(Class)
153
174
  # lookup or declare non-class dependencies
154
175
  name = normalize_name(need).camelize
155
- need = Tap::Support::Constant.constantize(name) do |base, constants|
176
+ need = Tap::Env::Constant.constantize(name) do |base, constants|
156
177
  const = block_given? ? yield(name) : nil
157
178
  const or raise ArgumentError, "unknown task class: #{name}"
158
179
  end
@@ -186,26 +207,46 @@ module Rap
186
207
 
187
208
  # Registers a task class with the Declarations.env, if necessary.
188
209
  # 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)
210
+ def register(tasc)
211
+ tasks = Declarations.env.manifest(:task)
212
+
213
+ const_name = tasc.to_s
214
+ constant = tasks.find do |const|
215
+ const.const_name == const_name
216
+ end
217
+
218
+ unless constant
219
+ constant = Tap::Env::Constant.new(const_name)
220
+ tasks.entries << constant
194
221
  end
195
222
 
196
- task_class
223
+ constant.comment = tasc.desc(false)
224
+ tasc
197
225
  end
198
226
  end
199
227
 
200
228
  class DeclarationTask
201
229
  class << self
230
+ # :stopdoc:
231
+ alias original_desc desc
232
+ # :startdoc:
233
+
202
234
  include Declarations
203
235
 
204
- # alias task as declare, so that DeclarationTask and subclasses
205
- # may directly declare subclasses of themselves
236
+ # :stopdoc:
237
+ undef_method :desc
238
+ alias desc original_desc
239
+
240
+ # hide remaining Declarations methods (including Utils methods)
241
+ private :namespace, :sh
242
+ # :startdoc:
206
243
 
207
- alias declare task
208
- private :task, :desc, :namespace
244
+ private
245
+
246
+ # overridden to provide self as the declaration_class
247
+ def declaration_class # :nodoc:
248
+ self
249
+ end
209
250
  end
210
251
  end
211
252
 
@@ -1,13 +1,13 @@
1
1
  module Rap
2
2
 
3
- # :::-
3
+ # :startdoc:::-
4
4
  # A special type of Lazydoc::Comment designed to handle the comment syntax
5
5
  # for task declarations.
6
6
  #
7
7
  # Description instances can be assigned a description, or they may parse
8
8
  # one directly from the comment. Comment lines with the constant attribute
9
9
  # '::desc' will have the value set as desc.
10
- # :::+
10
+ # :startdoc:::+
11
11
  class Description < Lazydoc::Comment
12
12
 
13
13
  # The description for self.
@@ -15,8 +15,8 @@ module Rap
15
15
 
16
16
  # Parses in-comment descriptions from prepended lines, if present.
17
17
  def prepend(line)
18
- if line =~ /::desc\s+(.*?)\s*$/
19
- self.desc = $1
18
+ if line =~ /::desc(?:\s+(.*?))?\s*$/
19
+ self.desc = $1.to_s
20
20
  false
21
21
  else
22
22
  super
@@ -1,14 +1,15 @@
1
- require 'rap/rake_app'
1
+ require 'rubygems'
2
+ require 'rake'
2
3
 
3
4
  module Rap
4
5
 
5
- # :startdoc::manifest run rake tasks
6
+ # :startdoc::task run rake tasks
6
7
  #
7
8
  # Simply enques the specified rake task(s) for execution. Useful when a
8
9
  # rake task needs to be executed within a workflow. For example these
9
10
  # are equivalent:
10
11
  #
11
- # % tap run -- rake test
12
+ # % rap rake test
12
13
  # % rake test
13
14
  #
14
15
  # The only exeception is in the use of the --help option. Use --rake-help
@@ -16,7 +17,7 @@ module Rap
16
17
  #
17
18
  class Rake < Tap::Task
18
19
  class << self
19
-
20
+
20
21
  # Overrides Tap::Support::FrameworkClass#parse! to do
21
22
  # nothing so that all args get passed forward to rake.
22
23
  def parse!(argv, app=Tap::App.instance) # => instance, argv
@@ -24,13 +25,21 @@ module Rap
24
25
  puts help
25
26
  exit
26
27
  end
27
- [new({}, default_name, app), argv.collect {|arg| arg == '--rake-help' ? '--help' : arg}]
28
+ argv = argv.collect {|arg| arg == '--rake-help' ? '--help' : arg}
29
+ [new({}, app), argv]
30
+ end
31
+
32
+ # Returns true if Rake detects a rakefile.
33
+ def has_rakefile?
34
+ ::Rake.application.have_rakefile != nil
28
35
  end
29
36
  end
30
-
37
+
38
+ # Executes Rake using the input arguments as if they came from the
39
+ # command line.
31
40
  def process(*argv)
32
41
  rake = ::Rake.application
33
-
42
+
34
43
  # run as if from command line using argv
35
44
  current_argv = ARGV.dup
36
45
  begin
@@ -45,9 +54,9 @@ module Rap
45
54
  ARGV.clear
46
55
  ARGV.concat(current_argv)
47
56
  end
48
-
49
- rake.enq_top_level(app)
50
-
57
+
58
+ rake.top_level
59
+
51
60
  nil
52
61
  end
53
62
  end
@@ -0,0 +1,18 @@
1
+ module Rap
2
+ module Utils
3
+ # Run the system command +cmd+, passing the result to the block, if given.
4
+ # Raises an error if the command fails. Uses the same semantics as
5
+ # Kernel::exec and Kernel::system.
6
+ #
7
+ # Based on FileUtils#sh from Rake.
8
+ def sh(*cmd) # :yields: ok, status
9
+ ok = system(*cmd)
10
+
11
+ if block_given?
12
+ yield(ok, $?)
13
+ else
14
+ ok or raise "Command failed with status (#{$?.exitstatus}): [#{cmd.join(' ')}]"
15
+ end
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-23 00:00:00 -06:00
12
+ date: 2009-05-25 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.12.4
23
+ version: 0.17.0
24
24
  version:
25
25
  description:
26
26
  email: simon.a.chiang@gmail.com
@@ -32,19 +32,18 @@ extra_rdoc_files:
32
32
  - README
33
33
  - MIT-LICENSE
34
34
  - History
35
- - doc/Command Reference
36
35
  - doc/Syntax Reference
37
36
  files:
38
37
  - lib/rap/declaration_task.rb
39
38
  - lib/rap/declarations.rb
40
39
  - lib/rap/description.rb
41
- - lib/rap/rake_app.rb
42
40
  - lib/rap/rake.rb
41
+ - lib/rap/utils.rb
42
+ - lib/rap.rb
43
43
  - tap.yml
44
44
  - README
45
45
  - MIT-LICENSE
46
46
  - History
47
- - doc/Command Reference
48
47
  - doc/Syntax Reference
49
48
  has_rdoc: true
50
49
  homepage: http://tap.rubyforge.org
@@ -1,22 +0,0 @@
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
@@ -1,107 +0,0 @@
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