bundler 1.2.0.pre.1 → 1.2.0.rc
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- data/CHANGELOG.md +27 -1
- data/ISSUES.md +3 -3
- data/lib/bundler.rb +7 -5
- data/lib/bundler/cli.rb +17 -20
- data/lib/bundler/definition.rb +5 -0
- data/lib/bundler/dsl.rb +1 -1
- data/lib/bundler/fetcher.rb +5 -6
- data/lib/bundler/gem_path_manipulation.rb +8 -0
- data/lib/bundler/ruby_version.rb +4 -2
- data/lib/bundler/runtime.rb +46 -19
- data/lib/bundler/source.rb +25 -10
- data/lib/bundler/templates/newgem/{LICENSE.tt → LICENSE.txt.tt} +0 -0
- data/lib/bundler/templates/newgem/Rakefile.tt +0 -1
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +6 -4
- data/lib/bundler/vendor/thor.rb +49 -28
- data/lib/bundler/vendor/thor/actions.rb +7 -3
- data/lib/bundler/vendor/thor/actions/create_link.rb +1 -1
- data/lib/bundler/vendor/thor/actions/directory.rb +9 -4
- data/lib/bundler/vendor/thor/actions/empty_directory.rb +24 -5
- data/lib/bundler/vendor/thor/actions/file_manipulation.rb +39 -1
- data/lib/bundler/vendor/thor/base.rb +65 -24
- data/lib/bundler/vendor/thor/core_ext/dir_escape.rb +0 -0
- data/lib/bundler/vendor/thor/error.rb +6 -1
- data/lib/bundler/vendor/thor/group.rb +21 -9
- data/lib/bundler/vendor/thor/invocation.rb +4 -2
- data/lib/bundler/vendor/thor/parser/arguments.rb +4 -0
- data/lib/bundler/vendor/thor/parser/option.rb +3 -2
- data/lib/bundler/vendor/thor/parser/options.rb +13 -7
- data/lib/bundler/vendor/thor/rake_compat.rb +13 -8
- data/lib/bundler/vendor/thor/runner.rb +15 -3
- data/lib/bundler/vendor/thor/shell.rb +4 -4
- data/lib/bundler/vendor/thor/shell/basic.rb +169 -82
- data/lib/bundler/vendor/thor/shell/color.rb +40 -4
- data/lib/bundler/vendor/thor/shell/html.rb +28 -26
- data/lib/bundler/vendor/thor/task.rb +24 -5
- data/lib/bundler/vendor/thor/util.rb +43 -6
- data/lib/bundler/vendor/thor/version.rb +1 -1
- data/lib/bundler/version.rb +1 -1
- data/man/bundle-config.ronn +2 -2
- data/spec/bundler/definition_spec.rb +25 -0
- data/spec/cache/git_spec.rb +47 -0
- data/spec/cache/path_spec.rb +18 -0
- data/spec/install/git_spec.rb +21 -6
- data/spec/lock/lockfile_spec.rb +1 -1
- data/spec/other/check_spec.rb +14 -1
- data/spec/other/newgem_spec.rb +1 -0
- data/spec/other/platform_spec.rb +164 -0
- data/spec/runtime/setup_spec.rb +87 -0
- data/spec/runtime/with_clean_env_spec.rb +14 -0
- metadata +78 -133
File without changes
|
@@ -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
|
@@ -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
|
#
|
@@ -180,16 +180,16 @@ class Thor::Group
|
|
180
180
|
end
|
181
181
|
next unless value
|
182
182
|
|
183
|
-
klass,
|
183
|
+
klass, _ = prepare_for_invocation(name, value)
|
184
184
|
next unless klass && klass.respond_to?(:class_options)
|
185
185
|
|
186
186
|
value = value.to_s
|
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
|
|
@@ -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.
|
@@ -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
|
@@ -35,7 +35,7 @@ class Thor
|
|
35
35
|
@non_assigned_required.delete(hash_options[key])
|
36
36
|
end
|
37
37
|
|
38
|
-
@shorts, @switches, @
|
38
|
+
@shorts, @switches, @extra = {}, {}, []
|
39
39
|
|
40
40
|
options.each do |option|
|
41
41
|
@switches[option.switch_name] = option
|
@@ -46,14 +46,19 @@ class Thor
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
def remaining
|
50
|
+
@extra
|
51
|
+
end
|
52
|
+
|
49
53
|
def parse(args)
|
50
54
|
@pile = args.dup
|
51
55
|
|
52
56
|
while peek
|
53
57
|
match, is_switch = current_is_switch?
|
58
|
+
shifted = shift
|
54
59
|
|
55
60
|
if is_switch
|
56
|
-
case
|
61
|
+
case shifted
|
57
62
|
when SHORT_SQ_RE
|
58
63
|
unshift($1.split('').map { |f| "-#{f}" })
|
59
64
|
next
|
@@ -68,9 +73,10 @@ class Thor
|
|
68
73
|
option = switch_option(switch)
|
69
74
|
@assigns[option.human_name] = parse_peek(switch, option)
|
70
75
|
elsif match
|
71
|
-
@
|
76
|
+
@extra << shifted
|
77
|
+
@extra << shift while peek && peek !~ /^-/
|
72
78
|
else
|
73
|
-
|
79
|
+
@extra << shifted
|
74
80
|
end
|
75
81
|
end
|
76
82
|
|
@@ -82,9 +88,9 @@ class Thor
|
|
82
88
|
end
|
83
89
|
|
84
90
|
def check_unknown!
|
85
|
-
|
86
|
-
|
87
|
-
|
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?
|
88
94
|
end
|
89
95
|
|
90
96
|
protected
|
@@ -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
|
+
|
@@ -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
|
@@ -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
|
#
|
@@ -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_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
|
27
27
|
|
28
28
|
autoload :Basic, 'thor/shell/basic'
|
29
29
|
autoload :Color, 'thor/shell/color'
|
@@ -62,8 +62,8 @@ class Thor
|
|
62
62
|
# Common methods that are delegated to the shell.
|
63
63
|
SHELL_DELEGATED_METHODS.each do |method|
|
64
64
|
module_eval <<-METHOD, __FILE__, __LINE__
|
65
|
-
def #{method}(*args)
|
66
|
-
shell.#{method}(*args)
|
65
|
+
def #{method}(*args,&block)
|
66
|
+
shell.#{method}(*args,&block)
|
67
67
|
end
|
68
68
|
METHOD
|
69
69
|
end
|
@@ -3,12 +3,13 @@ require 'tempfile'
|
|
3
3
|
class Thor
|
4
4
|
module Shell
|
5
5
|
class Basic
|
6
|
-
attr_accessor :base
|
6
|
+
attr_accessor :base
|
7
|
+
attr_reader :padding
|
7
8
|
|
8
|
-
# Initialize base and padding to nil.
|
9
|
+
# Initialize base, mute and padding to nil.
|
9
10
|
#
|
10
11
|
def initialize #:nodoc:
|
11
|
-
@base, @padding = nil, 0
|
12
|
+
@base, @mute, @padding = nil, false, 0
|
12
13
|
end
|
13
14
|
|
14
15
|
# Mute everything that's inside given block
|
@@ -32,14 +33,22 @@ class Thor
|
|
32
33
|
@padding = [0, value].max
|
33
34
|
end
|
34
35
|
|
35
|
-
#
|
36
|
+
# Asks something to the user and receives a response.
|
37
|
+
#
|
38
|
+
# If asked to limit the correct responses, you can pass in an
|
39
|
+
# array of acceptable answers. If one of those is not supplied,
|
40
|
+
# they will be shown a message stating that one of those answers
|
41
|
+
# must be given and re-asked the question.
|
36
42
|
#
|
37
43
|
# ==== Example
|
38
44
|
# ask("What is your name?")
|
39
45
|
#
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
47
|
+
#
|
48
|
+
def ask(statement, *args)
|
49
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
50
|
+
|
51
|
+
options[:limited_to] ? ask_filtered(statement, options[:limited_to], *args) : ask_simply(statement, *args)
|
43
52
|
end
|
44
53
|
|
45
54
|
# Say (print) something to the user. If the sentence ends with a whitespace
|
@@ -51,7 +60,8 @@ class Thor
|
|
51
60
|
#
|
52
61
|
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)$/))
|
53
62
|
message = message.to_s
|
54
|
-
|
63
|
+
|
64
|
+
message = set_color(message, *color) if color
|
55
65
|
|
56
66
|
spaces = " " * padding
|
57
67
|
|
@@ -94,37 +104,77 @@ class Thor
|
|
94
104
|
!yes?(statement, color)
|
95
105
|
end
|
96
106
|
|
107
|
+
# Prints values in columns
|
108
|
+
#
|
109
|
+
# ==== Parameters
|
110
|
+
# Array[String, String, ...]
|
111
|
+
#
|
112
|
+
def print_in_columns(array)
|
113
|
+
return if array.empty?
|
114
|
+
colwidth = (array.map{|el| el.to_s.size}.max || 0) + 2
|
115
|
+
array.each_with_index do |value, index|
|
116
|
+
# Don't output trailing spaces when printing the last column
|
117
|
+
if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
|
118
|
+
stdout.puts value
|
119
|
+
else
|
120
|
+
stdout.printf("%-#{colwidth}s", value)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
97
125
|
# Prints a table.
|
98
126
|
#
|
99
127
|
# ==== Parameters
|
100
128
|
# Array[Array[String, String, ...]]
|
101
129
|
#
|
102
130
|
# ==== Options
|
103
|
-
#
|
131
|
+
# indent<Integer>:: Indent the first column by indent value.
|
104
132
|
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
105
133
|
#
|
106
|
-
def print_table(
|
107
|
-
return if
|
134
|
+
def print_table(array, options={})
|
135
|
+
return if array.empty?
|
108
136
|
|
109
|
-
formats,
|
137
|
+
formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth]
|
110
138
|
options[:truncate] = terminal_width if options[:truncate] == true
|
111
139
|
|
112
140
|
formats << "%-#{colwidth + 2}s" if colwidth
|
113
141
|
start = colwidth ? 1 : 0
|
114
142
|
|
115
|
-
|
116
|
-
|
117
|
-
|
143
|
+
colcount = array.max{|a,b| a.size <=> b.size }.size
|
144
|
+
|
145
|
+
maximas = []
|
146
|
+
|
147
|
+
start.upto(colcount - 1) do |index|
|
148
|
+
maxima = array.map {|row| row[index] ? row[index].to_s.size : 0 }.max
|
149
|
+
maximas << maxima
|
150
|
+
if index == colcount - 1
|
151
|
+
# Don't output 2 trailing spaces when printing the last column
|
152
|
+
formats << "%-s"
|
153
|
+
else
|
154
|
+
formats << "%-#{maxima + 2}s"
|
155
|
+
end
|
118
156
|
end
|
119
157
|
|
120
|
-
formats[0] = formats[0].insert(0, " " *
|
158
|
+
formats[0] = formats[0].insert(0, " " * indent)
|
121
159
|
formats << "%s"
|
122
160
|
|
123
|
-
|
161
|
+
array.each do |row|
|
124
162
|
sentence = ""
|
125
163
|
|
126
|
-
row.each_with_index do |column,
|
127
|
-
|
164
|
+
row.each_with_index do |column, index|
|
165
|
+
maxima = maximas[index]
|
166
|
+
|
167
|
+
if column.is_a?(Numeric)
|
168
|
+
if index == row.size - 1
|
169
|
+
# Don't output 2 trailing spaces when printing the last column
|
170
|
+
f = "%#{maxima}s"
|
171
|
+
else
|
172
|
+
f = "%#{maxima}s "
|
173
|
+
end
|
174
|
+
else
|
175
|
+
f = formats[index]
|
176
|
+
end
|
177
|
+
sentence << f % column.to_s
|
128
178
|
end
|
129
179
|
|
130
180
|
sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
@@ -139,11 +189,11 @@ class Thor
|
|
139
189
|
# String
|
140
190
|
#
|
141
191
|
# ==== Options
|
142
|
-
#
|
192
|
+
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
|
143
193
|
#
|
144
194
|
def print_wrapped(message, options={})
|
145
|
-
|
146
|
-
width = terminal_width -
|
195
|
+
indent = options[:indent] || 0
|
196
|
+
width = terminal_width - indent
|
147
197
|
paras = message.split("\n\n")
|
148
198
|
|
149
199
|
paras.map! do |unwrapped|
|
@@ -154,14 +204,14 @@ class Thor
|
|
154
204
|
|
155
205
|
paras.each do |para|
|
156
206
|
para.split("\n").each do |line|
|
157
|
-
stdout.puts line.insert(0, " " *
|
207
|
+
stdout.puts line.insert(0, " " * indent)
|
158
208
|
end
|
159
209
|
stdout.puts unless para == paras.last
|
160
210
|
end
|
161
211
|
end
|
162
212
|
|
163
213
|
# Deals with file collision and returns true if the file should be
|
164
|
-
#
|
214
|
+
# overwritten and false otherwise. If a block is given, it uses the block
|
165
215
|
# response as the content for the diff.
|
166
216
|
#
|
167
217
|
# ==== Parameters
|
@@ -194,6 +244,19 @@ class Thor
|
|
194
244
|
end
|
195
245
|
end
|
196
246
|
|
247
|
+
# This code was copied from Rake, available under MIT-LICENSE
|
248
|
+
# Copyright (c) 2003, 2004 Jim Weirich
|
249
|
+
def terminal_width
|
250
|
+
if ENV['THOR_COLUMNS']
|
251
|
+
result = ENV['THOR_COLUMNS'].to_i
|
252
|
+
else
|
253
|
+
result = unix? ? dynamic_width : 80
|
254
|
+
end
|
255
|
+
(result < 10) ? 80 : result
|
256
|
+
rescue
|
257
|
+
80
|
258
|
+
end
|
259
|
+
|
197
260
|
# Called if something goes wrong during the execution. This is used by Thor
|
198
261
|
# internally and should not be used inside your scripts. If something went
|
199
262
|
# wrong, you can always raise an exception. If you raise a Thor::Error, it
|
@@ -206,35 +269,40 @@ class Thor
|
|
206
269
|
# Apply color to the given string with optional bold. Disabled in the
|
207
270
|
# Thor::Shell::Basic class.
|
208
271
|
#
|
209
|
-
def set_color(string,
|
272
|
+
def set_color(string, *args) #:nodoc:
|
210
273
|
string
|
211
274
|
end
|
212
275
|
|
213
|
-
|
276
|
+
protected
|
214
277
|
|
215
|
-
|
216
|
-
|
217
|
-
|
278
|
+
def lookup_color(color)
|
279
|
+
return color unless color.is_a?(Symbol)
|
280
|
+
self.class.const_get(color.to_s.upcase)
|
281
|
+
end
|
218
282
|
|
219
|
-
|
220
|
-
|
221
|
-
|
283
|
+
def stdout
|
284
|
+
$stdout
|
285
|
+
end
|
222
286
|
|
223
|
-
|
224
|
-
|
225
|
-
|
287
|
+
def stdin
|
288
|
+
$stdin
|
289
|
+
end
|
290
|
+
|
291
|
+
def stderr
|
292
|
+
$stderr
|
293
|
+
end
|
226
294
|
|
227
|
-
|
228
|
-
|
295
|
+
def is?(value) #:nodoc:
|
296
|
+
value = value.to_s
|
229
297
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
end
|
298
|
+
if value.size == 1
|
299
|
+
/\A#{value}\z/i
|
300
|
+
else
|
301
|
+
/\A(#{value}|#{value[0,1]})\z/i
|
235
302
|
end
|
303
|
+
end
|
236
304
|
|
237
|
-
|
305
|
+
def file_collision_help #:nodoc:
|
238
306
|
<<HELP
|
239
307
|
Y - yes, overwrite
|
240
308
|
n - no, do not overwrite
|
@@ -243,59 +311,78 @@ q - quit, abort
|
|
243
311
|
d - diff, show the differences between the old and the new
|
244
312
|
h - help, show this help
|
245
313
|
HELP
|
246
|
-
|
314
|
+
end
|
247
315
|
|
248
|
-
|
249
|
-
|
316
|
+
def show_diff(destination, content) #:nodoc:
|
317
|
+
diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u'
|
250
318
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
end
|
319
|
+
Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
|
320
|
+
temp.write content
|
321
|
+
temp.rewind
|
322
|
+
system %(#{diff_cmd} "#{destination}" "#{temp.path}")
|
256
323
|
end
|
324
|
+
end
|
257
325
|
|
258
|
-
|
259
|
-
|
260
|
-
|
326
|
+
def quiet? #:nodoc:
|
327
|
+
mute? || (base && base.options[:quiet])
|
328
|
+
end
|
329
|
+
|
330
|
+
# Calculate the dynamic width of the terminal
|
331
|
+
def dynamic_width
|
332
|
+
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
|
333
|
+
end
|
334
|
+
|
335
|
+
def dynamic_width_stty
|
336
|
+
%x{stty size 2>/dev/null}.split[1].to_i
|
337
|
+
end
|
261
338
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
339
|
+
def dynamic_width_tput
|
340
|
+
%x{tput cols 2>/dev/null}.to_i
|
341
|
+
end
|
342
|
+
|
343
|
+
def unix?
|
344
|
+
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
345
|
+
end
|
346
|
+
|
347
|
+
def truncate(string, width)
|
348
|
+
as_unicode do
|
349
|
+
chars = string.chars.to_a
|
350
|
+
if chars.length <= width
|
351
|
+
chars.join
|
267
352
|
else
|
268
|
-
|
353
|
+
( chars[0, width-3].join ) + "..."
|
269
354
|
end
|
270
|
-
(result < 10) ? 80 : result
|
271
|
-
rescue
|
272
|
-
80
|
273
|
-
end
|
274
|
-
|
275
|
-
# Calculate the dynamic width of the terminal
|
276
|
-
def dynamic_width
|
277
|
-
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
|
278
355
|
end
|
356
|
+
end
|
279
357
|
|
280
|
-
|
281
|
-
|
358
|
+
if "".respond_to?(:encode)
|
359
|
+
def as_unicode
|
360
|
+
yield
|
282
361
|
end
|
283
|
-
|
284
|
-
def
|
285
|
-
|
362
|
+
else
|
363
|
+
def as_unicode
|
364
|
+
old, $KCODE = $KCODE, "U"
|
365
|
+
yield
|
366
|
+
ensure
|
367
|
+
$KCODE = old
|
286
368
|
end
|
369
|
+
end
|
287
370
|
|
288
|
-
|
289
|
-
|
290
|
-
|
371
|
+
def ask_simply(statement, color=nil)
|
372
|
+
say("#{statement} ", color)
|
373
|
+
stdin.gets.strip
|
374
|
+
end
|
291
375
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
376
|
+
def ask_filtered(statement, answer_set, *args)
|
377
|
+
correct_answer = nil
|
378
|
+
until correct_answer
|
379
|
+
answer = ask_simply("#{statement} #{answer_set.inspect}", *args)
|
380
|
+
correct_answer = answer_set.include?(answer) ? answer : nil
|
381
|
+
answers = answer_set.map(&:inspect).join(", ")
|
382
|
+
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
298
383
|
end
|
384
|
+
correct_answer
|
385
|
+
end
|
299
386
|
|
300
387
|
end
|
301
388
|
end
|