thor 0.14.6 → 0.15.0
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/.autotest +8 -0
- data/.document +5 -0
- data/.gemtest +0 -0
- data/.gitignore +44 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.rdoc +4 -4
- data/Gemfile +19 -0
- data/{LICENSE → LICENSE.md} +2 -2
- data/README.md +21 -300
- data/Thorfile +21 -15
- data/lib/thor.rb +56 -11
- data/lib/thor/actions.rb +7 -3
- data/lib/thor/actions/create_link.rb +1 -1
- data/lib/thor/actions/directory.rb +7 -3
- data/lib/thor/actions/empty_directory.rb +24 -5
- data/lib/thor/actions/file_manipulation.rb +40 -2
- data/lib/thor/base.rb +66 -28
- data/lib/thor/error.rb +6 -1
- data/lib/thor/group.rb +20 -8
- data/lib/thor/invocation.rb +4 -2
- data/lib/thor/parser/arguments.rb +6 -2
- data/lib/thor/parser/option.rb +3 -2
- data/lib/thor/parser/options.rb +13 -8
- data/lib/thor/rake_compat.rb +13 -8
- data/lib/thor/runner.rb +16 -4
- data/lib/thor/shell.rb +2 -2
- data/lib/thor/shell/basic.rb +86 -29
- data/lib/thor/shell/color.rb +40 -4
- data/lib/thor/shell/html.rb +28 -26
- data/lib/thor/task.rb +26 -8
- data/lib/thor/util.rb +26 -7
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_link_spec.rb +81 -0
- data/spec/actions/empty_directory_spec.rb +32 -0
- data/spec/actions/file_manipulation_spec.rb +61 -1
- data/spec/actions_spec.rb +4 -0
- data/spec/base_spec.rb +10 -5
- data/spec/exit_condition_spec.rb +19 -0
- data/spec/fixtures/script.thor +8 -2
- data/spec/group_spec.rb +39 -1
- data/spec/parser/arguments_spec.rb +1 -0
- data/spec/parser/options_spec.rb +12 -2
- data/spec/rake_compat_spec.rb +11 -7
- data/spec/register_spec.rb +43 -0
- data/spec/runner_spec.rb +34 -3
- data/spec/shell/basic_spec.rb +50 -3
- data/spec/shell/color_spec.rb +46 -6
- data/spec/shell/html_spec.rb +10 -5
- data/spec/spec_helper.rb +4 -0
- data/spec/task_spec.rb +26 -16
- data/spec/thor_spec.rb +56 -3
- data/thor.gemspec +26 -0
- metadata +174 -117
data/lib/thor/error.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Thor
|
2
2
|
# Thor::Error is raised when it's caused by wrong usage of thor classes. Those
|
3
|
-
# errors have their backtrace
|
3
|
+
# errors have their backtrace suppressed and are nicely shown to the user.
|
4
4
|
#
|
5
5
|
# Errors that are caused by the developer, like declaring a method which
|
6
6
|
# overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
|
@@ -27,4 +27,9 @@ class Thor
|
|
27
27
|
|
28
28
|
class MalformattedArgumentError < InvocationError
|
29
29
|
end
|
30
|
+
|
31
|
+
# Raised when a user tries to call a private method encoded in templated filename.
|
32
|
+
#
|
33
|
+
class PrivateMethodEncodedError < Error
|
34
|
+
end
|
30
35
|
end
|
data/lib/thor/group.rb
CHANGED
@@ -104,7 +104,7 @@ class Thor::Group
|
|
104
104
|
#
|
105
105
|
# ==== Custom invocations
|
106
106
|
#
|
107
|
-
# You can also supply a block to customize how the option is
|
107
|
+
# You can also supply a block to customize how the option is going to be
|
108
108
|
# invoked. The block receives two parameters, an instance of the current
|
109
109
|
# class and the klass to be invoked.
|
110
110
|
#
|
@@ -187,9 +187,9 @@ class Thor::Group
|
|
187
187
|
human_name = value.respond_to?(:classify) ? value.classify : value
|
188
188
|
|
189
189
|
group_options[human_name] ||= []
|
190
|
-
group_options[human_name] += klass.class_options.values.select do |
|
191
|
-
base_options[
|
192
|
-
!group_options.values.flatten.any? { |i| i.name ==
|
190
|
+
group_options[human_name] += klass.class_options.values.select do |class_option|
|
191
|
+
base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
|
192
|
+
!group_options.values.flatten.any? { |i| i.name == class_option.name }
|
193
193
|
end
|
194
194
|
|
195
195
|
yield klass if block_given?
|
@@ -204,8 +204,16 @@ class Thor::Group
|
|
204
204
|
[item]
|
205
205
|
end
|
206
206
|
|
207
|
-
def handle_argument_error(task, error) #:nodoc:
|
208
|
-
|
207
|
+
def handle_argument_error(task, error, arity=nil) #:nodoc:
|
208
|
+
if arity > 0
|
209
|
+
msg = "#{basename} #{task.name} takes #{arity} argument"
|
210
|
+
msg << "s" if arity > 1
|
211
|
+
msg << ", but it should not."
|
212
|
+
else
|
213
|
+
msg = "You should not pass arguments to #{basename} #{task.name}."
|
214
|
+
end
|
215
|
+
|
216
|
+
raise error, msg
|
209
217
|
end
|
210
218
|
|
211
219
|
protected
|
@@ -220,10 +228,14 @@ class Thor::Group
|
|
220
228
|
args, opts = Thor::Options.split(given_args)
|
221
229
|
opts = given_opts || opts
|
222
230
|
|
231
|
+
instance = new(args, opts, config)
|
232
|
+
yield instance if block_given?
|
233
|
+
args = instance.args
|
234
|
+
|
223
235
|
if task
|
224
|
-
|
236
|
+
instance.invoke_task(all_tasks[task])
|
225
237
|
else
|
226
|
-
|
238
|
+
instance.invoke_all
|
227
239
|
end
|
228
240
|
end
|
229
241
|
|
data/lib/thor/invocation.rb
CHANGED
@@ -85,7 +85,7 @@ class Thor
|
|
85
85
|
# that it's going to use.
|
86
86
|
#
|
87
87
|
# If you want Rspec::RR to be initialized with its own set of options, you
|
88
|
-
# have to do that
|
88
|
+
# have to do that explicitly:
|
89
89
|
#
|
90
90
|
# invoke "rspec:rr", [], :style => :foo
|
91
91
|
#
|
@@ -106,7 +106,9 @@ class Thor
|
|
106
106
|
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
107
107
|
|
108
108
|
args, opts, config = _parse_initialization_options(args, opts, config)
|
109
|
-
klass.send(:dispatch, task, args, opts, config)
|
109
|
+
klass.send(:dispatch, task, args, opts, config) do |instance|
|
110
|
+
instance.parent_options = options
|
111
|
+
end
|
110
112
|
end
|
111
113
|
|
112
114
|
# Invoke the given task if the given args.
|
@@ -28,7 +28,7 @@ class Thor
|
|
28
28
|
@switches = arguments
|
29
29
|
|
30
30
|
arguments.each do |argument|
|
31
|
-
if argument.default
|
31
|
+
if argument.default != nil
|
32
32
|
@assigns[argument.human_name] = argument.default
|
33
33
|
elsif argument.required?
|
34
34
|
@non_assigned_required << argument
|
@@ -49,6 +49,10 @@ class Thor
|
|
49
49
|
@assigns
|
50
50
|
end
|
51
51
|
|
52
|
+
def remaining
|
53
|
+
@pile
|
54
|
+
end
|
55
|
+
|
52
56
|
private
|
53
57
|
|
54
58
|
def no_or_skip?(arg)
|
@@ -94,7 +98,7 @@ class Thor
|
|
94
98
|
hash = {}
|
95
99
|
|
96
100
|
while current_is_value? && peek.include?(?:)
|
97
|
-
key, value = shift.split(':')
|
101
|
+
key, value = shift.split(':',2)
|
98
102
|
hash[key] = value
|
99
103
|
end
|
100
104
|
hash
|
data/lib/thor/parser/option.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
class Thor
|
2
2
|
class Option < Argument #:nodoc:
|
3
|
-
attr_reader :aliases, :group, :lazy_default
|
3
|
+
attr_reader :aliases, :group, :lazy_default, :hide
|
4
4
|
|
5
5
|
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
6
6
|
|
7
|
-
def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil)
|
7
|
+
def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil, hide=nil)
|
8
8
|
super(name, description, required, type, default, banner)
|
9
9
|
@lazy_default = lazy_default
|
10
10
|
@group = group.to_s.capitalize if group
|
11
11
|
@aliases = [*aliases].compact
|
12
|
+
@hide = hide
|
12
13
|
end
|
13
14
|
|
14
15
|
# This parse quick options given as method_options. It makes several
|
data/lib/thor/parser/options.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
1
|
class Thor
|
2
|
-
# This is a modified version of Daniel Berger's Getopt::Long class, licensed
|
3
|
-
# under Ruby's license.
|
4
|
-
#
|
5
2
|
class Options < Arguments #:nodoc:
|
6
3
|
LONG_RE = /^(--\w+(?:-\w+)*)$/
|
7
4
|
SHORT_RE = /^(-[a-z])$/i
|
@@ -38,7 +35,7 @@ class Thor
|
|
38
35
|
@non_assigned_required.delete(hash_options[key])
|
39
36
|
end
|
40
37
|
|
41
|
-
@shorts, @switches, @
|
38
|
+
@shorts, @switches, @extra = {}, {}, []
|
42
39
|
|
43
40
|
options.each do |option|
|
44
41
|
@switches[option.switch_name] = option
|
@@ -49,14 +46,19 @@ class Thor
|
|
49
46
|
end
|
50
47
|
end
|
51
48
|
|
49
|
+
def remaining
|
50
|
+
@extra
|
51
|
+
end
|
52
|
+
|
52
53
|
def parse(args)
|
53
54
|
@pile = args.dup
|
54
55
|
|
55
56
|
while peek
|
56
57
|
match, is_switch = current_is_switch?
|
58
|
+
shifted = shift
|
57
59
|
|
58
60
|
if is_switch
|
59
|
-
case
|
61
|
+
case shifted
|
60
62
|
when SHORT_SQ_RE
|
61
63
|
unshift($1.split('').map { |f| "-#{f}" })
|
62
64
|
next
|
@@ -71,9 +73,10 @@ class Thor
|
|
71
73
|
option = switch_option(switch)
|
72
74
|
@assigns[option.human_name] = parse_peek(switch, option)
|
73
75
|
elsif match
|
74
|
-
@
|
76
|
+
@extra << shifted
|
77
|
+
@extra << shift while peek && peek !~ /^-/
|
75
78
|
else
|
76
|
-
|
79
|
+
@extra << shifted
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
@@ -85,7 +88,9 @@ class Thor
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def check_unknown!
|
88
|
-
|
91
|
+
# an unknown option starts with - or -- and has no more --'s afterward.
|
92
|
+
unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
|
93
|
+
raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
|
89
94
|
end
|
90
95
|
|
91
96
|
protected
|
data/lib/thor/rake_compat.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rake'
|
2
|
+
require 'rake/dsl_definition'
|
2
3
|
|
3
4
|
class Thor
|
4
5
|
# Adds a compatibility layer to your Thor classes which allows you to use
|
@@ -16,6 +17,8 @@ class Thor
|
|
16
17
|
# end
|
17
18
|
#
|
18
19
|
module RakeCompat
|
20
|
+
include Rake::DSL if defined?(Rake::DSL)
|
21
|
+
|
19
22
|
def self.rake_classes
|
20
23
|
@rake_classes ||= []
|
21
24
|
end
|
@@ -29,12 +32,12 @@ class Thor
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
alias
|
35
|
+
# override task on (main), for compatibility with Rake 0.9
|
36
|
+
self.instance_eval do
|
37
|
+
alias rake_namespace namespace
|
35
38
|
|
36
|
-
def task(*
|
37
|
-
task =
|
39
|
+
def task(*)
|
40
|
+
task = super
|
38
41
|
|
39
42
|
if klass = Thor::RakeCompat.rake_classes.last
|
40
43
|
non_namespaced_name = task.name.split(':').last
|
@@ -43,7 +46,8 @@ class Object #:nodoc:
|
|
43
46
|
description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ')
|
44
47
|
description.strip!
|
45
48
|
|
46
|
-
klass.desc description,
|
49
|
+
klass.desc description, Rake.application.last_description || non_namespaced_name
|
50
|
+
Rake.application.last_description = nil
|
47
51
|
klass.send :define_method, non_namespaced_name do |*args|
|
48
52
|
Rake::Task[task.name.to_sym].invoke(*args)
|
49
53
|
end
|
@@ -52,7 +56,7 @@ class Object #:nodoc:
|
|
52
56
|
task
|
53
57
|
end
|
54
58
|
|
55
|
-
def namespace(name
|
59
|
+
def namespace(name)
|
56
60
|
if klass = Thor::RakeCompat.rake_classes.last
|
57
61
|
const_name = Thor::Util.camel_case(name.to_s).to_sym
|
58
62
|
klass.const_set(const_name, Class.new(Thor))
|
@@ -60,7 +64,8 @@ class Object #:nodoc:
|
|
60
64
|
Thor::RakeCompat.rake_classes << new_klass
|
61
65
|
end
|
62
66
|
|
63
|
-
|
67
|
+
super
|
64
68
|
Thor::RakeCompat.rake_classes.pop
|
65
69
|
end
|
66
70
|
end
|
71
|
+
|
data/lib/thor/runner.rb
CHANGED
@@ -17,6 +17,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
17
17
|
if meth && !self.respond_to?(meth)
|
18
18
|
initialize_thorfiles(meth)
|
19
19
|
klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
|
20
|
+
self.class.handle_no_task_error(task, false) if klass.nil?
|
20
21
|
klass.start(["-h", task].compact, :shell => self.shell)
|
21
22
|
else
|
22
23
|
super
|
@@ -30,6 +31,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
30
31
|
meth = meth.to_s
|
31
32
|
initialize_thorfiles(meth)
|
32
33
|
klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
|
34
|
+
self.class.handle_no_task_error(task, false) if klass.nil?
|
33
35
|
args.unshift(task) if task
|
34
36
|
klass.start(args, :shell => self.shell)
|
35
37
|
end
|
@@ -73,7 +75,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
73
75
|
as = basename if as.empty?
|
74
76
|
end
|
75
77
|
|
76
|
-
location = if options[:relative] || name =~ /^
|
78
|
+
location = if options[:relative] || name =~ /^https?:\/\//
|
77
79
|
name
|
78
80
|
else
|
79
81
|
File.expand_path(name)
|
@@ -124,7 +126,17 @@ class Thor::Runner < Thor #:nodoc:
|
|
124
126
|
|
125
127
|
old_filename = thor_yaml[name][:filename]
|
126
128
|
self.options = self.options.merge("as" => name)
|
127
|
-
|
129
|
+
|
130
|
+
if File.directory? File.expand_path(name)
|
131
|
+
FileUtils.rm_rf(File.join(thor_root, old_filename))
|
132
|
+
|
133
|
+
thor_yaml.delete(old_filename)
|
134
|
+
save_yaml(thor_yaml)
|
135
|
+
|
136
|
+
filename = install(name)
|
137
|
+
else
|
138
|
+
filename = install(thor_yaml[name][:location])
|
139
|
+
end
|
128
140
|
|
129
141
|
unless filename == old_filename
|
130
142
|
File.delete(File.join(thor_root, old_filename))
|
@@ -190,7 +202,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
190
202
|
true
|
191
203
|
end
|
192
204
|
|
193
|
-
# Load the
|
205
|
+
# Load the Thorfiles. If relevant_to is supplied, looks for specific files
|
194
206
|
# in the thor_root instead of loading them all.
|
195
207
|
#
|
196
208
|
# By default, it also traverses the current path until find Thor files, as
|
@@ -244,7 +256,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
244
256
|
end
|
245
257
|
end
|
246
258
|
|
247
|
-
# Load
|
259
|
+
# Load Thorfiles relevant to the given method. If you provide "foo:bar" it
|
248
260
|
# will load all thor files in the thor.yaml that has "foo" e "foo:bar"
|
249
261
|
# namespaces registered.
|
250
262
|
#
|
data/lib/thor/shell.rb
CHANGED
@@ -8,7 +8,7 @@ class Thor
|
|
8
8
|
def self.shell
|
9
9
|
@shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0
|
10
10
|
Thor::Shell.const_get(ENV['THOR_SHELL'])
|
11
|
-
elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
11
|
+
elsif ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) && !(ENV['ANSICON']))
|
12
12
|
Thor::Shell::Basic
|
13
13
|
else
|
14
14
|
Thor::Shell::Color
|
@@ -23,7 +23,7 @@ class Thor
|
|
23
23
|
end
|
24
24
|
|
25
25
|
module Shell
|
26
|
-
SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table]
|
26
|
+
SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_table, :print_wrapped, :file_collision]
|
27
27
|
|
28
28
|
autoload :Basic, 'thor/shell/basic'
|
29
29
|
autoload :Color, 'thor/shell/color'
|
data/lib/thor/shell/basic.rb
CHANGED
@@ -5,10 +5,10 @@ class Thor
|
|
5
5
|
class Basic
|
6
6
|
attr_accessor :base, :padding
|
7
7
|
|
8
|
-
# Initialize base and padding to nil.
|
8
|
+
# Initialize base, mute and padding to nil.
|
9
9
|
#
|
10
10
|
def initialize #:nodoc:
|
11
|
-
@base, @padding = nil, 0
|
11
|
+
@base, @mute, @padding = nil, false, 0
|
12
12
|
end
|
13
13
|
|
14
14
|
# Mute everything that's inside given block
|
@@ -23,7 +23,7 @@ class Thor
|
|
23
23
|
# Check if base is muted
|
24
24
|
#
|
25
25
|
def mute?
|
26
|
-
@mute
|
26
|
+
@mute ||= false
|
27
27
|
end
|
28
28
|
|
29
29
|
# Sets the output padding, not allowing less than zero values.
|
@@ -32,14 +32,22 @@ class Thor
|
|
32
32
|
@padding = [0, value].max
|
33
33
|
end
|
34
34
|
|
35
|
-
#
|
35
|
+
# Asks something to the user and receives a response.
|
36
|
+
#
|
37
|
+
# If asked to limit the correct responses, you can pass in an
|
38
|
+
# array of acceptable answers. If one of those is not supplied,
|
39
|
+
# they will be shown a message stating that one of those answers
|
40
|
+
# must be given and re-asked the question.
|
36
41
|
#
|
37
42
|
# ==== Example
|
38
43
|
# ask("What is your name?")
|
39
44
|
#
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
46
|
+
#
|
47
|
+
def ask(statement, *args)
|
48
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
49
|
+
|
50
|
+
options[:limited_to] ? ask_filtered(statement, options[:limited_to], *args) : ask_simply(statement, *args)
|
43
51
|
end
|
44
52
|
|
45
53
|
# Say (print) something to the user. If the sentence ends with a whitespace
|
@@ -51,16 +59,17 @@ class Thor
|
|
51
59
|
#
|
52
60
|
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)$/))
|
53
61
|
message = message.to_s
|
54
|
-
|
62
|
+
|
63
|
+
message = set_color(message, *color) if color
|
55
64
|
|
56
65
|
spaces = " " * padding
|
57
66
|
|
58
67
|
if force_new_line
|
59
|
-
|
68
|
+
stdout.puts(spaces + message)
|
60
69
|
else
|
61
|
-
|
70
|
+
stdout.print(spaces + message)
|
62
71
|
end
|
63
|
-
|
72
|
+
stdout.flush
|
64
73
|
end
|
65
74
|
|
66
75
|
# Say a status with the given color and appends the message. Since this
|
@@ -76,8 +85,8 @@ class Thor
|
|
76
85
|
status = status.to_s.rjust(12)
|
77
86
|
status = set_color status, color, true if color
|
78
87
|
|
79
|
-
|
80
|
-
|
88
|
+
stdout.puts "#{status}#{spaces}#{message}"
|
89
|
+
stdout.flush
|
81
90
|
end
|
82
91
|
|
83
92
|
# Make a question the to user and returns true if the user replies "y" or
|
@@ -100,35 +109,47 @@ class Thor
|
|
100
109
|
# Array[Array[String, String, ...]]
|
101
110
|
#
|
102
111
|
# ==== Options
|
103
|
-
#
|
112
|
+
# indent<Integer>:: Indent the first column by indent value.
|
104
113
|
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
105
114
|
#
|
106
115
|
def print_table(table, options={})
|
107
116
|
return if table.empty?
|
108
117
|
|
109
|
-
formats,
|
118
|
+
formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth]
|
110
119
|
options[:truncate] = terminal_width if options[:truncate] == true
|
111
120
|
|
112
121
|
formats << "%-#{colwidth + 2}s" if colwidth
|
113
122
|
start = colwidth ? 1 : 0
|
114
123
|
|
115
|
-
|
116
|
-
|
124
|
+
colcount = table.max{|a,b| a.size <=> b.size }.size
|
125
|
+
|
126
|
+
maximas = []
|
127
|
+
|
128
|
+
start.upto(colcount - 2) do |i|
|
129
|
+
maxima = table.map {|row| row[i] ? row[i].to_s.size : 0 }.max
|
130
|
+
maximas << maxima
|
117
131
|
formats << "%-#{maxima + 2}s"
|
118
132
|
end
|
119
133
|
|
120
|
-
formats[0] = formats[0].insert(0, " " *
|
134
|
+
formats[0] = formats[0].insert(0, " " * indent)
|
121
135
|
formats << "%s"
|
122
136
|
|
123
137
|
table.each do |row|
|
124
138
|
sentence = ""
|
125
139
|
|
126
140
|
row.each_with_index do |column, i|
|
127
|
-
|
141
|
+
maxima = maximas[i]
|
142
|
+
|
143
|
+
if column.is_a?(Numeric)
|
144
|
+
f = "%#{maxima}s "
|
145
|
+
else
|
146
|
+
f = formats[i]
|
147
|
+
end
|
148
|
+
sentence << f % column.to_s
|
128
149
|
end
|
129
150
|
|
130
151
|
sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
131
|
-
|
152
|
+
stdout.puts sentence
|
132
153
|
end
|
133
154
|
end
|
134
155
|
|
@@ -139,11 +160,11 @@ class Thor
|
|
139
160
|
# String
|
140
161
|
#
|
141
162
|
# ==== Options
|
142
|
-
#
|
163
|
+
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
|
143
164
|
#
|
144
165
|
def print_wrapped(message, options={})
|
145
|
-
|
146
|
-
width = terminal_width -
|
166
|
+
indent = options[:indent] || 0
|
167
|
+
width = terminal_width - indent
|
147
168
|
paras = message.split("\n\n")
|
148
169
|
|
149
170
|
paras.map! do |unwrapped|
|
@@ -154,14 +175,14 @@ class Thor
|
|
154
175
|
|
155
176
|
paras.each do |para|
|
156
177
|
para.split("\n").each do |line|
|
157
|
-
|
178
|
+
stdout.puts line.insert(0, " " * indent)
|
158
179
|
end
|
159
|
-
|
180
|
+
stdout.puts unless para == paras.last
|
160
181
|
end
|
161
182
|
end
|
162
183
|
|
163
184
|
# Deals with file collision and returns true if the file should be
|
164
|
-
#
|
185
|
+
# overwritten and false otherwise. If a block is given, it uses the block
|
165
186
|
# response as the content for the diff.
|
166
187
|
#
|
167
188
|
# ==== Parameters
|
@@ -195,23 +216,40 @@ class Thor
|
|
195
216
|
end
|
196
217
|
|
197
218
|
# Called if something goes wrong during the execution. This is used by Thor
|
198
|
-
# internally and should not be used inside your scripts. If
|
219
|
+
# internally and should not be used inside your scripts. If something went
|
199
220
|
# wrong, you can always raise an exception. If you raise a Thor::Error, it
|
200
221
|
# will be rescued and wrapped in the method below.
|
201
222
|
#
|
202
223
|
def error(statement)
|
203
|
-
|
224
|
+
stderr.puts statement
|
204
225
|
end
|
205
226
|
|
206
227
|
# Apply color to the given string with optional bold. Disabled in the
|
207
228
|
# Thor::Shell::Basic class.
|
208
229
|
#
|
209
|
-
def set_color(string,
|
230
|
+
def set_color(string, *args) #:nodoc:
|
210
231
|
string
|
211
232
|
end
|
212
233
|
|
213
234
|
protected
|
214
235
|
|
236
|
+
def lookup_color(color)
|
237
|
+
return color unless color.is_a?(Symbol)
|
238
|
+
self.class.const_get(color.to_s.upcase)
|
239
|
+
end
|
240
|
+
|
241
|
+
def stdout
|
242
|
+
$stdout
|
243
|
+
end
|
244
|
+
|
245
|
+
def stdin
|
246
|
+
$stdin
|
247
|
+
end
|
248
|
+
|
249
|
+
def stderr
|
250
|
+
$stderr
|
251
|
+
end
|
252
|
+
|
215
253
|
def is?(value) #:nodoc:
|
216
254
|
value = value.to_s
|
217
255
|
|
@@ -285,6 +323,25 @@ HELP
|
|
285
323
|
end
|
286
324
|
end
|
287
325
|
|
326
|
+
def ask_simply(statement, color = nil)
|
327
|
+
say("#{statement} ", color)
|
328
|
+
stdin.gets.strip
|
329
|
+
end
|
330
|
+
|
331
|
+
def ask_filtered(statement, answer_set, *args)
|
332
|
+
correct_answer = nil
|
333
|
+
|
334
|
+
until correct_answer
|
335
|
+
answer = ask_simply("#{statement} #{answer_set.inspect}", *args)
|
336
|
+
|
337
|
+
correct_answer = answer_set.include?(answer) ? answer : nil
|
338
|
+
|
339
|
+
answers = answer_set.map(&:inspect).join(", ")
|
340
|
+
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
341
|
+
end
|
342
|
+
|
343
|
+
correct_answer
|
344
|
+
end
|
288
345
|
end
|
289
346
|
end
|
290
347
|
end
|