thor 0.19.4 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,18 @@
1
1
  class Thor
2
2
  class Option < Argument #:nodoc:
3
- attr_reader :aliases, :group, :lazy_default, :hide
3
+ attr_reader :aliases, :group, :lazy_default, :hide, :repeatable
4
4
 
5
5
  VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
6
6
 
7
7
  def initialize(name, options = {})
8
+ @check_default_type = options[:check_default_type]
8
9
  options[:required] = false unless options.key?(:required)
10
+ @repeatable = options.fetch(:repeatable, false)
9
11
  super
10
- @lazy_default = options[:lazy_default]
11
- @group = options[:group].to_s.capitalize if options[:group]
12
- @aliases = Array(options[:aliases])
13
- @hide = options[:hide]
12
+ @lazy_default = options[:lazy_default]
13
+ @group = options[:group].to_s.capitalize if options[:group]
14
+ @aliases = Array(options[:aliases])
15
+ @hide = options[:hide]
14
16
  end
15
17
 
16
18
  # This parse quick options given as method_options. It makes several
@@ -80,12 +82,12 @@ class Thor
80
82
 
81
83
  def usage(padding = 0)
82
84
  sample = if banner && !banner.to_s.empty?
83
- "#{switch_name}=#{banner}"
85
+ "#{switch_name}=#{banner}".dup
84
86
  else
85
87
  switch_name
86
88
  end
87
89
 
88
- sample = "[#{sample}]" unless required?
90
+ sample = "[#{sample}]".dup unless required?
89
91
 
90
92
  if boolean?
91
93
  sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-")
@@ -127,8 +129,19 @@ class Thor
127
129
  @default.class.name.downcase.to_sym
128
130
  end
129
131
 
130
- # TODO: This should raise an ArgumentError in a future version of Thor
131
- warn "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" unless default_type == @type
132
+ expected_type = (@repeatable && @type != :hash) ? :array : @type
133
+
134
+ if default_type != expected_type
135
+ err = "Expected #{expected_type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})"
136
+
137
+ if @check_default_type
138
+ raise ArgumentError, err
139
+ elsif @check_default_type == nil
140
+ Thor.deprecation_warning "#{err}.\n" +
141
+ 'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' +
142
+ ' or call `allow_incompatible_default_type!` in your code'
143
+ end
144
+ end
132
145
  end
133
146
 
134
147
  def dasherized?
@@ -18,19 +18,20 @@ class Thor
18
18
  when Hash
19
19
  "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}"
20
20
  when nil, false
21
- ""
21
+ nil
22
22
  else
23
23
  "--#{key} #{value.inspect}"
24
24
  end
25
- end.join(" ")
25
+ end.compact.join(" ")
26
26
  end
27
27
 
28
28
  # Takes a hash of Thor::Option and a hash with defaults.
29
29
  #
30
30
  # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
31
31
  # an unknown option or a regular argument.
32
- def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false)
32
+ def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
33
33
  @stop_on_unknown = stop_on_unknown
34
+ @disable_required_check = disable_required_check
34
35
  options = hash_options.values
35
36
  super(options)
36
37
 
@@ -43,6 +44,8 @@ class Thor
43
44
  @shorts = {}
44
45
  @switches = {}
45
46
  @extra = []
47
+ @stopped_parsing_after_extra_index = nil
48
+ @is_treated_as_value = false
46
49
 
47
50
  options.each do |option|
48
51
  @switches[option.switch_name] = option
@@ -65,14 +68,26 @@ class Thor
65
68
  if result == OPTS_END
66
69
  shift
67
70
  @parsing_options = false
71
+ @stopped_parsing_after_extra_index ||= @extra.size
68
72
  super
69
73
  else
70
74
  result
71
75
  end
72
76
  end
73
77
 
78
+ def shift
79
+ @is_treated_as_value = false
80
+ super
81
+ end
82
+
83
+ def unshift(arg, is_value: false)
84
+ @is_treated_as_value = is_value
85
+ super(arg)
86
+ end
87
+
74
88
  def parse(args) # rubocop:disable MethodLength
75
89
  @pile = args.dup
90
+ @is_treated_as_value = false
76
91
  @parsing_options = true
77
92
 
78
93
  while peek
@@ -85,7 +100,10 @@ class Thor
85
100
  when SHORT_SQ_RE
86
101
  unshift($1.split("").map { |f| "-#{f}" })
87
102
  next
88
- when EQ_RE, SHORT_NUM
103
+ when EQ_RE
104
+ unshift($2, is_value: true)
105
+ switch = $1
106
+ when SHORT_NUM
89
107
  unshift($2)
90
108
  switch = $1
91
109
  when LONG_RE, SHORT_RE
@@ -94,10 +112,12 @@ class Thor
94
112
 
95
113
  switch = normalize_switch(switch)
96
114
  option = switch_option(switch)
97
- @assigns[option.human_name] = parse_peek(switch, option)
115
+ result = parse_peek(switch, option)
116
+ assign_result!(option, result)
98
117
  elsif @stop_on_unknown
99
118
  @parsing_options = false
100
119
  @extra << shifted
120
+ @stopped_parsing_after_extra_index ||= @extra.size
101
121
  @extra << shift while peek
102
122
  break
103
123
  elsif match
@@ -111,7 +131,7 @@ class Thor
111
131
  end
112
132
  end
113
133
 
114
- check_requirement!
134
+ check_requirement! unless @disable_required_check
115
135
 
116
136
  assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
117
137
  assigns.freeze
@@ -119,18 +139,31 @@ class Thor
119
139
  end
120
140
 
121
141
  def check_unknown!
142
+ to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra
143
+
122
144
  # an unknown option starts with - or -- and has no more --'s afterward.
123
- unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
124
- raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
145
+ unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ }
146
+ raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty?
125
147
  end
126
148
 
127
149
  protected
128
150
 
151
+ def assign_result!(option, result)
152
+ if option.repeatable && option.type == :hash
153
+ (@assigns[option.human_name] ||= {}).merge!(result)
154
+ elsif option.repeatable
155
+ (@assigns[option.human_name] ||= []) << result
156
+ else
157
+ @assigns[option.human_name] = result
158
+ end
159
+ end
160
+
129
161
  # Check if the current value in peek is a registered switch.
130
162
  #
131
163
  # Two booleans are returned. The first is true if the current value
132
164
  # starts with a hyphen; the second is true if it is a registered switch.
133
165
  def current_is_switch?
166
+ return [false, false] if @is_treated_as_value
134
167
  case peek
135
168
  when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
136
169
  [true, switch?($1)]
@@ -142,6 +175,7 @@ class Thor
142
175
  end
143
176
 
144
177
  def current_is_switch_formatted?
178
+ return false if @is_treated_as_value
145
179
  case peek
146
180
  when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
147
181
  true
@@ -151,11 +185,12 @@ class Thor
151
185
  end
152
186
 
153
187
  def current_is_value?
188
+ return true if @is_treated_as_value
154
189
  peek && (!parsing_options? || super)
155
190
  end
156
191
 
157
192
  def switch?(arg)
158
- switch_option(normalize_switch(arg))
193
+ !switch_option(normalize_switch(arg)).nil?
159
194
  end
160
195
 
161
196
  def switch_option(arg)
@@ -188,7 +223,7 @@ class Thor
188
223
  shift
189
224
  false
190
225
  else
191
- true
226
+ @switches.key?(switch) || !no_or_skip?(switch)
192
227
  end
193
228
  else
194
229
  @switches.key?(switch) || !no_or_skip?(switch)
data/lib/thor/parser.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "thor/parser/argument"
2
- require "thor/parser/arguments"
3
- require "thor/parser/option"
4
- require "thor/parser/options"
1
+ require_relative "parser/argument"
2
+ require_relative "parser/arguments"
3
+ require_relative "parser/option"
4
+ require_relative "parser/options"
@@ -25,6 +25,7 @@ class Thor
25
25
  end
26
26
 
27
27
  def self.included(base)
28
+ super(base)
28
29
  # Hack. Make rakefile point to invoker, so rdoc task is generated properly.
29
30
  rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
30
31
  Rake.application.instance_variable_set(:@rakefile, rakefile)
data/lib/thor/runner.rb CHANGED
@@ -1,14 +1,13 @@
1
- require "thor"
2
- require "thor/group"
3
- require "thor/core_ext/io_binary_read"
1
+ require_relative "../thor"
2
+ require_relative "group"
4
3
 
5
- require "fileutils"
6
- require "open-uri"
7
4
  require "yaml"
8
5
  require "digest/md5"
9
6
  require "pathname"
10
7
 
11
8
  class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
9
+ autoload :OpenURI, "open-uri"
10
+
12
11
  map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
13
12
 
14
13
  def self.banner(command, all = false, subcommand = false)
@@ -104,6 +103,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
104
103
  if package == :file
105
104
  File.open(destination, "w") { |f| f.puts contents }
106
105
  else
106
+ require "fileutils"
107
107
  FileUtils.cp_r(name, destination)
108
108
  end
109
109
 
@@ -112,7 +112,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
112
112
 
113
113
  desc "version", "Show Thor version"
114
114
  def version
115
- require "thor/version"
115
+ require_relative "version"
116
116
  say "Thor #{Thor::VERSION}"
117
117
  end
118
118
 
@@ -120,6 +120,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
120
120
  def uninstall(name)
121
121
  raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
122
122
  say "Uninstalling #{name}."
123
+ require "fileutils"
123
124
  FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s))
124
125
 
125
126
  thor_yaml.delete(name)
@@ -138,6 +139,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
138
139
  self.options = options.merge("as" => name)
139
140
 
140
141
  if File.directory? File.expand_path(name)
142
+ require "fileutils"
141
143
  FileUtils.rm_rf(File.join(thor_root, old_filename))
142
144
 
143
145
  thor_yaml.delete(old_filename)
@@ -194,6 +196,7 @@ private
194
196
  yaml_file = File.join(thor_root, "thor.yml")
195
197
 
196
198
  unless File.exist?(yaml_file)
199
+ require "fileutils"
197
200
  FileUtils.mkdir_p(thor_root)
198
201
  yaml_file = File.join(thor_root, "thor.yml")
199
202
  FileUtils.touch(yaml_file)
@@ -1,9 +1,8 @@
1
- require "tempfile"
2
- require "io/console" if RUBY_VERSION > "1.9.2"
3
-
4
1
  class Thor
5
2
  module Shell
6
3
  class Basic
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
7
6
  attr_accessor :base
8
7
  attr_reader :padding
9
8
 
@@ -48,6 +47,10 @@ class Thor
48
47
 
49
48
  # Asks something to the user and receives a response.
50
49
  #
50
+ # If a default value is specified it will be presented to the user
51
+ # and allows them to select that value with an empty response. This
52
+ # option is ignored when limited answers are supplied.
53
+ #
51
54
  # If asked to limit the correct responses, you can pass in an
52
55
  # array of acceptable answers. If one of those is not supplied,
53
56
  # they will be shown a message stating that one of those answers
@@ -64,6 +67,8 @@ class Thor
64
67
  # ==== Example
65
68
  # ask("What is your name?")
66
69
  #
70
+ # ask("What is the planet furthest from the sun?", :default => "Pluto")
71
+ #
67
72
  # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
68
73
  #
69
74
  # ask("What is your password?", :echo => false)
@@ -89,6 +94,8 @@ class Thor
89
94
  # say("I know you knew that.")
90
95
  #
91
96
  def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
97
+ return if quiet?
98
+
92
99
  buffer = prepare_message(message, *color)
93
100
  buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
94
101
 
@@ -96,6 +103,23 @@ class Thor
96
103
  stdout.flush
97
104
  end
98
105
 
106
+ # Say (print) an error to the user. If the sentence ends with a whitespace
107
+ # or tab character, a new line is not appended (print + flush). Otherwise
108
+ # are passed straight to puts (behavior got from Highline).
109
+ #
110
+ # ==== Example
111
+ # say_error("error: something went wrong")
112
+ #
113
+ def say_error(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
114
+ return if quiet?
115
+
116
+ buffer = prepare_message(message, *color)
117
+ buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
118
+
119
+ stderr.print(buffer)
120
+ stderr.flush
121
+ end
122
+
99
123
  # Say a status with the given color and appends the message. Since this
100
124
  # method is used frequently by actions, it allows nil or false to be given
101
125
  # in log_status, avoiding the message from being shown. If a Symbol is
@@ -104,13 +128,14 @@ class Thor
104
128
  def say_status(status, message, log_status = true)
105
129
  return if quiet? || log_status == false
106
130
  spaces = " " * (padding + 1)
107
- color = log_status.is_a?(Symbol) ? log_status : :green
108
-
109
131
  status = status.to_s.rjust(12)
132
+ margin = " " * status.length + spaces
133
+
134
+ color = log_status.is_a?(Symbol) ? log_status : :green
110
135
  status = set_color status, color, true if color
111
136
 
112
- buffer = "#{status}#{spaces}#{message}"
113
- buffer << "\n" unless buffer.end_with?("\n")
137
+ message = message.to_s.chomp.gsub(/(?<!\A)^/, margin)
138
+ buffer = "#{status}#{spaces}#{message}\n"
114
139
 
115
140
  stdout.print(buffer)
116
141
  stdout.flush
@@ -165,7 +190,7 @@ class Thor
165
190
  colwidth = options[:colwidth]
166
191
  options[:truncate] = terminal_width if options[:truncate] == true
167
192
 
168
- formats << "%-#{colwidth + 2}s" if colwidth
193
+ formats << "%-#{colwidth + 2}s".dup if colwidth
169
194
  start = colwidth ? 1 : 0
170
195
 
171
196
  colcount = array.max { |a, b| a.size <=> b.size }.size
@@ -177,9 +202,9 @@ class Thor
177
202
  maximas << maxima
178
203
  formats << if index == colcount - 1
179
204
  # Don't output 2 trailing spaces when printing the last column
180
- "%-s"
205
+ "%-s".dup
181
206
  else
182
- "%-#{maxima + 2}s"
207
+ "%-#{maxima + 2}s".dup
183
208
  end
184
209
  end
185
210
 
@@ -187,7 +212,7 @@ class Thor
187
212
  formats << "%s"
188
213
 
189
214
  array.each do |row|
190
- sentence = ""
215
+ sentence = "".dup
191
216
 
192
217
  row.each_with_index do |column, index|
193
218
  maxima = maximas[index]
@@ -225,8 +250,21 @@ class Thor
225
250
  paras = message.split("\n\n")
226
251
 
227
252
  paras.map! do |unwrapped|
228
- unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
229
- end
253
+ words = unwrapped.split(" ")
254
+ counter = words.first.length
255
+ words.inject do |memo, word|
256
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
257
+ counter = 0 if word.include? "\n"
258
+ if (counter + word.length + 1) < width
259
+ memo = "#{memo} #{word}"
260
+ counter += (word.length + 1)
261
+ else
262
+ memo = "#{memo}\n#{word}"
263
+ counter = word.length
264
+ end
265
+ memo
266
+ end
267
+ end.compact!
230
268
 
231
269
  paras.each do |para|
232
270
  para.split("\n").each do |line|
@@ -242,11 +280,11 @@ class Thor
242
280
  #
243
281
  # ==== Parameters
244
282
  # destination<String>:: the destination file to solve conflicts
245
- # block<Proc>:: an optional block that returns the value to be used in diff
283
+ # block<Proc>:: an optional block that returns the value to be used in diff and merge
246
284
  #
247
285
  def file_collision(destination)
248
286
  return true if @always_force
249
- options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
287
+ options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]"
250
288
 
251
289
  loop do
252
290
  answer = ask(
@@ -255,6 +293,9 @@ class Thor
255
293
  )
256
294
 
257
295
  case answer
296
+ when nil
297
+ say ""
298
+ return true
258
299
  when is?(:yes), is?(:force), ""
259
300
  return true
260
301
  when is?(:no), is?(:skip)
@@ -267,6 +308,13 @@ class Thor
267
308
  when is?(:diff)
268
309
  show_diff(destination, yield) if block_given?
269
310
  say "Retrying..."
311
+ when is?(:merge)
312
+ if block_given? && !merge_tool.empty?
313
+ merge(destination, yield)
314
+ return nil
315
+ end
316
+
317
+ say "Please specify merge tool to `THOR_MERGE` env."
270
318
  else
271
319
  say file_collision_help
272
320
  end
@@ -279,11 +327,11 @@ class Thor
279
327
  result = if ENV["THOR_COLUMNS"]
280
328
  ENV["THOR_COLUMNS"].to_i
281
329
  else
282
- unix? ? dynamic_width : 80
330
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
283
331
  end
284
- result < 10 ? 80 : result
332
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
285
333
  rescue
286
- 80
334
+ DEFAULT_TERMINAL_WIDTH
287
335
  end
288
336
 
289
337
  # Called if something goes wrong during the execution. This is used by Thor
@@ -344,12 +392,14 @@ class Thor
344
392
  q - quit, abort
345
393
  d - diff, show the differences between the old and the new
346
394
  h - help, show this help
395
+ m - merge, run merge tool
347
396
  HELP
348
397
  end
349
398
 
350
399
  def show_diff(destination, content) #:nodoc:
351
400
  diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
352
401
 
402
+ require "tempfile"
353
403
  Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
354
404
  temp.write content
355
405
  temp.rewind
@@ -411,7 +461,7 @@ class Thor
411
461
 
412
462
  return unless result
413
463
 
414
- result.strip!
464
+ result = result.strip
415
465
 
416
466
  if default && result == ""
417
467
  default
@@ -422,15 +472,41 @@ class Thor
422
472
 
423
473
  def ask_filtered(statement, color, options)
424
474
  answer_set = options[:limited_to]
475
+ case_insensitive = options.fetch(:case_insensitive, false)
425
476
  correct_answer = nil
426
477
  until correct_answer
427
478
  answers = answer_set.join(", ")
428
479
  answer = ask_simply("#{statement} [#{answers}]", color, options)
429
- correct_answer = answer_set.include?(answer) ? answer : nil
480
+ correct_answer = answer_match(answer_set, answer, case_insensitive)
430
481
  say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
431
482
  end
432
483
  correct_answer
433
484
  end
485
+
486
+ def answer_match(possibilities, answer, case_insensitive)
487
+ if case_insensitive
488
+ possibilities.detect{ |possibility| possibility.downcase == answer.downcase }
489
+ else
490
+ possibilities.detect{ |possibility| possibility == answer }
491
+ end
492
+ end
493
+
494
+ def merge(destination, content) #:nodoc:
495
+ require "tempfile"
496
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
497
+ temp.write content
498
+ temp.rewind
499
+ system %(#{merge_tool} "#{temp.path}" "#{destination}")
500
+ end
501
+ end
502
+
503
+ def merge_tool #:nodoc:
504
+ @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
505
+ end
506
+
507
+ def git_merge_tool #:nodoc:
508
+ `git config merge.tool`.rstrip rescue ""
509
+ end
434
510
  end
435
511
  end
436
512
  end
@@ -1,4 +1,4 @@
1
- require "thor/shell/basic"
1
+ require_relative "basic"
2
2
 
3
3
  class Thor
4
4
  module Shell
@@ -97,7 +97,15 @@ class Thor
97
97
  protected
98
98
 
99
99
  def can_display_colors?
100
- stdout.tty?
100
+ are_colors_supported? && !are_colors_disabled?
101
+ end
102
+
103
+ def are_colors_supported?
104
+ stdout.tty? && ENV["TERM"] != "dumb"
105
+ end
106
+
107
+ def are_colors_disabled?
108
+ !ENV['NO_COLOR'].nil?
101
109
  end
102
110
 
103
111
  # Overwrite show_diff to show diff with colors if Diff::LCS is
@@ -1,4 +1,4 @@
1
- require "thor/shell/basic"
1
+ require_relative "basic"
2
2
 
3
3
  class Thor
4
4
  module Shell
@@ -51,13 +51,13 @@ class Thor
51
51
  def set_color(string, *colors)
52
52
  if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
53
53
  html_colors = colors.map { |color| lookup_color(color) }
54
- "<span style=\"#{html_colors.join('; ')};\">#{string}</span>"
54
+ "<span style=\"#{html_colors.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
55
55
  else
56
56
  color, bold = colors
57
57
  html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
58
58
  styles = [html_color]
59
59
  styles << BOLD if bold
60
- "<span style=\"#{styles.join('; ')};\">#{string}</span>"
60
+ "<span style=\"#{styles.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
61
61
  end
62
62
  end
63
63
 
data/lib/thor/shell.rb CHANGED
@@ -21,12 +21,12 @@ class Thor
21
21
  end
22
22
 
23
23
  module Shell
24
- SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
24
+ SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_error, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
25
25
  attr_writer :shell
26
26
 
27
- autoload :Basic, "thor/shell/basic"
28
- autoload :Color, "thor/shell/color"
29
- autoload :HTML, "thor/shell/html"
27
+ autoload :Basic, File.expand_path("shell/basic", __dir__)
28
+ autoload :Color, File.expand_path("shell/color", __dir__)
29
+ autoload :HTML, File.expand_path("shell/html", __dir__)
30
30
 
31
31
  # Add shell to initialize config values.
32
32
  #
@@ -55,7 +55,7 @@ class Thor
55
55
 
56
56
  # Common methods that are delegated to the shell.
57
57
  SHELL_DELEGATED_METHODS.each do |method|
58
- module_eval <<-METHOD, __FILE__, __LINE__
58
+ module_eval <<-METHOD, __FILE__, __LINE__ + 1
59
59
  def #{method}(*args,&block)
60
60
  shell.#{method}(*args,&block)
61
61
  end
data/lib/thor/util.rb CHANGED
@@ -27,7 +27,7 @@ class Thor
27
27
  end
28
28
 
29
29
  # Receives a constant and converts it to a Thor namespace. Since Thor
30
- # commands can be added to a sandbox, this method is also responsable for
30
+ # commands can be added to a sandbox, this method is also responsible for
31
31
  # removing the sandbox namespace.
32
32
  #
33
33
  # This method should not be used in general because it's used to deal with
@@ -211,7 +211,7 @@ class Thor
211
211
  #
212
212
  def globs_for(path)
213
213
  path = escape_globs(path)
214
- ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
214
+ ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/**/*.thor"]
215
215
  end
216
216
 
217
217
  # Return the path to the ruby interpreter taking into account multiple
@@ -263,6 +263,22 @@ class Thor
263
263
  def escape_globs(path)
264
264
  path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
265
265
  end
266
+
267
+ # Returns a string that has had any HTML characters escaped.
268
+ #
269
+ # ==== Examples
270
+ #
271
+ # Thor::Util.escape_html('<div>') # => "&lt;div&gt;"
272
+ #
273
+ # ==== Parameters
274
+ # String
275
+ #
276
+ # ==== Returns
277
+ # String
278
+ #
279
+ def escape_html(string)
280
+ CGI.escapeHTML(string)
281
+ end
266
282
  end
267
283
  end
268
284
  end
data/lib/thor/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "0.19.4"
2
+ VERSION = "1.2.1"
3
3
  end