thor 0.13.6 → 0.13.7
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 +2 -2
- data/lib/thor.rb +62 -17
- data/lib/thor/actions.rb +3 -2
- data/lib/thor/actions/create_file.rb +3 -1
- data/lib/thor/actions/directory.rb +3 -1
- data/lib/thor/actions/file_manipulation.rb +11 -5
- data/lib/thor/base.rb +5 -6
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +1 -1
- data/lib/thor/group.rb +2 -2
- data/lib/thor/parser/arguments.rb +14 -3
- data/lib/thor/parser/options.rb +0 -5
- data/lib/thor/runner.rb +7 -12
- data/lib/thor/shell.rb +7 -2
- data/lib/thor/shell/basic.rb +38 -6
- data/lib/thor/shell/html.rb +121 -0
- data/lib/thor/task.rb +12 -12
- data/lib/thor/util.rb +6 -1
- data/lib/thor/version.rb +1 -1
- data/spec/actions_spec.rb +19 -1
- data/spec/base_spec.rb +2 -2
- data/spec/fixtures/path with spaces b/data/spec/fixtures/path with → spaces +0 -0
- data/spec/fixtures/script.thor +21 -0
- data/spec/parser/options_spec.rb +5 -0
- data/spec/runner_spec.rb +1 -1
- data/spec/shell/basic_spec.rb +9 -0
- data/spec/shell/html_spec.rb +27 -0
- data/spec/shell_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/task_spec.rb +2 -2
- data/spec/thor_spec.rb +39 -2
- metadata +49 -4
data/CHANGELOG.rdoc
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
== 0.13, released 2010-02-03
|
2
2
|
|
3
|
-
*
|
3
|
+
* Added Thor::Shell::HTML
|
4
4
|
* Decoupled Thor::Group and Thor, so it's easier to vendor
|
5
|
-
* Added check_unknown_options! in case you want error messages to be raised in valid switches
|
5
|
+
* Added check_unknown_options! in case you want error messages to be raised in valid switches
|
6
6
|
* run(command) should return the results of command
|
7
7
|
|
8
8
|
== 0.12, released 2010-01-02
|
data/lib/thor.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'thor/base'
|
2
2
|
|
3
|
-
# TODO: Update thor to allow for git-style CLI (git bisect run)
|
4
3
|
class Thor
|
5
4
|
class << self
|
6
5
|
# Sets the default task when thor is executed without an explicit task to be called.
|
@@ -35,6 +34,20 @@ class Thor
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
37
|
+
# Defines the long description of the next task.
|
38
|
+
#
|
39
|
+
# ==== Parameters
|
40
|
+
# long description<String>
|
41
|
+
#
|
42
|
+
def long_desc(long_description, options={})
|
43
|
+
if options[:for]
|
44
|
+
task = find_and_refresh_task(options[:for])
|
45
|
+
task.long_description = long_description if long_description
|
46
|
+
else
|
47
|
+
@long_desc = long_description
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
# Maps an input to a task. If you define:
|
39
52
|
#
|
40
53
|
# map "-T" => "list"
|
@@ -121,8 +134,17 @@ class Thor
|
|
121
134
|
# script.invoke(:task, first_arg, second_arg, third_arg)
|
122
135
|
#
|
123
136
|
def start(original_args=ARGV, config={})
|
137
|
+
@@original_args = original_args
|
124
138
|
super do |given_args|
|
125
|
-
meth =
|
139
|
+
meth = given_args.first.to_s
|
140
|
+
|
141
|
+
if !meth.empty? && (map[meth] || meth !~ /^\-/)
|
142
|
+
given_args.shift
|
143
|
+
else
|
144
|
+
meth = nil
|
145
|
+
end
|
146
|
+
|
147
|
+
meth = normalize_task_name(meth)
|
126
148
|
task = all_tasks[meth]
|
127
149
|
|
128
150
|
if task
|
@@ -153,7 +175,12 @@ class Thor
|
|
153
175
|
shell.say " #{banner(task)}"
|
154
176
|
shell.say
|
155
177
|
class_options_help(shell, nil => task.options.map { |_, o| o })
|
156
|
-
|
178
|
+
if task.long_description
|
179
|
+
shell.say "Description:"
|
180
|
+
shell.print_wrapped(task.long_description, :ident => 2)
|
181
|
+
else
|
182
|
+
shell.say task.description
|
183
|
+
end
|
157
184
|
end
|
158
185
|
|
159
186
|
# Prints help information for this class.
|
@@ -161,8 +188,8 @@ class Thor
|
|
161
188
|
# ==== Parameters
|
162
189
|
# shell<Thor::Shell>
|
163
190
|
#
|
164
|
-
def help(shell)
|
165
|
-
list = printable_tasks
|
191
|
+
def help(shell, subcommand = false)
|
192
|
+
list = printable_tasks(true, subcommand)
|
166
193
|
Thor::Util.thor_classes_in(self).each do |klass|
|
167
194
|
list += klass.printable_tasks(false)
|
168
195
|
end
|
@@ -175,17 +202,24 @@ class Thor
|
|
175
202
|
end
|
176
203
|
|
177
204
|
# Returns tasks ready to be printed.
|
178
|
-
def printable_tasks(all=true)
|
205
|
+
def printable_tasks(all = true, subcommand = false)
|
179
206
|
(all ? all_tasks : tasks).map do |_, task|
|
180
207
|
item = []
|
181
|
-
item << banner(task)
|
208
|
+
item << banner(task, false, subcommand)
|
182
209
|
item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
|
183
210
|
item
|
184
211
|
end
|
185
212
|
end
|
186
213
|
|
187
|
-
def
|
188
|
-
|
214
|
+
def subcommands
|
215
|
+
@@subcommands ||= {}
|
216
|
+
end
|
217
|
+
|
218
|
+
def subcommand(subcommand, subcommand_class)
|
219
|
+
subcommand = subcommand.to_s
|
220
|
+
subcommands[subcommand] = subcommand_class
|
221
|
+
subcommand_class.subcommand_help subcommand
|
222
|
+
define_method(subcommand) { |*_| subcommand_class.start(subcommand_args) }
|
189
223
|
end
|
190
224
|
|
191
225
|
protected
|
@@ -195,8 +229,8 @@ class Thor
|
|
195
229
|
# the task that is going to be invoked and a boolean which indicates if
|
196
230
|
# the namespace should be displayed as arguments.
|
197
231
|
#
|
198
|
-
def banner(task)
|
199
|
-
"#{
|
232
|
+
def banner(task, namespace = nil, subcommand = false)
|
233
|
+
"#{$0} #{task.formatted_usage(self, $thor_runner, subcommand)}"
|
200
234
|
end
|
201
235
|
|
202
236
|
def baseclass #:nodoc:
|
@@ -205,8 +239,8 @@ class Thor
|
|
205
239
|
|
206
240
|
def create_task(meth) #:nodoc:
|
207
241
|
if @usage && @desc
|
208
|
-
tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options)
|
209
|
-
@usage, @desc, @method_options = nil
|
242
|
+
tasks[meth.to_s] = Thor::Task.new(meth, @desc, @long_desc, @usage, method_options)
|
243
|
+
@usage, @desc, @long_desc, @method_options = nil
|
210
244
|
true
|
211
245
|
elsif self.all_tasks[meth.to_s] || meth.to_sym == :method_missing
|
212
246
|
true
|
@@ -227,10 +261,21 @@ class Thor
|
|
227
261
|
# If a map can't be found use the sent name or the default task.
|
228
262
|
#
|
229
263
|
def normalize_task_name(meth) #:nodoc:
|
230
|
-
|
231
|
-
meth = mapping || meth || default_task
|
264
|
+
meth = map[meth.to_s] || meth || default_task
|
232
265
|
meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
|
233
266
|
end
|
267
|
+
|
268
|
+
def subcommand_help(cmd)
|
269
|
+
desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
|
270
|
+
class_eval <<-RUBY
|
271
|
+
def help(task = nil, subcommand = true); super; end
|
272
|
+
RUBY
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
def subcommand_args
|
278
|
+
@@original_args[1..-1]
|
234
279
|
end
|
235
280
|
|
236
281
|
include Thor::Base
|
@@ -238,7 +283,7 @@ class Thor
|
|
238
283
|
map HELP_MAPPINGS => :help
|
239
284
|
|
240
285
|
desc "help [TASK]", "Describe available tasks or one specific task"
|
241
|
-
def help(task=nil)
|
242
|
-
task ? self.class.task_help(shell, task) : self.class.help(shell)
|
286
|
+
def help(task = nil, subcommand = false)
|
287
|
+
task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
|
243
288
|
end
|
244
289
|
end
|
data/lib/thor/actions.rb
CHANGED
@@ -190,12 +190,13 @@ class Thor
|
|
190
190
|
#
|
191
191
|
def apply(path, config={})
|
192
192
|
verbose = config.fetch(:verbose, true)
|
193
|
-
|
193
|
+
is_uri = path =~ /^https?\:\/\//
|
194
|
+
path = find_in_source_paths(path) unless is_uri
|
194
195
|
|
195
196
|
say_status :apply, path, verbose
|
196
197
|
shell.padding += 1 if verbose
|
197
198
|
|
198
|
-
if
|
199
|
+
if is_uri
|
199
200
|
contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
|
200
201
|
else
|
201
202
|
contents = open(path) {|io| io.read }
|
@@ -20,7 +20,9 @@ class Thor
|
|
20
20
|
#
|
21
21
|
# create_file "config/apach.conf", "your apache config"
|
22
22
|
#
|
23
|
-
def create_file(destination,
|
23
|
+
def create_file(destination, *args, &block)
|
24
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
25
|
+
data = args.first
|
24
26
|
action CreateFile.new(self, destination, block || data.to_s, config)
|
25
27
|
end
|
26
28
|
alias :add_file :create_file
|
@@ -40,7 +40,9 @@ class Thor
|
|
40
40
|
# directory "doc"
|
41
41
|
# directory "doc", "docs", :recursive => false
|
42
42
|
#
|
43
|
-
def directory(source,
|
43
|
+
def directory(source, *args, &block)
|
44
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
45
|
+
destination = args.first || source
|
44
46
|
action Directory.new(self, source, destination || source, config, &block)
|
45
47
|
end
|
46
48
|
|
@@ -18,8 +18,9 @@ class Thor
|
|
18
18
|
#
|
19
19
|
# copy_file "doc/README"
|
20
20
|
#
|
21
|
-
def copy_file(source,
|
22
|
-
|
21
|
+
def copy_file(source, *args, &block)
|
22
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
23
|
+
destination = args.first || source
|
23
24
|
source = File.expand_path(find_in_source_paths(source.to_s))
|
24
25
|
|
25
26
|
create_file destination, nil, config do
|
@@ -46,7 +47,10 @@ class Thor
|
|
46
47
|
# content.split("\n").first
|
47
48
|
# end
|
48
49
|
#
|
49
|
-
def get(source,
|
50
|
+
def get(source, *args, &block)
|
51
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
52
|
+
destination = args.first
|
53
|
+
|
50
54
|
source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
|
51
55
|
render = open(source) {|input| input.binmode.read }
|
52
56
|
|
@@ -74,8 +78,10 @@ class Thor
|
|
74
78
|
#
|
75
79
|
# template "doc/README"
|
76
80
|
#
|
77
|
-
def template(source,
|
78
|
-
|
81
|
+
def template(source, *args, &block)
|
82
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
83
|
+
destination = args.first || source
|
84
|
+
|
79
85
|
source = File.expand_path(find_in_source_paths(source.to_s))
|
80
86
|
context = instance_eval('binding')
|
81
87
|
|
data/lib/thor/base.rb
CHANGED
@@ -382,13 +382,17 @@ class Thor
|
|
382
382
|
end
|
383
383
|
|
384
384
|
def handle_no_task_error(task) #:nodoc:
|
385
|
-
if
|
385
|
+
if $thor_runner
|
386
386
|
raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
|
387
387
|
else
|
388
388
|
raise UndefinedTaskError, "Could not find task #{task.inspect}."
|
389
389
|
end
|
390
390
|
end
|
391
391
|
|
392
|
+
def handle_argument_error(task, error) #:nodoc:
|
393
|
+
raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{self.banner(task).inspect}."
|
394
|
+
end
|
395
|
+
|
392
396
|
protected
|
393
397
|
|
394
398
|
# Prints the class options per group. If an option does not belong to
|
@@ -516,11 +520,6 @@ class Thor
|
|
516
520
|
false
|
517
521
|
end
|
518
522
|
|
519
|
-
# Returns the base for banner.
|
520
|
-
def banner_base
|
521
|
-
@banner_base ||= $thor_runner ? "thor" : File.basename($0.split(" ").first)
|
522
|
-
end
|
523
|
-
|
524
523
|
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
525
524
|
# finishes.
|
526
525
|
def baseclass #:nodoc:
|
data/lib/thor/group.rb
CHANGED
@@ -228,7 +228,7 @@ class Thor::Group
|
|
228
228
|
# The banner for this class. You can customize it if you are invoking the
|
229
229
|
# thor class by another ways which is not the Thor::Runner.
|
230
230
|
def banner
|
231
|
-
"#{
|
231
|
+
"#{$0} #{self_task.formatted_usage(self, false)}"
|
232
232
|
end
|
233
233
|
|
234
234
|
# Represents the whole class as a task.
|
@@ -241,7 +241,7 @@ class Thor::Group
|
|
241
241
|
end
|
242
242
|
|
243
243
|
def create_task(meth) #:nodoc:
|
244
|
-
tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil)
|
244
|
+
tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, nil)
|
245
245
|
true
|
246
246
|
end
|
247
247
|
end
|
@@ -51,6 +51,11 @@ class Thor
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
+
def no_or_skip?(arg)
|
55
|
+
arg =~ /^--(no|skip)-([-\w]+)$/
|
56
|
+
$2
|
57
|
+
end
|
58
|
+
|
54
59
|
def last?
|
55
60
|
@pile.empty?
|
56
61
|
end
|
@@ -114,7 +119,7 @@ class Thor
|
|
114
119
|
array
|
115
120
|
end
|
116
121
|
|
117
|
-
# Check if the
|
122
|
+
# Check if the peek is numeric format and return a Float or Integer.
|
118
123
|
# Otherwise raises an error.
|
119
124
|
#
|
120
125
|
def parse_numeric(name)
|
@@ -127,10 +132,16 @@ class Thor
|
|
127
132
|
$&.index('.') ? shift.to_f : shift.to_i
|
128
133
|
end
|
129
134
|
|
130
|
-
# Parse string
|
135
|
+
# Parse string:
|
136
|
+
# for --string-arg, just return the current value in the pile
|
137
|
+
# for --no-string-arg, nil
|
131
138
|
#
|
132
139
|
def parse_string(name)
|
133
|
-
|
140
|
+
if no_or_skip?(name)
|
141
|
+
nil
|
142
|
+
else
|
143
|
+
shift
|
144
|
+
end
|
134
145
|
end
|
135
146
|
|
136
147
|
# Raises an error if @non_assigned_required array is not empty.
|
data/lib/thor/parser/options.rb
CHANGED
data/lib/thor/runner.rb
CHANGED
@@ -13,7 +13,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
13
13
|
|
14
14
|
# Override Thor#help so it can give information about any class and any method.
|
15
15
|
#
|
16
|
-
def help(meth=nil)
|
16
|
+
def help(meth = nil)
|
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)
|
@@ -39,7 +39,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
39
39
|
def install(name)
|
40
40
|
initialize_thorfiles
|
41
41
|
|
42
|
-
# If a directory name is provided as the argument, look for a 'main.thor'
|
42
|
+
# If a directory name is provided as the argument, look for a 'main.thor'
|
43
43
|
# task in said directory.
|
44
44
|
begin
|
45
45
|
if File.directory?(File.expand_path(name))
|
@@ -139,7 +139,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
139
139
|
end
|
140
140
|
|
141
141
|
desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
|
142
|
-
method_options :substring => :boolean, :group => :string, :all => :boolean
|
142
|
+
method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
|
143
143
|
def list(search="")
|
144
144
|
initialize_thorfiles
|
145
145
|
|
@@ -156,8 +156,8 @@ class Thor::Runner < Thor #:nodoc:
|
|
156
156
|
|
157
157
|
private
|
158
158
|
|
159
|
-
def self.banner(task)
|
160
|
-
"thor " + task.formatted_usage(self,
|
159
|
+
def self.banner(task, all = false, subcommand = false)
|
160
|
+
"thor " + task.formatted_usage(self, all, subcommand)
|
161
161
|
end
|
162
162
|
|
163
163
|
def thor_root
|
@@ -199,7 +199,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
199
199
|
#
|
200
200
|
def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
|
201
201
|
thorfiles(relevant_to, skip_lookup).each do |f|
|
202
|
-
Thor::Util.load_thorfile(f) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
|
202
|
+
Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
|
203
203
|
end
|
204
204
|
end
|
205
205
|
|
@@ -267,16 +267,11 @@ class Thor::Runner < Thor #:nodoc:
|
|
267
267
|
raise Error, "No Thor tasks available" if klasses.empty?
|
268
268
|
show_modules if with_modules && !thor_yaml.empty?
|
269
269
|
|
270
|
-
# Remove subclasses
|
271
|
-
klasses.dup.each do |klass|
|
272
|
-
klasses -= Thor::Util.thor_classes_in(klass)
|
273
|
-
end
|
274
|
-
|
275
270
|
list = Hash.new { |h,k| h[k] = [] }
|
276
271
|
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
|
277
272
|
|
278
273
|
# Get classes which inherit from Thor
|
279
|
-
(klasses - groups).each { |k| list[k.namespace] += k.printable_tasks(false) }
|
274
|
+
(klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_tasks(false) }
|
280
275
|
|
281
276
|
# Get classes which inherit from Thor::Base
|
282
277
|
groups.map! { |k| k.printable_tasks(false).first }
|
data/lib/thor/shell.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rbconfig'
|
2
|
-
require 'thor/shell/color'
|
3
2
|
|
4
3
|
class Thor
|
5
4
|
module Base
|
@@ -7,7 +6,9 @@ class Thor
|
|
7
6
|
# it will use a colored log, otherwise it will use a basic one without color.
|
8
7
|
#
|
9
8
|
def self.shell
|
10
|
-
@shell ||= if
|
9
|
+
@shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0
|
10
|
+
Thor::Shell.const_get(ENV['THOR_SHELL'])
|
11
|
+
elsif Config::CONFIG['host_os'] =~ /mswin|mingw/
|
11
12
|
Thor::Shell::Basic
|
12
13
|
else
|
13
14
|
Thor::Shell::Color
|
@@ -24,6 +25,10 @@ class Thor
|
|
24
25
|
module Shell
|
25
26
|
SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table]
|
26
27
|
|
28
|
+
autoload :Basic, 'thor/shell/basic'
|
29
|
+
autoload :Color, 'thor/shell/color'
|
30
|
+
autoload :HTML, 'thor/shell/HTML'
|
31
|
+
|
27
32
|
# Add shell to initialize config values.
|
28
33
|
#
|
29
34
|
# ==== Configuration
|
data/lib/thor/shell/basic.rb
CHANGED
@@ -42,8 +42,8 @@ class Thor
|
|
42
42
|
$stdout.puts(message)
|
43
43
|
else
|
44
44
|
$stdout.print(message)
|
45
|
-
$stdout.flush
|
46
45
|
end
|
46
|
+
$stdout.flush
|
47
47
|
end
|
48
48
|
|
49
49
|
# Say a status with the given color and appends the message. Since this
|
@@ -81,16 +81,20 @@ class Thor
|
|
81
81
|
# Array[Array[String, String, ...]]
|
82
82
|
#
|
83
83
|
# ==== Options
|
84
|
-
# ident<Integer>::
|
84
|
+
# ident<Integer>:: Indent the first column by ident value.
|
85
|
+
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
85
86
|
#
|
86
87
|
def print_table(table, options={})
|
87
88
|
return if table.empty?
|
88
89
|
|
89
|
-
formats, ident = [], options[:ident].to_i
|
90
|
+
formats, ident, colwidth = [], options[:ident].to_i, options[:colwidth]
|
90
91
|
options[:truncate] = terminal_width if options[:truncate] == true
|
91
92
|
|
92
|
-
|
93
|
-
|
93
|
+
formats << "%-#{colwidth + 2}s" if colwidth
|
94
|
+
start = colwidth ? 1 : 0
|
95
|
+
|
96
|
+
start.upto(table.first.length - 2) do |i|
|
97
|
+
maxima ||= table.max{|a,b| a[i].size <=> b[i].size }[i].size
|
94
98
|
formats << "%-#{maxima + 2}s"
|
95
99
|
end
|
96
100
|
|
@@ -105,7 +109,35 @@ class Thor
|
|
105
109
|
end
|
106
110
|
|
107
111
|
sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
108
|
-
$stdout.puts sentence
|
112
|
+
$stdout.puts sentence
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Prints a long string, word-wrapping the text to the current width of the
|
117
|
+
# terminal display. Ideal for printing heredocs.
|
118
|
+
#
|
119
|
+
# ==== Parameters
|
120
|
+
# String
|
121
|
+
#
|
122
|
+
# ==== Options
|
123
|
+
# ident<Integer>:: Indent each line of the printed paragraph by ident value.
|
124
|
+
#
|
125
|
+
def print_wrapped(message, options={})
|
126
|
+
ident = options[:ident] || 0
|
127
|
+
width = terminal_width - ident
|
128
|
+
paras = message.split("\n\n")
|
129
|
+
|
130
|
+
paras.map! do |unwrapped|
|
131
|
+
unwrapped.strip.gsub(/\n/, " ").squeeze(" ").
|
132
|
+
gsub(/.{1,#{width}}(?:\s|\Z)/){($& + 5.chr).
|
133
|
+
gsub(/\n\005/,"\n").gsub(/\005/,"\n")}
|
134
|
+
end
|
135
|
+
|
136
|
+
paras.each do |para|
|
137
|
+
para.split("\n").each do |line|
|
138
|
+
$stdout.puts line.insert(0, " " * ident)
|
139
|
+
end
|
140
|
+
$stdout.puts unless para == paras.last
|
109
141
|
end
|
110
142
|
end
|
111
143
|
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'thor/shell/basic'
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
module Shell
|
5
|
+
# Inherit from Thor::Shell::Basic and add set_color behavior. Check
|
6
|
+
# Thor::Shell::Basic to see all available methods.
|
7
|
+
#
|
8
|
+
class HTML < Basic
|
9
|
+
# The start of an HTML bold sequence.
|
10
|
+
BOLD = "<strong>"
|
11
|
+
# The end of an HTML bold sequence.
|
12
|
+
END_BOLD = "</strong>"
|
13
|
+
|
14
|
+
# Embed in a String to clear previous color selection.
|
15
|
+
CLEAR = "</span>"
|
16
|
+
|
17
|
+
# Set the terminal's foreground HTML color to black.
|
18
|
+
BLACK = '<span style="color: black;">'
|
19
|
+
# Set the terminal's foreground HTML color to red.
|
20
|
+
RED = '<span style="color: red;">'
|
21
|
+
# Set the terminal's foreground HTML color to green.
|
22
|
+
GREEN = '<span style="color: green;">'
|
23
|
+
# Set the terminal's foreground HTML color to yellow.
|
24
|
+
YELLOW = '<span style="color: yellow;">'
|
25
|
+
# Set the terminal's foreground HTML color to blue.
|
26
|
+
BLUE = '<span style="color: blue;">'
|
27
|
+
# Set the terminal's foreground HTML color to magenta.
|
28
|
+
MAGENTA = '<span style="color: magenta;">'
|
29
|
+
# Set the terminal's foreground HTML color to cyan.
|
30
|
+
CYAN = '<span style="color: cyan;">'
|
31
|
+
# Set the terminal's foreground HTML color to white.
|
32
|
+
WHITE = '<span style="color: white;">'
|
33
|
+
|
34
|
+
# Set the terminal's background HTML color to black.
|
35
|
+
ON_BLACK = '<span style="background-color: black">'
|
36
|
+
# Set the terminal's background HTML color to red.
|
37
|
+
ON_RED = '<span style="background-color: red">'
|
38
|
+
# Set the terminal's background HTML color to green.
|
39
|
+
ON_GREEN = '<span style="background-color: green">'
|
40
|
+
# Set the terminal's background HTML color to yellow.
|
41
|
+
ON_YELLOW = '<span style="background-color: yellow">'
|
42
|
+
# Set the terminal's background HTML color to blue.
|
43
|
+
ON_BLUE = '<span style="background-color: blue">'
|
44
|
+
# Set the terminal's background HTML color to magenta.
|
45
|
+
ON_MAGENTA = '<span style="background-color: magenta">'
|
46
|
+
# Set the terminal's background HTML color to cyan.
|
47
|
+
ON_CYAN = '<span style="background-color: cyan">'
|
48
|
+
# Set the terminal's background HTML color to white.
|
49
|
+
ON_WHITE = '<span style="background-color: white">'
|
50
|
+
|
51
|
+
# Set color by using a string or one of the defined constants. If a third
|
52
|
+
# option is set to true, it also adds bold to the string. This is based
|
53
|
+
# on Highline implementation and it automatically appends CLEAR to the end
|
54
|
+
# of the returned String.
|
55
|
+
#
|
56
|
+
def set_color(string, color, bold=false)
|
57
|
+
color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
58
|
+
bold, end_bold = bold ? [BOLD, END_BOLD] : ['', '']
|
59
|
+
"#{bold}#{color}#{string}#{CLEAR}#{end_bold}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Ask something to the user and receives a response.
|
63
|
+
#
|
64
|
+
# ==== Example
|
65
|
+
# ask("What is your name?")
|
66
|
+
#
|
67
|
+
# TODO: Implement #ask for Thor::Shell::HTML
|
68
|
+
def ask(statement, color=nil)
|
69
|
+
raise NotImplementedError, "Implement #ask for Thor::Shell::HTML"
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
75
|
+
# available.
|
76
|
+
#
|
77
|
+
def show_diff(destination, content) #:nodoc:
|
78
|
+
if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
|
79
|
+
actual = File.binread(destination).to_s.split("\n")
|
80
|
+
content = content.to_s.split("\n")
|
81
|
+
|
82
|
+
Diff::LCS.sdiff(actual, content).each do |diff|
|
83
|
+
output_diff_line(diff)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def output_diff_line(diff) #:nodoc:
|
91
|
+
case diff.action
|
92
|
+
when '-'
|
93
|
+
say "- #{diff.old_element.chomp}", :red, true
|
94
|
+
when '+'
|
95
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
96
|
+
when '!'
|
97
|
+
say "- #{diff.old_element.chomp}", :red, true
|
98
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
99
|
+
else
|
100
|
+
say " #{diff.old_element.chomp}", nil, true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
105
|
+
# for diff.
|
106
|
+
#
|
107
|
+
def diff_lcs_loaded? #:nodoc:
|
108
|
+
return true if defined?(Diff::LCS)
|
109
|
+
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
110
|
+
|
111
|
+
@diff_lcs_loaded = begin
|
112
|
+
require 'diff/lcs'
|
113
|
+
true
|
114
|
+
rescue LoadError
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/thor/task.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
class Thor
|
2
|
-
class Task < Struct.new(:name, :description, :usage, :options)
|
2
|
+
class Task < Struct.new(:name, :description, :long_description, :usage, :options)
|
3
3
|
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
|
4
4
|
|
5
5
|
# A dynamic task that handles method missing scenarios.
|
6
6
|
class Dynamic < Task
|
7
7
|
def initialize(name, options=nil)
|
8
|
-
super(name.to_s, "A dynamically-generated task", name.to_s, options)
|
8
|
+
super(name.to_s, "A dynamically-generated task", name.to_s, name.to_s, options)
|
9
9
|
end
|
10
10
|
|
11
11
|
def run(instance, args=[])
|
@@ -17,8 +17,8 @@ class Thor
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(name, description, usage, options=nil)
|
21
|
-
super(name.to_s, description, usage, options || {})
|
20
|
+
def initialize(name, description, long_description, usage, options=nil)
|
21
|
+
super(name.to_s, description, long_description, usage, options || {})
|
22
22
|
end
|
23
23
|
|
24
24
|
def initialize_copy(other) #:nodoc:
|
@@ -39,18 +39,18 @@ class Thor
|
|
39
39
|
instance.class.handle_no_task_error(name) : (raise e)
|
40
40
|
end
|
41
41
|
|
42
|
-
# Returns the formatted usage by injecting given required arguments
|
42
|
+
# Returns the formatted usage by injecting given required arguments
|
43
43
|
# and required options into the given usage.
|
44
|
-
def formatted_usage(klass, namespace=true)
|
44
|
+
def formatted_usage(klass, namespace = true, subcommand = false)
|
45
45
|
namespace = klass.namespace unless namespace == false
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
else
|
51
|
-
""
|
47
|
+
if namespace
|
48
|
+
formatted = "#{namespace.gsub(/^(default)/,'')}:"
|
49
|
+
formatted.sub!(/.$/, ' ') if subcommand
|
52
50
|
end
|
53
51
|
|
52
|
+
formatted ||= ""
|
53
|
+
|
54
54
|
# Add usage with required arguments
|
55
55
|
formatted << if klass && !klass.arguments.empty?
|
56
56
|
usage.to_s.gsub(/^#{name}/) do |match|
|
@@ -99,4 +99,4 @@ class Thor
|
|
99
99
|
end
|
100
100
|
|
101
101
|
end
|
102
|
-
end
|
102
|
+
end
|
data/lib/thor/util.rb
CHANGED
@@ -147,13 +147,18 @@ class Thor
|
|
147
147
|
# Receives a path and load the thor file in the path. The file is evaluated
|
148
148
|
# inside the sandbox to avoid namespacing conflicts.
|
149
149
|
#
|
150
|
-
def self.load_thorfile(path, content=nil)
|
150
|
+
def self.load_thorfile(path, content=nil, debug=false)
|
151
151
|
content ||= File.binread(path)
|
152
152
|
|
153
153
|
begin
|
154
154
|
Thor::Sandbox.class_eval(content, path)
|
155
155
|
rescue Exception => e
|
156
156
|
$stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}"
|
157
|
+
if debug
|
158
|
+
$stderr.puts *e.backtrace
|
159
|
+
else
|
160
|
+
$stderr.puts e.backtrace.first
|
161
|
+
end
|
157
162
|
end
|
158
163
|
end
|
159
164
|
|
data/lib/thor/version.rb
CHANGED
data/spec/actions_spec.rb
CHANGED
@@ -192,10 +192,28 @@ describe Thor::Actions do
|
|
192
192
|
@foo = "FOO"
|
193
193
|
say_status :cool, :padding
|
194
194
|
TEMPLATE
|
195
|
-
@template.
|
195
|
+
@template.stub(:read).and_return(@template)
|
196
196
|
|
197
|
+
@file = '/'
|
198
|
+
runner.stub(:open).and_return(@template)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "accepts a URL as the path" do
|
197
202
|
@file = "http://gist.github.com/103208.txt"
|
198
203
|
runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
|
204
|
+
action(:apply, @file)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "accepts a secure URL as the path" do
|
208
|
+
@file = "https://gist.github.com/103208.txt"
|
209
|
+
runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
|
210
|
+
action(:apply, @file)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "accepts a local file path with spaces" do
|
214
|
+
@file = File.expand_path("fixtures/path with spaces", File.dirname(__FILE__))
|
215
|
+
runner.should_receive(:open).with(@file).and_return(@template)
|
216
|
+
action(:apply, @file)
|
199
217
|
end
|
200
218
|
|
201
219
|
it "opens a file and executes its content in the instance binding" do
|
data/spec/base_spec.rb
CHANGED
@@ -176,8 +176,8 @@ describe Thor::Base do
|
|
176
176
|
it "returns tracked subclasses, grouped by the files they come from" do
|
177
177
|
thorfile = File.join(File.dirname(__FILE__), "fixtures", "script.thor")
|
178
178
|
Thor::Base.subclass_files[File.expand_path(thorfile)].must == [
|
179
|
-
MyScript, MyScript::AnotherScript, MyChildScript,
|
180
|
-
Scripts::MyDefaults, Scripts::ChildDefault
|
179
|
+
MyScript, MyScript::AnotherScript, MyChildScript, Barn,
|
180
|
+
Scripts::MyScript, Scripts::MyDefaults, Scripts::ChildDefault
|
181
181
|
]
|
182
182
|
end
|
183
183
|
|
File without changes
|
data/spec/fixtures/script.thor
CHANGED
@@ -37,6 +37,7 @@ END
|
|
37
37
|
end
|
38
38
|
|
39
39
|
desc "example_default_task", "example!"
|
40
|
+
method_options :with => :string
|
40
41
|
def example_default_task
|
41
42
|
options.empty? ? "default task" : options
|
42
43
|
end
|
@@ -52,6 +53,12 @@ END
|
|
52
53
|
end
|
53
54
|
|
54
55
|
desc "long_description", "a" * 80
|
56
|
+
long_desc <<-D
|
57
|
+
This is a really really really long description.
|
58
|
+
Here you go. So very long.
|
59
|
+
|
60
|
+
It even has two paragraphs.
|
61
|
+
D
|
55
62
|
def long_description
|
56
63
|
end
|
57
64
|
|
@@ -114,6 +121,17 @@ class MyChildScript < MyScript
|
|
114
121
|
remove_task :boom, :undefine => true
|
115
122
|
end
|
116
123
|
|
124
|
+
class Barn < Thor
|
125
|
+
desc "open [ITEM]", "open the barn door"
|
126
|
+
def open(item = nil)
|
127
|
+
if item == "shotgun"
|
128
|
+
puts "That's going to leave a mark."
|
129
|
+
else
|
130
|
+
puts "Open sesame!"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
117
135
|
module Scripts
|
118
136
|
class MyScript < MyChildScript
|
119
137
|
argument :accessor, :type => :string
|
@@ -136,6 +154,9 @@ module Scripts
|
|
136
154
|
def task_conflict
|
137
155
|
puts "task"
|
138
156
|
end
|
157
|
+
|
158
|
+
desc "barn", "commands to manage the barn"
|
159
|
+
subcommand "barn", Barn
|
139
160
|
end
|
140
161
|
|
141
162
|
class ChildDefault < Thor
|
data/spec/parser/options_spec.rb
CHANGED
@@ -176,6 +176,11 @@ describe Thor::Options do
|
|
176
176
|
parse("--no-foo")["foo"].must be_nil
|
177
177
|
end
|
178
178
|
|
179
|
+
it "does not consume an argument for --no-switch format" do
|
180
|
+
create "--cheese" => :string
|
181
|
+
parse('burger', '--no-cheese', 'fries')["cheese"].must be_nil
|
182
|
+
end
|
183
|
+
|
179
184
|
it "accepts a --switch format on non required types" do
|
180
185
|
create "--foo" => :string
|
181
186
|
parse("--foo")["foo"].must == "foo"
|
data/spec/runner_spec.rb
CHANGED
@@ -85,7 +85,7 @@ describe Thor::Runner do
|
|
85
85
|
it "does not swallow Thor InvocationError" do
|
86
86
|
ARGV.replace ["my_script:animal"]
|
87
87
|
content = capture(:stderr) { Thor::Runner.start }
|
88
|
-
content.strip.must == '"animal" was called incorrectly. Call as "my_script:animal TYPE".'
|
88
|
+
content.strip.must == '"animal" was called incorrectly. Call as "thor my_script:animal TYPE".'
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
data/spec/shell/basic_spec.rb
CHANGED
@@ -129,6 +129,15 @@ TABLE
|
|
129
129
|
abc #123 firs...
|
130
130
|
#0 empty
|
131
131
|
xyz #786 last...
|
132
|
+
TABLE
|
133
|
+
end
|
134
|
+
|
135
|
+
it "honors the colwidth option" do
|
136
|
+
content = capture(:stdout){ shell.print_table(@table, :colwidth => 10)}
|
137
|
+
content.must == <<-TABLE
|
138
|
+
abc #123 first three
|
139
|
+
#0 empty
|
140
|
+
xyz #786 last three
|
132
141
|
TABLE
|
133
142
|
end
|
134
143
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Thor::Shell::HTML do
|
4
|
+
def shell
|
5
|
+
@shell ||= Thor::Shell::HTML.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#say" do
|
9
|
+
it "set the color if specified" do
|
10
|
+
$stdout.should_receive(:puts).with('<span style="color: green;">Wow! Now we have colors!</span>')
|
11
|
+
shell.say "Wow! Now we have colors!", :green
|
12
|
+
end
|
13
|
+
|
14
|
+
it "does not use a new line even with colors" do
|
15
|
+
$stdout.should_receive(:print).with('<span style="color: green;">Wow! Now we have colors! </span>')
|
16
|
+
shell.say "Wow! Now we have colors! ", :green
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#say_status" do
|
21
|
+
it "uses color to say status" do
|
22
|
+
$stdout.should_receive(:puts).with('<strong><span style="color: red;"> conflict</span></strong> README')
|
23
|
+
shell.say_status :conflict, "README", :red
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/spec/shell_spec.rb
CHANGED
@@ -21,6 +21,18 @@ describe Thor::Shell do
|
|
21
21
|
it "returns the shell in use" do
|
22
22
|
MyCounter.new([1,2]).shell.must be_kind_of(Thor::Base.shell)
|
23
23
|
end
|
24
|
+
|
25
|
+
it "uses $THOR_SHELL" do
|
26
|
+
class Thor::Shell::TestShell < Thor::Shell::Basic; end
|
27
|
+
|
28
|
+
Thor::Base.shell.must == shell.class
|
29
|
+
ENV['THOR_SHELL'] = 'TestShell'
|
30
|
+
Thor::Base.shell = nil
|
31
|
+
Thor::Base.shell.must == Thor::Shell::TestShell
|
32
|
+
ENV['THOR_SHELL'] = ''
|
33
|
+
Thor::Base.shell = shell.class
|
34
|
+
Thor::Base.shell.must == shell.class
|
35
|
+
end
|
24
36
|
end
|
25
37
|
|
26
38
|
describe "with_padding" do
|
@@ -31,4 +43,5 @@ describe Thor::Shell do
|
|
31
43
|
end
|
32
44
|
end
|
33
45
|
end
|
46
|
+
|
34
47
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/task_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Thor::Task do
|
|
6
6
|
options[key] = Thor::Option.parse(key, value)
|
7
7
|
end
|
8
8
|
|
9
|
-
@task ||= Thor::Task.new(:can_has, "I can has cheezburger", "can_has", options)
|
9
|
+
@task ||= Thor::Task.new(:can_has, "I can has cheezburger", "I can has cheezburger\nLots and lots of it", "can_has", options)
|
10
10
|
end
|
11
11
|
|
12
12
|
describe "#formatted_usage" do
|
@@ -46,7 +46,7 @@ describe Thor::Task do
|
|
46
46
|
|
47
47
|
describe "#dup" do
|
48
48
|
it "dup options hash" do
|
49
|
-
task = Thor::Task.new("can_has", nil, nil, :foo => true, :bar => :required)
|
49
|
+
task = Thor::Task.new("can_has", nil, nil, nil, :foo => true, :bar => :required)
|
50
50
|
task.dup.options.delete(:foo)
|
51
51
|
task.options[:foo].must_not be_nil
|
52
52
|
end
|
data/spec/thor_spec.rb
CHANGED
@@ -41,6 +41,10 @@ describe Thor do
|
|
41
41
|
MyScript.start([]).must == "default task"
|
42
42
|
end
|
43
43
|
|
44
|
+
it "invokes the default task if no command is specified even if switches are given" do
|
45
|
+
MyScript.start(["--with", "option"]).must == {"with"=>"option"}
|
46
|
+
end
|
47
|
+
|
44
48
|
it "inherits the default task from parent" do
|
45
49
|
MyChildScript.default_task.must == "example_default_task"
|
46
50
|
end
|
@@ -112,7 +116,7 @@ describe Thor do
|
|
112
116
|
end
|
113
117
|
|
114
118
|
it "raises an error if a required param is not provided" do
|
115
|
-
capture(:stderr) { MyScript.start(["animal"]) }.strip.must == '"animal" was called incorrectly. Call as "my_script:animal TYPE".'
|
119
|
+
capture(:stderr) { MyScript.start(["animal"]) }.strip.must == '"animal" was called incorrectly. Call as "thor my_script:animal TYPE".'
|
116
120
|
end
|
117
121
|
|
118
122
|
it "raises an error if the invoked task does not exist" do
|
@@ -137,6 +141,21 @@ describe Thor do
|
|
137
141
|
end
|
138
142
|
end
|
139
143
|
|
144
|
+
describe "#subcommand" do
|
145
|
+
it "maps a given subcommand to another Thor subclass" do
|
146
|
+
barn_help = capture(:stdout){ Scripts::MyDefaults.start(["barn"]) }
|
147
|
+
barn_help.must include("barn help [COMMAND] # Describe subcommands or one specific subcommand")
|
148
|
+
end
|
149
|
+
|
150
|
+
it "passes commands to subcommand classes" do
|
151
|
+
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open"]) }.strip.must == "Open sesame!"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "passes arguments to subcommand classes" do
|
155
|
+
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open", "shotgun"]) }.strip.must == "That's going to leave a mark."
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
140
159
|
describe "#help" do
|
141
160
|
def shell
|
142
161
|
@shell ||= Thor::Base.shell.new
|
@@ -184,7 +203,7 @@ describe Thor do
|
|
184
203
|
|
185
204
|
describe "for a specific task" do
|
186
205
|
it "provides full help info when talking about a specific task" do
|
187
|
-
capture(:stdout) { MyScript.task_help(shell, "foo") }.must ==
|
206
|
+
capture(:stdout) { MyScript.task_help(shell, "foo") }.must == <<-END
|
188
207
|
Usage:
|
189
208
|
thor my_script:foo BAR
|
190
209
|
|
@@ -206,6 +225,24 @@ END
|
|
206
225
|
it "normalizes names before claiming they don't exist" do
|
207
226
|
capture(:stdout) { MyScript.task_help(shell, "name-with-dashes") }.must =~ /thor my_script:name-with-dashes/
|
208
227
|
end
|
228
|
+
|
229
|
+
it "uses the long description if it exists" do
|
230
|
+
capture(:stdout) { MyScript.task_help(shell, "long_description") }.must == <<-HELP
|
231
|
+
Usage:
|
232
|
+
thor my_script:long_description
|
233
|
+
|
234
|
+
Description:
|
235
|
+
This is a really really really long description. Here you go. So very long.
|
236
|
+
|
237
|
+
It even has two paragraphs.
|
238
|
+
HELP
|
239
|
+
end
|
240
|
+
|
241
|
+
it "doesn't assign the long description to the next task without one" do
|
242
|
+
capture(:stdout) do
|
243
|
+
MyScript.task_help(shell, "name_with_dashes")
|
244
|
+
end.must_not =~ /so very long/i
|
245
|
+
end
|
209
246
|
end
|
210
247
|
|
211
248
|
describe "instance method" do
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 37
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 13
|
8
|
-
-
|
9
|
-
version: 0.13.
|
9
|
+
- 7
|
10
|
+
version: 0.13.7
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Yehuda Katz
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2010-
|
19
|
+
date: 2010-06-28 00:00:00 +02:00
|
19
20
|
default_executable:
|
20
21
|
dependencies: []
|
21
22
|
|
@@ -62,9 +63,47 @@ files:
|
|
62
63
|
- lib/thor/shell.rb
|
63
64
|
- lib/thor/shell/basic.rb
|
64
65
|
- lib/thor/shell/color.rb
|
66
|
+
- lib/thor/shell/html.rb
|
65
67
|
- lib/thor/task.rb
|
66
68
|
- lib/thor/util.rb
|
67
69
|
- lib/thor/version.rb
|
70
|
+
- spec/actions/create_file_spec.rb
|
71
|
+
- spec/actions/directory_spec.rb
|
72
|
+
- spec/actions/empty_directory_spec.rb
|
73
|
+
- spec/actions/file_manipulation_spec.rb
|
74
|
+
- spec/actions/inject_into_file_spec.rb
|
75
|
+
- spec/actions_spec.rb
|
76
|
+
- spec/base_spec.rb
|
77
|
+
- spec/core_ext/hash_with_indifferent_access_spec.rb
|
78
|
+
- spec/core_ext/ordered_hash_spec.rb
|
79
|
+
- spec/fixtures/application.rb
|
80
|
+
- spec/fixtures/bundle/execute.rb
|
81
|
+
- spec/fixtures/doc/config.rb
|
82
|
+
- spec/group_spec.rb
|
83
|
+
- spec/invocation_spec.rb
|
84
|
+
- spec/parser/argument_spec.rb
|
85
|
+
- spec/parser/arguments_spec.rb
|
86
|
+
- spec/parser/option_spec.rb
|
87
|
+
- spec/parser/options_spec.rb
|
88
|
+
- spec/rake_compat_spec.rb
|
89
|
+
- spec/runner_spec.rb
|
90
|
+
- spec/shell/basic_spec.rb
|
91
|
+
- spec/shell/color_spec.rb
|
92
|
+
- spec/shell/html_spec.rb
|
93
|
+
- spec/shell_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
- spec/task_spec.rb
|
96
|
+
- spec/thor_spec.rb
|
97
|
+
- spec/util_spec.rb
|
98
|
+
- spec/fixtures/bundle/main.thor
|
99
|
+
- spec/fixtures/doc/%file_name%.rb.tt
|
100
|
+
- spec/fixtures/doc/README
|
101
|
+
- spec/fixtures/group.thor
|
102
|
+
- spec/fixtures/invoke.thor
|
103
|
+
- spec/fixtures/path with spaces
|
104
|
+
- spec/fixtures/script.thor
|
105
|
+
- spec/fixtures/task.thor
|
106
|
+
- spec/spec.opts
|
68
107
|
has_rdoc: true
|
69
108
|
homepage: http://yehudakatz.com
|
70
109
|
licenses: []
|
@@ -75,23 +114,27 @@ rdoc_options:
|
|
75
114
|
require_paths:
|
76
115
|
- lib
|
77
116
|
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
78
118
|
requirements:
|
79
119
|
- - ">="
|
80
120
|
- !ruby/object:Gem::Version
|
121
|
+
hash: 3
|
81
122
|
segments:
|
82
123
|
- 0
|
83
124
|
version: "0"
|
84
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
85
127
|
requirements:
|
86
128
|
- - ">="
|
87
129
|
- !ruby/object:Gem::Version
|
130
|
+
hash: 3
|
88
131
|
segments:
|
89
132
|
- 0
|
90
133
|
version: "0"
|
91
134
|
requirements: []
|
92
135
|
|
93
136
|
rubyforge_project: textmate
|
94
|
-
rubygems_version: 1.3.
|
137
|
+
rubygems_version: 1.3.7
|
95
138
|
signing_key:
|
96
139
|
specification_version: 3
|
97
140
|
summary: A scripting framework that replaces rake, sake and rubigen
|
@@ -118,6 +161,7 @@ test_files:
|
|
118
161
|
- spec/runner_spec.rb
|
119
162
|
- spec/shell/basic_spec.rb
|
120
163
|
- spec/shell/color_spec.rb
|
164
|
+
- spec/shell/html_spec.rb
|
121
165
|
- spec/shell_spec.rb
|
122
166
|
- spec/spec_helper.rb
|
123
167
|
- spec/task_spec.rb
|
@@ -128,6 +172,7 @@ test_files:
|
|
128
172
|
- spec/fixtures/doc/README
|
129
173
|
- spec/fixtures/group.thor
|
130
174
|
- spec/fixtures/invoke.thor
|
175
|
+
- spec/fixtures/path with spaces
|
131
176
|
- spec/fixtures/script.thor
|
132
177
|
- spec/fixtures/task.thor
|
133
178
|
- spec/spec.opts
|