rap 0.12.3 → 0.13.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 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