engineyard-serverside 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/lib/engineyard-serverside/paths.rb +0 -1
  2. data/lib/engineyard-serverside/version.rb +1 -1
  3. data/lib/vendor/thor/{LICENSE → LICENSE.md} +2 -2
  4. data/lib/vendor/thor/README.md +28 -0
  5. data/lib/vendor/thor/lib/thor.rb +183 -48
  6. data/lib/vendor/thor/lib/thor/actions.rb +66 -23
  7. data/lib/vendor/thor/lib/thor/actions/create_file.rb +5 -3
  8. data/lib/vendor/thor/lib/thor/actions/create_link.rb +57 -0
  9. data/lib/vendor/thor/lib/thor/actions/directory.rb +14 -7
  10. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +24 -5
  11. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +106 -21
  12. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +15 -10
  13. data/lib/vendor/thor/lib/thor/base.rb +144 -43
  14. data/lib/vendor/thor/lib/thor/core_ext/dir_escape.rb +0 -0
  15. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +1 -1
  16. data/lib/vendor/thor/lib/thor/error.rb +6 -1
  17. data/lib/vendor/thor/lib/thor/group.rb +41 -27
  18. data/lib/vendor/thor/lib/thor/invocation.rb +48 -58
  19. data/lib/vendor/thor/lib/thor/parser/argument.rb +29 -22
  20. data/lib/vendor/thor/lib/thor/parser/arguments.rb +26 -5
  21. data/lib/vendor/thor/lib/thor/parser/option.rb +42 -49
  22. data/lib/vendor/thor/lib/thor/parser/options.rb +39 -30
  23. data/lib/vendor/thor/lib/thor/rake_compat.rb +13 -8
  24. data/lib/vendor/thor/lib/thor/runner.rb +27 -20
  25. data/lib/vendor/thor/lib/thor/shell.rb +10 -5
  26. data/lib/vendor/thor/lib/thor/shell/basic.rb +228 -78
  27. data/lib/vendor/thor/lib/thor/shell/color.rb +40 -4
  28. data/lib/vendor/thor/lib/thor/shell/html.rb +123 -0
  29. data/lib/vendor/thor/lib/thor/task.rb +83 -53
  30. data/lib/vendor/thor/lib/thor/util.rb +57 -21
  31. data/lib/vendor/thor/lib/thor/version.rb +1 -1
  32. data/lib/vendor/thor/thor.gemspec +21 -115
  33. metadata +109 -217
  34. data/lib/vendor/thor/CHANGELOG.rdoc +0 -89
  35. data/lib/vendor/thor/README.rdoc +0 -297
  36. data/lib/vendor/thor/Thorfile +0 -69
@@ -7,7 +7,6 @@ module EY
7
7
  module LegacyHelpers
8
8
  def self.legacy_path_helper(name, new_name)
9
9
  define_method(name) do |*a|
10
- EY::Serverside.deprecation_warning("config.#{name} is deprecated. Please use 'config.paths.#{new_name}' which returns a Pathname object.")
11
10
  paths.send(new_name).to_s
12
11
  end
13
12
  end
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '2.0.0'
3
+ VERSION = '2.0.1'
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008 Yehuda Katz
1
+ Copyright (c) 2008 Yehuda Katz, Eric Hodel, et al.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ [![Build Status](https://secure.travis-ci.org/wycats/thor.png?branch=master)](http://travis-ci.org/wycats/thor)
2
+
3
+ Thor
4
+ ====
5
+
6
+ Description
7
+ -----------
8
+ Thor is a simple and efficient tool for building self-documenting command line
9
+ utilities. It removes the pain of parsing command line options, writing
10
+ "USAGE:" banners, and can also be used as an alternative to the [Rake][rake]
11
+ build tool. The syntax is Rake-like, so it should be familiar to most Rake
12
+ users.
13
+
14
+ [rake]: https://github.com/jimweirich/rake
15
+
16
+ Installation
17
+ ------------
18
+ gem install thor
19
+
20
+ Usage and documentation
21
+ -----------------------
22
+ Please see [the wiki](https://github.com/wycats/thor/wiki) for basic usage and other documentation on using Thor.
23
+
24
+ License
25
+ -------
26
+ Released under the MIT License. See the [LICENSE][license] file for further details.
27
+
28
+ [license]: https://github.com/wycats/thor/blob/master/LICENSE.md
@@ -1,12 +1,11 @@
1
1
  require 'thor/base'
2
2
 
3
- # TODO: Update thor to allow for git-style CLI (git bisect run)
4
3
  class Thor
5
4
  class << self
6
5
  # Sets the default task when thor is executed without an explicit task to be called.
7
6
  #
8
7
  # ==== Parameters
9
- # meth<Symbol>:: name of the defaut task
8
+ # meth<Symbol>:: name of the default task
10
9
  #
11
10
  def default_task(meth=nil)
12
11
  case meth
@@ -19,11 +18,29 @@ class Thor
19
18
  end
20
19
  end
21
20
 
21
+ # Registers another Thor subclass as a command.
22
+ #
23
+ # ==== Parameters
24
+ # klass<Class>:: Thor subclass to register
25
+ # command<String>:: Subcommand name to use
26
+ # usage<String>:: Short usage for the subcommand
27
+ # description<String>:: Description for the subcommand
28
+ def register(klass, subcommand_name, usage, description, options={})
29
+ if klass <= Thor::Group
30
+ desc usage, description, options
31
+ define_method(subcommand_name) { |*args| invoke(klass, args) }
32
+ else
33
+ desc usage, description, options
34
+ subcommand subcommand_name, klass
35
+ end
36
+ end
37
+
22
38
  # Defines the usage and the description of the next task.
23
39
  #
24
40
  # ==== Parameters
25
41
  # usage<String>
26
42
  # description<String>
43
+ # options<String>
27
44
  #
28
45
  def desc(usage, description, options={})
29
46
  if options[:for]
@@ -31,7 +48,21 @@ class Thor
31
48
  task.usage = usage if usage
32
49
  task.description = description if description
33
50
  else
34
- @usage, @desc = usage, description
51
+ @usage, @desc, @hide = usage, description, options[:hide] || false
52
+ end
53
+ end
54
+
55
+ # Defines the long description of the next task.
56
+ #
57
+ # ==== Parameters
58
+ # long description<String>
59
+ #
60
+ def long_desc(long_description, options={})
61
+ if options[:for]
62
+ task = find_and_refresh_task(options[:for])
63
+ task.long_description = long_description if long_description
64
+ else
65
+ @long_desc = long_description
35
66
  end
36
67
  end
37
68
 
@@ -77,6 +108,8 @@ class Thor
77
108
  @method_options
78
109
  end
79
110
 
111
+ alias options method_options
112
+
80
113
  # Adds an option to the set of method options. If :for is given as option,
81
114
  # it allows you to change the options from a previous defined task.
82
115
  #
@@ -101,6 +134,7 @@ class Thor
101
134
  # :aliases - Aliases for this option.
102
135
  # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
103
136
  # :banner - String to show on usage notes.
137
+ # :hide - If you want to hide this option from the help.
104
138
  #
105
139
  def method_option(name, options={})
106
140
  scope = if options[:for]
@@ -112,31 +146,7 @@ class Thor
112
146
  build_option(name, options, scope)
113
147
  end
114
148
 
115
- # Parses the task and options from the given args, instantiate the class
116
- # and invoke the task. This method is used when the arguments must be parsed
117
- # from an array. If you are inside Ruby and want to use a Thor class, you
118
- # can simply initialize it:
119
- #
120
- # script = MyScript.new(args, options, config)
121
- # script.invoke(:task, first_arg, second_arg, third_arg)
122
- #
123
- def start(original_args=ARGV, config={})
124
- super do |given_args|
125
- meth = normalize_task_name(given_args.shift)
126
- task = all_tasks[meth]
127
-
128
- if task
129
- args, opts = Thor::Options.split(given_args)
130
- config.merge!(:task_options => task.options)
131
- else
132
- args, opts = given_args, {}
133
- end
134
-
135
- task ||= Thor::Task::Dynamic.new(meth)
136
- trailing = args[Range.new(arguments.size, -1)]
137
- new(args, opts, config).invoke(task, trailing || [])
138
- end
139
- end
149
+ alias option method_option
140
150
 
141
151
  # Prints help information for the given task.
142
152
  #
@@ -153,7 +163,12 @@ class Thor
153
163
  shell.say " #{banner(task)}"
154
164
  shell.say
155
165
  class_options_help(shell, nil => task.options.map { |_, o| o })
156
- shell.say task.description
166
+ if task.long_description
167
+ shell.say "Description:"
168
+ shell.print_wrapped(task.long_description, :indent => 2)
169
+ else
170
+ shell.say task.description
171
+ end
157
172
  end
158
173
 
159
174
  # Prints help information for this class.
@@ -161,42 +176,112 @@ class Thor
161
176
  # ==== Parameters
162
177
  # shell<Thor::Shell>
163
178
  #
164
- def help(shell)
165
- list = printable_tasks
179
+ def help(shell, subcommand = false)
180
+ list = printable_tasks(true, subcommand)
166
181
  Thor::Util.thor_classes_in(self).each do |klass|
167
182
  list += klass.printable_tasks(false)
168
183
  end
169
184
  list.sort!{ |a,b| a[0] <=> b[0] }
170
185
 
171
186
  shell.say "Tasks:"
172
- shell.print_table(list, :ident => 2, :truncate => true)
187
+ shell.print_table(list, :indent => 2, :truncate => true)
173
188
  shell.say
174
189
  class_options_help(shell)
175
190
  end
176
191
 
177
192
  # Returns tasks ready to be printed.
178
- def printable_tasks(all=true)
193
+ def printable_tasks(all = true, subcommand = false)
179
194
  (all ? all_tasks : tasks).map do |_, task|
195
+ next if task.hidden?
180
196
  item = []
181
- item << banner(task)
197
+ item << banner(task, false, subcommand)
182
198
  item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
183
199
  item
200
+ end.compact
201
+ end
202
+
203
+ def subcommands
204
+ @subcommands ||= from_superclass(:subcommands, [])
205
+ end
206
+
207
+ def subcommand(subcommand, subcommand_class)
208
+ self.subcommands << subcommand.to_s
209
+ subcommand_class.subcommand_help subcommand
210
+
211
+ define_method(subcommand) do |*args|
212
+ args, opts = Thor::Arguments.split(args)
213
+ invoke subcommand_class, args, opts
214
+ end
215
+ end
216
+
217
+ # Extend check unknown options to accept a hash of conditions.
218
+ #
219
+ # === Parameters
220
+ # options<Hash>: A hash containing :only and/or :except keys
221
+ def check_unknown_options!(options={})
222
+ @check_unknown_options ||= Hash.new
223
+ options.each do |key, value|
224
+ if value
225
+ @check_unknown_options[key] = Array(value)
226
+ else
227
+ @check_unknown_options.delete(key)
228
+ end
184
229
  end
230
+ @check_unknown_options
185
231
  end
186
232
 
187
- def handle_argument_error(task, error) #:nodoc:
188
- raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{task.formatted_usage(self, banner_base == "thor").inspect}."
233
+ # Overwrite check_unknown_options? to take subcommands and options into account.
234
+ def check_unknown_options?(config) #:nodoc:
235
+ options = check_unknown_options
236
+ return false unless options
237
+
238
+ task = config[:current_task]
239
+ return true unless task
240
+
241
+ name = task.name
242
+
243
+ if subcommands.include?(name)
244
+ false
245
+ elsif options[:except]
246
+ !options[:except].include?(name.to_sym)
247
+ elsif options[:only]
248
+ options[:only].include?(name.to_sym)
249
+ else
250
+ true
251
+ end
189
252
  end
190
253
 
191
254
  protected
192
255
 
256
+ # The method responsible for dispatching given the args.
257
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
258
+ meth ||= retrieve_task_name(given_args)
259
+ task = all_tasks[normalize_task_name(meth)]
260
+
261
+ if task
262
+ args, opts = Thor::Options.split(given_args)
263
+ else
264
+ args, opts = given_args, nil
265
+ task = Thor::DynamicTask.new(meth)
266
+ end
267
+
268
+ opts = given_opts || opts || []
269
+ config.merge!(:current_task => task, :task_options => task.options)
270
+
271
+ instance = new(args, opts, config)
272
+ yield instance if block_given?
273
+ args = instance.args
274
+ trailing = args[Range.new(arguments.size, -1)]
275
+ instance.invoke_task(task, trailing || [])
276
+ end
277
+
193
278
  # The banner for this class. You can customize it if you are invoking the
194
279
  # thor class by another ways which is not the Thor::Runner. It receives
195
280
  # the task that is going to be invoked and a boolean which indicates if
196
281
  # the namespace should be displayed as arguments.
197
282
  #
198
- def banner(task)
199
- "#{banner_base} #{task.formatted_usage(self, banner_base == "thor")}"
283
+ def banner(task, namespace = nil, subcommand = false)
284
+ "#{basename} #{task.formatted_usage(self, $thor_runner, subcommand)}"
200
285
  end
201
286
 
202
287
  def baseclass #:nodoc:
@@ -205,10 +290,11 @@ class Thor
205
290
 
206
291
  def create_task(meth) #:nodoc:
207
292
  if @usage && @desc
208
- tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options)
209
- @usage, @desc, @method_options = nil
293
+ base_class = @hide ? Thor::HiddenTask : Thor::Task
294
+ tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
295
+ @usage, @desc, @long_desc, @method_options, @hide = nil
210
296
  true
211
- elsif self.all_tasks[meth.to_s] || meth.to_sym == :method_missing
297
+ elsif self.all_tasks[meth] || meth == "method_missing"
212
298
  true
213
299
  else
214
300
  puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
@@ -223,13 +309,62 @@ class Thor
223
309
  @method_options = nil
224
310
  end
225
311
 
226
- # Receives a task name (can be nil), and try to get a map from it.
227
- # If a map can't be found use the sent name or the default task.
312
+ # Retrieve the task name from given args.
313
+ def retrieve_task_name(args) #:nodoc:
314
+ meth = args.first.to_s unless args.empty?
315
+ if meth && (map[meth] || meth !~ /^\-/)
316
+ args.shift
317
+ else
318
+ nil
319
+ end
320
+ end
321
+
322
+ # receives a (possibly nil) task name and returns a name that is in
323
+ # the tasks hash. In addition to normalizing aliases, this logic
324
+ # will determine if a shortened command is an unambiguous substring of
325
+ # a task or alias.
228
326
  #
327
+ # +normalize_task_name+ also converts names like +animal-prison+
328
+ # into +animal_prison+.
229
329
  def normalize_task_name(meth) #:nodoc:
230
- mapping = map[meth.to_s]
231
- meth = mapping || meth || default_task
232
- meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
330
+ return default_task.to_s.gsub('-', '_') unless meth
331
+
332
+ possibilities = find_task_possibilities(meth)
333
+ if possibilities.size > 1
334
+ raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]"
335
+ elsif possibilities.size < 1
336
+ meth = meth || default_task
337
+ elsif map[meth]
338
+ meth = map[meth]
339
+ else
340
+ meth = possibilities.first
341
+ end
342
+
343
+ meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
344
+ end
345
+
346
+ # this is the logic that takes the task name passed in by the user
347
+ # and determines whether it is an unambiguous substrings of a task or
348
+ # alias name.
349
+ def find_task_possibilities(meth)
350
+ len = meth.to_s.length
351
+ possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort
352
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
353
+
354
+ if possibilities.include?(meth)
355
+ [meth]
356
+ elsif unique_possibilities.size == 1
357
+ unique_possibilities
358
+ else
359
+ possibilities
360
+ end
361
+ end
362
+
363
+ def subcommand_help(cmd)
364
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
365
+ class_eval <<-RUBY
366
+ def help(task = nil, subcommand = true); super; end
367
+ RUBY
233
368
  end
234
369
  end
235
370
 
@@ -238,7 +373,7 @@ class Thor
238
373
  map HELP_MAPPINGS => :help
239
374
 
240
375
  desc "help [TASK]", "Describe available tasks or one specific task"
241
- def help(task=nil)
242
- task ? self.class.task_help(shell, task) : self.class.help(shell)
376
+ def help(task = nil, subcommand = false)
377
+ task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
243
378
  end
244
379
  end
@@ -1,9 +1,12 @@
1
1
  require 'fileutils'
2
+ require 'uri'
2
3
  require 'thor/core_ext/file_binary_read'
3
-
4
- Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
5
- require action
6
- end
4
+ require 'thor/actions/create_file'
5
+ require 'thor/actions/create_link'
6
+ require 'thor/actions/directory'
7
+ require 'thor/actions/empty_directory'
8
+ require 'thor/actions/file_manipulation'
9
+ require 'thor/actions/inject_into_file'
7
10
 
8
11
  class Thor
9
12
  module Actions
@@ -19,7 +22,13 @@ class Thor
19
22
  # inherited paths and the source root.
20
23
  #
21
24
  def source_paths
22
- @source_paths ||= []
25
+ @_source_paths ||= []
26
+ end
27
+
28
+ # Stores and return the source root for this class
29
+ def source_root(path=nil)
30
+ @_source_root = path if path
31
+ @_source_root
23
32
  end
24
33
 
25
34
  # Returns the source paths in the following order:
@@ -31,7 +40,7 @@ class Thor
31
40
  def source_paths_for_search
32
41
  paths = []
33
42
  paths += self.source_paths
34
- paths << self.source_root if self.respond_to?(:source_root)
43
+ paths << self.source_root if self.source_root
35
44
  paths += from_superclass(:source_paths, [])
36
45
  paths
37
46
  end
@@ -46,7 +55,7 @@ class Thor
46
55
  :desc => "Run but do not make any changes"
47
56
 
48
57
  class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
49
- :desc => "Supress status output"
58
+ :desc => "Suppress status output"
50
59
 
51
60
  class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
52
61
  :desc => "Skip files that already exist"
@@ -105,8 +114,12 @@ class Thor
105
114
  # the script started).
106
115
  #
107
116
  def relative_to_original_destination_root(path, remove_dot=true)
108
- path = path.gsub(@destination_stack[0], '.')
109
- remove_dot ? (path[2..-1] || '') : path
117
+ path = path.dup
118
+ if path.gsub!(@destination_stack[0], '.')
119
+ remove_dot ? (path[2..-1] || '') : path
120
+ else
121
+ path
122
+ end
110
123
  end
111
124
 
112
125
  # Holds source paths in instance so they can be manipulated.
@@ -115,7 +128,7 @@ class Thor
115
128
  @source_paths ||= self.class.source_paths_for_search
116
129
  end
117
130
 
118
- # Receives a file or directory and search for it in the source paths.
131
+ # Receives a file or directory and search for it in the source paths.
119
132
  #
120
133
  def find_in_source_paths(file)
121
134
  relative_root = relative_to_original_destination_root(destination_root, false)
@@ -125,12 +138,19 @@ class Thor
125
138
  return source_file if File.exists?(source_file)
126
139
  end
127
140
 
141
+ message = "Could not find #{file.inspect} in any of your source paths. "
142
+
143
+ unless self.class.source_root
144
+ message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
145
+ end
146
+
128
147
  if source_paths.empty?
129
- raise Error, "You don't have any source path defined for class #{self.class.name}. To fix this, " <<
130
- "you can define a source_root in your class."
148
+ message << "Currently you have no source paths."
131
149
  else
132
- raise Error, "Could not find #{file.inspect} in source paths."
150
+ message << "Your current source paths are: \n#{source_paths.join("\n")}"
133
151
  end
152
+
153
+ raise Error, message
134
154
  end
135
155
 
136
156
  # Do something in the root or on a provided subfolder. If a relative path
@@ -144,13 +164,23 @@ class Thor
144
164
  #
145
165
  def inside(dir='', config={}, &block)
146
166
  verbose = config.fetch(:verbose, false)
167
+ pretend = options[:pretend]
147
168
 
148
169
  say_status :inside, dir, verbose
149
170
  shell.padding += 1 if verbose
150
171
  @destination_stack.push File.expand_path(dir, destination_root)
151
172
 
152
- FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
153
- FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
173
+ # If the directory doesnt exist and we're not pretending
174
+ if !File.exist?(destination_root) && !pretend
175
+ FileUtils.mkdir_p(destination_root)
176
+ end
177
+
178
+ if pretend
179
+ # In pretend mode, just yield down to the block
180
+ block.arity == 1 ? yield(destination_root) : yield
181
+ else
182
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
183
+ end
154
184
 
155
185
  @destination_stack.pop
156
186
  shell.padding -= 1 if verbose
@@ -176,11 +206,19 @@ class Thor
176
206
  #
177
207
  def apply(path, config={})
178
208
  verbose = config.fetch(:verbose, true)
179
- path = find_in_source_paths(path) unless path =~ /^http\:\/\//
209
+ is_uri = path =~ /^https?\:\/\//
210
+ path = find_in_source_paths(path) unless is_uri
180
211
 
181
212
  say_status :apply, path, verbose
182
213
  shell.padding += 1 if verbose
183
- instance_eval(open(path).read)
214
+
215
+ if is_uri
216
+ contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
217
+ else
218
+ contents = open(path) {|io| io.read }
219
+ end
220
+
221
+ instance_eval(contents, path)
184
222
  shell.padding -= 1 if verbose
185
223
  end
186
224
 
@@ -188,7 +226,7 @@ class Thor
188
226
  #
189
227
  # ==== Parameters
190
228
  # command<String>:: the command to be executed.
191
- # config<Hash>:: give :verbose => false to not log the status. Specify :with
229
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
192
230
  # to append an executable to command executation.
193
231
  #
194
232
  # ==== Example
@@ -209,7 +247,10 @@ class Thor
209
247
  end
210
248
 
211
249
  say_status :run, desc, config.fetch(:verbose, true)
212
- `#{command}` unless options[:pretend]
250
+
251
+ unless options[:pretend]
252
+ config[:capture] ? `#{command}` : system("#{command}")
253
+ end
213
254
  end
214
255
 
215
256
  # Executes a ruby script (taking into account WIN32 platform quirks).
@@ -223,14 +264,15 @@ class Thor
223
264
  run command, config.merge(:with => Thor::Util.ruby_command)
224
265
  end
225
266
 
226
- # Run a thor command. A hash of options can be given and it's converted to
267
+ # Run a thor command. A hash of options can be given and it's converted to
227
268
  # switches.
228
269
  #
229
270
  # ==== Parameters
230
271
  # task<String>:: the task to be invoked
231
272
  # args<Array>:: arguments to the task
232
- # config<Hash>:: give :verbose => false to not log the status. Other options
233
- # are given as parameter to Thor.
273
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
274
+ # Other options are given as parameter to Thor.
275
+ #
234
276
  #
235
277
  # ==== Examples
236
278
  #
@@ -244,12 +286,13 @@ class Thor
244
286
  config = args.last.is_a?(Hash) ? args.pop : {}
245
287
  verbose = config.key?(:verbose) ? config.delete(:verbose) : true
246
288
  pretend = config.key?(:pretend) ? config.delete(:pretend) : false
289
+ capture = config.key?(:capture) ? config.delete(:capture) : false
247
290
 
248
291
  args.unshift task
249
292
  args.push Thor::Options.to_switches(config)
250
293
  command = args.join(' ').strip
251
294
 
252
- run command, :with => :thor, :verbose => verbose, :pretend => pretend
295
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
253
296
  end
254
297
 
255
298
  protected