thor 0.12.0 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
data/Thorfile CHANGED
@@ -1,6 +1,7 @@
1
1
  # enconding: utf-8
2
2
 
3
3
  require File.join(File.dirname(__FILE__), "lib", "thor", "version")
4
+ require 'rubygems'
4
5
  require 'thor/rake_compat'
5
6
  require 'spec/rake/spectask'
6
7
  require 'rdoc/task'
@@ -52,7 +53,7 @@ class Default < Thor
52
53
  s.bindir = "bin"
53
54
  s.executables = %w( thor rake2thor )
54
55
  s.files = s.extra_rdoc_files + Dir.glob("{bin,lib}/**/*")
55
- s.files.exclude 'spec/sandbox/**/*'
56
+ s.test_files.include 'spec/**/*'
56
57
  s.test_files.exclude 'spec/sandbox/**/*'
57
58
  end
58
59
 
@@ -78,14 +78,14 @@ class Thor
78
78
  @method_options
79
79
  end
80
80
 
81
- # Adds an option to the set of class options. If :for is given as option,
81
+ # Adds an option to the set of method options. If :for is given as option,
82
82
  # it allows you to change the options from a previous defined task.
83
83
  #
84
84
  # def previous_task
85
85
  # # magic
86
86
  # end
87
87
  #
88
- # method_options :foo => :bar, :for => :previous_task
88
+ # method_option :foo => :bar, :for => :previous_task
89
89
  #
90
90
  # def next_task
91
91
  # # magic
@@ -101,7 +101,6 @@ class Thor
101
101
  # :default - Default value for this argument. It cannot be required and have default values.
102
102
  # :aliases - Aliases for this option.
103
103
  # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
104
- # :group - The group for this options. Use by class options to output options in different levels.
105
104
  # :banner - String to show on usage notes.
106
105
  #
107
106
  def method_option(name, options={})
@@ -150,39 +149,42 @@ class Thor
150
149
  # namespace:: When true, shows the namespace in the output before the usage.
151
150
  # skip_inherited:: When true, does not show tasks from superclass.
152
151
  #
153
- def help(shell, meth=nil, options={})
154
- meth, options = nil, meth if meth.is_a?(Hash)
155
-
156
- if meth
157
- task = all_tasks[meth]
158
- raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task
152
+ def help(shell, options={})
153
+ if options[:task]
154
+ task = all_tasks[options[:task]]
155
+ raise UndefinedTaskError, "task '#{options[:task]}' could not be found in namespace '#{self.namespace}'" unless task
159
156
 
160
157
  shell.say "Usage:"
161
- shell.say " #{banner(task, options[:namespace], false)}"
158
+ shell.say " #{banner(task)}"
162
159
  shell.say
163
- class_options_help(shell, "Class", :Method => task.options.map { |_, o| o })
160
+ class_options_help(shell, nil => task.options.map { |_, o| o })
164
161
  shell.say task.description
165
162
  else
166
- list = (options[:short] ? tasks : all_tasks).map do |_, task|
167
- item = [ banner(task, options[:namespace]) ]
168
- item << "# #{task.short_description}" if task.short_description
169
- item << " "
163
+ list = printable_tasks(!options[:short])
164
+
165
+ Thor::Util.thor_classes_in(self).each do |klass|
166
+ list += klass.printable_tasks(false)
170
167
  end
171
168
 
172
- options[:ident] ||= 2
169
+ list.sort!{ |a,b| a[0] <=> b[0] }
170
+
173
171
  if options[:short]
174
- shell.print_list(list, :ident => options[:ident])
172
+ shell.print_table(list, :truncate => true)
175
173
  else
176
174
  shell.say "Tasks:"
177
- shell.print_list(list, :ident => options[:ident])
178
- end
179
-
180
- Thor::Util.thor_classes_in(self).each do |subclass|
181
- namespace = options[:namespace] == true || subclass.namespace.gsub(/^#{self.namespace}:/, '')
182
- subclass.help(shell, options.merge(:short => true, :namespace => namespace))
175
+ shell.print_table(list, :ident => 2, :truncate => true)
176
+ shell.say
177
+ class_options_help(shell)
183
178
  end
179
+ end
180
+ end
184
181
 
185
- class_options_help(shell, "Class") unless options[:short]
182
+ def printable_tasks(all=true)
183
+ (all ? all_tasks : tasks).map do |_, task|
184
+ item = []
185
+ item << banner(task)
186
+ item << "# #{task.description}" if task.description
187
+ item
186
188
  end
187
189
  end
188
190
 
@@ -193,8 +195,8 @@ class Thor
193
195
  # the task that is going to be invoked and a boolean which indicates if
194
196
  # the namespace should be displayed as arguments.
195
197
  #
196
- def banner(task, namespace=true, show_options=true)
197
- task.formatted_usage(self, namespace, show_options)
198
+ def banner(task)
199
+ "thor " + task.formatted_usage(self)
198
200
  end
199
201
 
200
202
  def baseclass #:nodoc:
@@ -237,6 +239,6 @@ class Thor
237
239
 
238
240
  desc "help [TASK]", "Describe available tasks or one specific task"
239
241
  def help(task=nil)
240
- self.class.help(shell, task, :namespace => task && task.include?(?:))
242
+ self.class.help(shell, :task => task)
241
243
  end
242
244
  end
@@ -38,17 +38,17 @@ class Thor
38
38
  # Add runtime options that help actions execution.
39
39
  #
40
40
  def add_runtime_options!
41
- class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
42
- :desc => "Run but do not make any changes"
43
-
44
41
  class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
45
42
  :desc => "Overwrite files that already exist"
46
43
 
47
- class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
48
- :desc => "Skip files that already exist"
44
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
45
+ :desc => "Run but do not make any changes"
49
46
 
50
47
  class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
51
48
  :desc => "Supress status output"
49
+
50
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
51
+ :desc => "Skip files that already exist"
52
52
  end
53
53
  end
54
54
 
@@ -79,11 +79,9 @@ class Thor
79
79
  next if dirname == given_destination
80
80
  base.empty_directory(dirname, config)
81
81
  when /\.tt$/
82
- destination = base.template(file_source, file_destination[0..-4], config)
83
- @block.call(destination) if @block
82
+ destination = base.template(file_source, file_destination[0..-4], config, &@block)
84
83
  else
85
- destination = base.copy_file(file_source, file_destination, config)
86
- @block.call(destination) if @block
84
+ destination = base.copy_file(file_source, file_destination, config, &@block)
87
85
  end
88
86
  end
89
87
  end
@@ -18,12 +18,14 @@ class Thor
18
18
  #
19
19
  # copy_file "doc/README"
20
20
  #
21
- def copy_file(source, destination=nil, config={})
21
+ def copy_file(source, destination=nil, config={}, &block)
22
22
  destination ||= source
23
23
  source = File.expand_path(find_in_source_paths(source.to_s))
24
24
 
25
25
  create_file destination, nil, config do
26
- File.read(source)
26
+ content = File.read(source)
27
+ content = block.call(content) if block
28
+ content
27
29
  end
28
30
  end
29
31
 
@@ -72,13 +74,15 @@ class Thor
72
74
  #
73
75
  # template "doc/README"
74
76
  #
75
- def template(source, destination=nil, config={})
77
+ def template(source, destination=nil, config={}, &block)
76
78
  destination ||= source
77
79
  source = File.expand_path(find_in_source_paths(source.to_s))
78
80
  context = instance_eval('binding')
79
81
 
80
82
  create_file destination, nil, config do
81
- ERB.new(::File.read(source), nil, '-').result(context)
83
+ content = ERB.new(::File.read(source), nil, '-').result(context)
84
+ content = block.call(content) if block
85
+ content
82
86
  end
83
87
  end
84
88
 
@@ -92,6 +92,8 @@ class Thor
92
92
  end
93
93
 
94
94
  module ClassMethods
95
+ attr_accessor :debugging
96
+
95
97
  # Adds an argument to the class and creates an attr_accessor for it.
96
98
  #
97
99
  # Arguments are different from options in several aspects. The first one
@@ -347,10 +349,11 @@ class Thor
347
349
  # Default way to start generators from the command line.
348
350
  #
349
351
  def start(given_args=ARGV, config={})
352
+ self.debugging = given_args.include?("--debug")
350
353
  config[:shell] ||= Thor::Base.shell.new
351
354
  yield
352
355
  rescue Thor::Error => e
353
- if given_args.include?("--debug")
356
+ if debugging
354
357
  raise e
355
358
  else
356
359
  config[:shell].error e.message
@@ -361,48 +364,43 @@ class Thor
361
364
  protected
362
365
 
363
366
  # Prints the class options per group. If an option does not belong to
364
- # any group, it uses the ungrouped name value. This method provide to
365
- # hooks to add extra options, one of them if the third argument called
366
- # extra_group that should be a hash in the format :group => Array[Options].
367
- #
368
- # The second is by returning a lambda used to print values. The lambda
369
- # requires two options: the group name and the array of options.
367
+ # any group, it's printed as Class option.
370
368
  #
371
- def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc:
372
- groups = {}
373
-
369
+ def class_options_help(shell, groups={}) #:nodoc:
370
+ # Group options by group
374
371
  class_options.each do |_, value|
375
372
  groups[value.group] ||= []
376
373
  groups[value.group] << value
377
374
  end
378
375
 
379
- printer = proc do |group_name, options|
380
- list = []
381
- padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
376
+ # Deal with default group
377
+ global_options = groups.delete(nil) || []
378
+ print_options(shell, global_options)
379
+
380
+ # Print all others
381
+ groups.each do |group_name, options|
382
+ print_options(shell, options, group_name)
383
+ end
384
+ end
385
+
386
+ # Receives a set of options and print them.
387
+ def print_options(shell, options, group_name=nil)
388
+ return if options.empty?
382
389
 
383
- options.each do |option|
384
- item = [ option.usage(padding) ]
385
- item.push(option.description ? "# #{option.description}" : "")
390
+ list = []
391
+ padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
386
392
 
387
- list << item
388
- list << [ "", "# Default: #{option.default}" ] if option.show_default?
389
- end
393
+ options.each do |option|
394
+ item = [ option.usage(padding) ]
395
+ item.push(option.description ? "# #{option.description}" : "")
390
396
 
391
- unless list.empty?
392
- shell.say(group_name ? "#{group_name} options:" : "Options:")
393
- shell.print_table(list, :ident => 2)
394
- shell.say ""
395
- end
397
+ list << item
398
+ list << [ "", "# Default: #{option.default}" ] if option.show_default?
396
399
  end
397
400
 
398
- # Deal with default group
399
- global_options = groups.delete(nil) || []
400
- printer.call(ungrouped_name, global_options) if global_options
401
-
402
- # Print all others
403
- groups = extra_group.merge(groups) if extra_group
404
- groups.each(&printer)
405
- printer
401
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
402
+ shell.print_table(list, :ident => 2)
403
+ shell.say ""
406
404
  end
407
405
 
408
406
  # Raises an error if the word given is a Thor reserved word.
@@ -46,8 +46,8 @@ class Thor::Group
46
46
  shell.say banner
47
47
  else
48
48
  shell.say "Usage:"
49
- shell.say " #{banner}"
50
- shell.say
49
+ shell.say " #{banner}\n"
50
+ shell.say ""
51
51
  class_options_help(shell)
52
52
  shell.say self.desc if self.desc
53
53
  end
@@ -177,15 +177,11 @@ class Thor::Group
177
177
  # Overwrite class options help to allow invoked generators options to be
178
178
  # shown recursively when invoking a generator.
179
179
  #
180
- def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc:
181
- group_options = {}
182
-
183
- get_options_from_invocations(group_options, class_options) do |klass|
184
- klass.send(:get_options_from_invocations, group_options, class_options)
180
+ def class_options_help(shell, groups={}) #:nodoc:
181
+ get_options_from_invocations(groups, class_options) do |klass|
182
+ klass.send(:get_options_from_invocations, groups, class_options)
185
183
  end
186
-
187
- group_options.merge!(extra_group) if extra_group
188
- super(shell, ungrouped_name, group_options)
184
+ super(shell, groups)
189
185
  end
190
186
 
191
187
  # Get invocations array and merge options from invocations. Those
@@ -224,7 +220,7 @@ class Thor::Group
224
220
  # thor class by another ways which is not the Thor::Runner.
225
221
  #
226
222
  def banner
227
- "#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
223
+ "thor #{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
228
224
  end
229
225
 
230
226
  def baseclass #:nodoc:
@@ -149,6 +149,10 @@ class Thor::Runner < Thor #:nodoc:
149
149
 
150
150
  private
151
151
 
152
+ def self.banner(task)
153
+ "thor " + task.formatted_usage(self, false)
154
+ end
155
+
152
156
  def thor_root
153
157
  Thor::Util.thor_root
154
158
  end
@@ -289,11 +293,11 @@ class Thor::Runner < Thor #:nodoc:
289
293
  unless klass.tasks.empty?
290
294
  base = klass.namespace
291
295
 
292
- color = base == "default" ? :magenta : :blue
293
- say shell.set_color(base, color, true)
296
+ say shell.set_color(base, :blue, true)
294
297
  say "-" * base.length
295
298
 
296
- klass.help(shell, :short => true, :ident => 0, :namespace => true)
299
+ klass.help(shell, :short => true)
300
+ say
297
301
  end
298
302
  end
299
303
  end
@@ -22,7 +22,7 @@ class Thor
22
22
  end
23
23
 
24
24
  module Shell
25
- SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_list, :print_table]
25
+ SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table]
26
26
 
27
27
  # Add shell to initialize config values.
28
28
  #
@@ -75,30 +75,6 @@ class Thor
75
75
  !yes?(statement, color)
76
76
  end
77
77
 
78
- # Prints a list of items.
79
- #
80
- # ==== Parameters
81
- # list<Array[String, String, ...]>
82
- #
83
- # ==== Options
84
- # mode:: Can be :rows or :inline. Defaults to :rows.
85
- # ident:: Ident each item with the value given.
86
- #
87
- def print_list(list, options={})
88
- return if list.empty?
89
-
90
- ident = " " * (options[:ident] || 0)
91
- content = case options[:mode]
92
- when :inline
93
- last = list.pop
94
- "#{list.join(", ")}, and #{last}"
95
- else # rows
96
- ident + list.join("\n#{ident}")
97
- end
98
-
99
- $stdout.puts content
100
- end
101
-
102
78
  # Prints a table.
103
79
  #
104
80
  # ==== Parameters
@@ -110,20 +86,26 @@ class Thor
110
86
  def print_table(table, options={})
111
87
  return if table.empty?
112
88
 
113
- formats = []
89
+ formats, ident = [], options[:ident].to_i
90
+ options[:truncate] = terminal_width if options[:truncate] == true
91
+
114
92
  0.upto(table.first.length - 2) do |i|
115
93
  maxima = table.max{ |a,b| a[i].size <=> b[i].size }[i].size
116
94
  formats << "%-#{maxima + 2}s"
117
95
  end
118
96
 
119
- formats[0] = formats[0].insert(0, " " * options[:ident]) if options[:ident]
97
+ formats[0] = formats[0].insert(0, " " * ident)
120
98
  formats << "%s"
121
99
 
122
100
  table.each do |row|
101
+ sentence = ""
102
+
123
103
  row.each_with_index do |column, i|
124
- $stdout.print formats[i] % column.to_s
104
+ sentence << formats[i] % column.to_s
125
105
  end
126
- $stdout.puts
106
+
107
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
108
+ $stdout.puts sentence
127
109
  end
128
110
  end
129
111
 
@@ -143,7 +125,7 @@ class Thor
143
125
  answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
144
126
 
145
127
  case answer
146
- when is?(:yes), is?(:force)
128
+ when is?(:yes), is?(:force), ""
147
129
  return true
148
130
  when is?(:no), is?(:skip)
149
131
  return false
@@ -214,6 +196,44 @@ HELP
214
196
  base && base.options[:quiet]
215
197
  end
216
198
 
199
+ # This code was copied from Rake, available under MIT-LICENSE
200
+ # Copyright (c) 2003, 2004 Jim Weirich
201
+ def terminal_width
202
+ if ENV['THOR_COLUMNS']
203
+ result = ENV['THOR_COLUMNS'].to_i
204
+ else
205
+ result = unix? ? dynamic_width : 80
206
+ end
207
+ (result < 10) ? 80 : result
208
+ rescue
209
+ 80
210
+ end
211
+
212
+ # Calculate the dynamic width of the terminal
213
+ def dynamic_width
214
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
215
+ end
216
+
217
+ def dynamic_width_stty
218
+ %x{stty size 2>/dev/null}.split[1].to_i
219
+ end
220
+
221
+ def dynamic_width_tput
222
+ %x{tput cols 2>/dev/null}.to_i
223
+ end
224
+
225
+ def unix?
226
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
227
+ end
228
+
229
+ def truncate(string, width)
230
+ if string.length <= width
231
+ string
232
+ else
233
+ ( string[0, width-3] || "" ) + "..."
234
+ end
235
+ end
236
+
217
237
  end
218
238
  end
219
239
  end