thor 0.12.0 → 0.12.3

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/CHANGELOG.rdoc CHANGED
@@ -1,9 +1,7 @@
1
- == TODO
2
-
3
- * Improve spec coverage for Thor::Runner
4
-
5
- == 0.12, released 2009-11-06
1
+ == 0.12, released 2010-01-02
6
2
 
3
+ * Removed rr in favor to rspec mock framework
4
+ * Improved output for thor -T
7
5
  * [#7] Do not force white color on status
8
6
  * [#8] Yield a block with the filename on directory
9
7
 
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
 
data/bin/thor CHANGED
@@ -4,4 +4,5 @@
4
4
  require 'thor'
5
5
  require 'thor/runner'
6
6
 
7
+ $thor_runner = true
7
8
  Thor::Runner.start
@@ -42,7 +42,7 @@ class Thor
42
42
  # Boolean:: true if it is identical, false otherwise.
43
43
  #
44
44
  def identical?
45
- exists? && File.read(destination) == render
45
+ exists? && File.binread(destination) == render
46
46
  end
47
47
 
48
48
  # Holds the content to be added to the file.
@@ -58,7 +58,7 @@ class Thor
58
58
  def invoke!
59
59
  invoke_with_conflict_check do
60
60
  FileUtils.mkdir_p(File.dirname(destination))
61
- File.open(destination, 'w'){ |f| f.write render }
61
+ File.open(destination, 'wb') { |f| f.write render }
62
62
  end
63
63
  given_destination
64
64
  end
@@ -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.binread(source)
27
+ content = block.call(content) if block
28
+ content
27
29
  end
28
30
  end
29
31
 
@@ -46,7 +48,7 @@ class Thor
46
48
  #
47
49
  def get(source, destination=nil, config={}, &block)
48
50
  source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
49
- render = open(source).read
51
+ render = File.binread(source)
50
52
 
51
53
  destination ||= if block_given?
52
54
  block.arity == 1 ? block.call(render) : block.call
@@ -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.binread(source), nil, '-').result(context)
84
+ content = block.call(content) if block
85
+ content
82
86
  end
83
87
  end
84
88
 
@@ -189,7 +193,7 @@ class Thor
189
193
  say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
190
194
 
191
195
  unless options[:pretend]
192
- content = File.read(path)
196
+ content = File.binread(path)
193
197
  content.gsub!(flag, *args, &block)
194
198
  File.open(path, 'wb') { |file| file.write(content) }
195
199
  end
@@ -90,7 +90,7 @@ class Thor
90
90
  #
91
91
  def replace!(regexp, string)
92
92
  unless base.options[:pretend]
93
- content = File.read(destination)
93
+ content = File.binread(destination)
94
94
  content.gsub!(regexp, string)
95
95
  File.open(destination, 'wb') { |file| file.write(content) }
96
96
  end
data/lib/thor/actions.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'thor/core_ext/file_binary_read'
2
3
 
3
4
  Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
4
5
  require action
@@ -38,17 +39,17 @@ class Thor
38
39
  # Add runtime options that help actions execution.
39
40
  #
40
41
  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
42
  class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
45
43
  :desc => "Overwrite files that already exist"
46
44
 
47
- class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
48
- :desc => "Skip files that already exist"
45
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
46
+ :desc => "Run but do not make any changes"
49
47
 
50
48
  class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
51
49
  :desc => "Supress status output"
50
+
51
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
52
+ :desc => "Skip files that already exist"
52
53
  end
53
54
  end
54
55
 
data/lib/thor/base.rb CHANGED
@@ -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.
@@ -0,0 +1,9 @@
1
+ class File #:nodoc:
2
+
3
+ unless File.respond_to?(:binread)
4
+ def self.binread(file)
5
+ File.open(file, 'rb') { |f| f.read }
6
+ end
7
+ end
8
+
9
+ end
data/lib/thor/group.rb CHANGED
@@ -41,16 +41,12 @@ class Thor::Group
41
41
  # ==== Options
42
42
  # short:: When true, shows only usage.
43
43
  #
44
- def help(shell, options={})
45
- if options[:short]
46
- shell.say banner
47
- else
48
- shell.say "Usage:"
49
- shell.say " #{banner}"
50
- shell.say
51
- class_options_help(shell)
52
- shell.say self.desc if self.desc
53
- end
44
+ def help(shell)
45
+ shell.say "Usage:"
46
+ shell.say " #{banner}\n"
47
+ shell.say
48
+ class_options_help(shell)
49
+ shell.say self.desc if self.desc
54
50
  end
55
51
 
56
52
  # Stores invocations for this class merging with superclass values.
@@ -177,15 +173,11 @@ class Thor::Group
177
173
  # Overwrite class options help to allow invoked generators options to be
178
174
  # shown recursively when invoking a generator.
179
175
  #
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)
176
+ def class_options_help(shell, groups={}) #:nodoc:
177
+ get_options_from_invocations(groups, class_options) do |klass|
178
+ klass.send(:get_options_from_invocations, groups, class_options)
185
179
  end
186
-
187
- group_options.merge!(extra_group) if extra_group
188
- super(shell, ungrouped_name, group_options)
180
+ super(shell, groups)
189
181
  end
190
182
 
191
183
  # Get invocations array and merge options from invocations. Those
@@ -218,13 +210,27 @@ class Thor::Group
218
210
  end
219
211
  end
220
212
 
213
+ # Returns tasks ready to be printed.
214
+ def printable_tasks(*)
215
+ item = []
216
+ item << banner
217
+ item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
218
+ [item]
219
+ end
220
+
221
221
  protected
222
222
 
223
223
  # The banner for this class. You can customize it if you are invoking the
224
224
  # thor class by another ways which is not the Thor::Runner.
225
225
  #
226
226
  def banner
227
- "#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
227
+ base = $thor_runner ? "thor" : File.basename($0.split(" ").first)
228
+ "#{base} #{self_task.formatted_usage(self, false)}"
229
+ end
230
+
231
+ # Represents the whole class as a task.
232
+ def self_task #:nodoc:
233
+ Thor::Task::Dynamic.new(self.namespace, class_options)
228
234
  end
229
235
 
230
236
  def baseclass #:nodoc:
@@ -241,23 +247,25 @@ class Thor::Group
241
247
 
242
248
  protected
243
249
 
244
- # Shortcut to invoke with padding and block handling. Use internally by
245
- # invoke and invoke_from_option class methods.
246
- #
247
- def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
248
- shell.padding += 1
249
-
250
- result = if block_given?
251
- if block.arity == 2
252
- block.call(self, klass)
253
- else
254
- block.call(self, klass, task)
255
- end
256
- else
257
- invoke klass, task, *args
250
+ # Shortcut to invoke with padding and block handling. Use internally by
251
+ # invoke and invoke_from_option class methods.
252
+ def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
253
+ shell.padding += 1
254
+
255
+ result = if block_given?
256
+ case block.arity
257
+ when 3
258
+ block.call(self, klass, task)
259
+ when 2
260
+ block.call(self, klass)
261
+ when 1
262
+ instance_exec(klass, &block)
258
263
  end
259
-
260
- shell.padding -= 1
261
- result
264
+ else
265
+ invoke klass, task, *args
262
266
  end
267
+
268
+ shell.padding -= 1
269
+ result
270
+ end
263
271
  end
data/lib/thor/runner.rb CHANGED
@@ -124,11 +124,7 @@ class Thor::Runner < Thor #:nodoc:
124
124
  method_options :internal => :boolean
125
125
  def installed
126
126
  initialize_thorfiles(nil, true)
127
-
128
- klasses = Thor::Base.subclasses
129
- klasses -= [Thor, Thor::Runner] unless options["internal"]
130
-
131
- display_klasses(true, klasses)
127
+ display_klasses(true, options["internal"])
132
128
  end
133
129
 
134
130
  desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
@@ -144,11 +140,15 @@ class Thor::Runner < Thor #:nodoc:
144
140
  (options[:all] || k.group == group) && k.namespace =~ search
145
141
  end
146
142
 
147
- display_klasses(false, klasses)
143
+ display_klasses(false, false, klasses)
148
144
  end
149
145
 
150
146
  private
151
147
 
148
+ def self.banner(task)
149
+ "thor " + task.formatted_usage(self, false)
150
+ end
151
+
152
152
  def thor_root
153
153
  Thor::Util.thor_root
154
154
  end
@@ -156,7 +156,7 @@ class Thor::Runner < Thor #:nodoc:
156
156
  def thor_yaml
157
157
  @thor_yaml ||= begin
158
158
  yaml_file = File.join(thor_root, "thor.yml")
159
- yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
159
+ yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
160
160
  yaml || {}
161
161
  end
162
162
  end
@@ -215,9 +215,6 @@ class Thor::Runner < Thor #:nodoc:
215
215
  # 5. c:\ <-- no Thorfiles found!
216
216
  #
217
217
  def thorfiles(relevant_to=nil, skip_lookup=false)
218
- # TODO Remove this dealing with deprecated thor when :namespaces: is available as constants
219
- save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml)
220
-
221
218
  thorfiles = []
222
219
 
223
220
  unless skip_lookup
@@ -253,47 +250,54 @@ class Thor::Runner < Thor #:nodoc:
253
250
  # Display information about the given klasses. If with_module is given,
254
251
  # it shows a table with information extracted from the yaml file.
255
252
  #
256
- def display_klasses(with_modules=false, klasses=Thor.subclasses)
257
- klasses -= [Thor, Thor::Runner] unless with_modules
253
+ def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
254
+ klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
255
+
258
256
  raise Error, "No Thor tasks available" if klasses.empty?
257
+ show_modules if with_modules && !thor_yaml.empty?
259
258
 
260
- if with_modules && !thor_yaml.empty?
261
- info = []
262
- labels = ["Modules", "Namespaces"]
259
+ # Remove subclasses
260
+ klasses.dup.each do |klass|
261
+ klasses -= Thor::Util.thor_classes_in(klass)
262
+ end
263
263
 
264
- info << labels
265
- info << [ "-" * labels[0].size, "-" * labels[1].size ]
264
+ list = Hash.new { |h,k| h[k] = [] }
265
+ groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
266
266
 
267
- thor_yaml.each do |name, hash|
268
- info << [ name, hash[:namespaces].join(", ") ]
269
- end
267
+ # Get classes which inherit from Thor
268
+ (klasses - groups).each { |k| list[k.namespace] += k.printable_tasks(false) }
270
269
 
271
- print_table info
272
- say ""
273
- end
270
+ # Get classes which inherit from Thor::Base
271
+ groups.map! { |k| k.printable_tasks(false).first }
272
+ list["root"] = groups
274
273
 
275
- unless klasses.empty?
276
- klasses.dup.each do |klass|
277
- klasses -= Thor::Util.thor_classes_in(klass)
278
- end
274
+ # Order namespaces with default coming first
275
+ list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
276
+ list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
277
+ end
279
278
 
280
- klasses.each { |k| display_tasks(k) }
281
- else
282
- say "\033[1;34mNo Thor tasks available\033[0m"
283
- end
279
+ def display_tasks(namespace, list) #:nodoc:
280
+ list.sort!{ |a,b| a[0] <=> b[0] }
281
+
282
+ say shell.set_color(namespace, :blue, true)
283
+ say "-" * namespace.size
284
+
285
+ print_table(list, :truncate => true)
286
+ say
284
287
  end
285
288
 
286
- # Display tasks from the given Thor class.
287
- #
288
- def display_tasks(klass)
289
- unless klass.tasks.empty?
290
- base = klass.namespace
289
+ def show_modules #:nodoc:
290
+ info = []
291
+ labels = ["Modules", "Namespaces"]
291
292
 
292
- color = base == "default" ? :magenta : :blue
293
- say shell.set_color(base, color, true)
294
- say "-" * base.length
293
+ info << labels
294
+ info << [ "-" * labels[0].size, "-" * labels[1].size ]
295
295
 
296
- klass.help(shell, :short => true, :ident => 0, :namespace => true)
296
+ thor_yaml.each do |name, hash|
297
+ info << [ name, hash[:namespaces].join(", ") ]
297
298
  end
299
+
300
+ print_table info
301
+ say ""
298
302
  end
299
303
  end
@@ -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
@@ -63,7 +63,7 @@ class Thor
63
63
  #
64
64
  def show_diff(destination, content) #:nodoc:
65
65
  if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
66
- actual = File.read(destination).to_s.split("\n")
66
+ actual = File.binread(destination).to_s.split("\n")
67
67
  content = content.to_s.split("\n")
68
68
 
69
69
  Diff::LCS.sdiff(actual, content).each do |diff|
data/lib/thor/shell.rb CHANGED
@@ -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
  #