thor 0.12.0 → 0.12.2

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