thor 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/thor/actions/file_manipulation.rb +45 -11
- data/lib/thor/group.rb +11 -0
- data/lib/thor/parser/argument.rb +1 -4
- data/lib/thor/parser/option.rb +2 -2
- data/lib/thor/parser/options.rb +3 -2
- data/lib/thor/runner.rb +1 -1
- data/lib/thor/shell/basic.rb +12 -16
- data/lib/thor/shell/html.rb +1 -1
- data/lib/thor/shell/table_printer.rb +5 -21
- data/lib/thor/util.rb +1 -1
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +11 -0
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50c78a27ef16cfc96930bc60d8637e86acd69c94b932cc745bb2ed5c3e1605c8
|
4
|
+
data.tar.gz: 00b8a88f938047a55fe3ffadb6bd019666d82813ff584209a338bd8e6d3f16a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86fb64f2b698f06f5c7a0bd14523338802b374ae3d42879d71f94d542598216595176ce744b9ea84196d87657ec4cdaa9f73954ad15124b89109ee87a304eadc
|
7
|
+
data.tar.gz: 81f3b4ce1bca3d43efe2aecf00c88372b6673e3a82706e75ef018cc17badf3b3f2a267fe926b86225b112bbe1bd6e0257115327aa006984c89d8ddc434b88d56
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ users.
|
|
15
15
|
|
16
16
|
Please note: Thor, by design, is a system tool created to allow seamless file and url
|
17
17
|
access, which should not receive application user input. It relies on [open-uri][open-uri],
|
18
|
-
which combined with application user input would provide a command injection attack
|
18
|
+
which, combined with application user input, would provide a command injection attack
|
19
19
|
vector.
|
20
20
|
|
21
21
|
[rake]: https://github.com/ruby/rake
|
@@ -27,7 +27,7 @@ Installation
|
|
27
27
|
|
28
28
|
Usage and documentation
|
29
29
|
-----------------------
|
30
|
-
Please see the [wiki][] for basic usage and other documentation on using Thor. You can also
|
30
|
+
Please see the [wiki][] for basic usage and other documentation on using Thor. You can also check out the [official homepage][homepage].
|
31
31
|
|
32
32
|
[wiki]: https://github.com/rails/thor/wiki
|
33
33
|
[homepage]: http://whatisthor.com/
|
@@ -10,7 +10,6 @@ class Thor
|
|
10
10
|
# destination<String>:: the relative path to the destination root.
|
11
11
|
# config<Hash>:: give :verbose => false to not log the status, and
|
12
12
|
# :mode => :preserve, to preserve the file mode from the source.
|
13
|
-
|
14
13
|
#
|
15
14
|
# ==== Examples
|
16
15
|
#
|
@@ -243,6 +242,35 @@ class Thor
|
|
243
242
|
insert_into_file(path, *(args << config), &block)
|
244
243
|
end
|
245
244
|
|
245
|
+
# Run a regular expression replacement on a file, raising an error if the
|
246
|
+
# contents of the file are not changed.
|
247
|
+
#
|
248
|
+
# ==== Parameters
|
249
|
+
# path<String>:: path of the file to be changed
|
250
|
+
# flag<Regexp|String>:: the regexp or string to be replaced
|
251
|
+
# replacement<String>:: the replacement, can be also given as a block
|
252
|
+
# config<Hash>:: give :verbose => false to not log the status, and
|
253
|
+
# :force => true, to force the replacement regardless of runner behavior.
|
254
|
+
#
|
255
|
+
# ==== Example
|
256
|
+
#
|
257
|
+
# gsub_file! 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
|
258
|
+
#
|
259
|
+
# gsub_file! 'README', /rake/, :green do |match|
|
260
|
+
# match << " no more. Use thor!"
|
261
|
+
# end
|
262
|
+
#
|
263
|
+
def gsub_file!(path, flag, *args, &block)
|
264
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
265
|
+
|
266
|
+
return unless behavior == :invoke || config.fetch(:force, false)
|
267
|
+
|
268
|
+
path = File.expand_path(path, destination_root)
|
269
|
+
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
270
|
+
|
271
|
+
actually_gsub_file(path, flag, args, true, &block) unless options[:pretend]
|
272
|
+
end
|
273
|
+
|
246
274
|
# Run a regular expression replacement on a file.
|
247
275
|
#
|
248
276
|
# ==== Parameters
|
@@ -268,16 +296,11 @@ class Thor
|
|
268
296
|
path = File.expand_path(path, destination_root)
|
269
297
|
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
270
298
|
|
271
|
-
unless options[:pretend]
|
272
|
-
content = File.binread(path)
|
273
|
-
content.gsub!(flag, *args, &block)
|
274
|
-
File.open(path, "wb") { |file| file.write(content) }
|
275
|
-
end
|
299
|
+
actually_gsub_file(path, flag, args, false, &block) unless options[:pretend]
|
276
300
|
end
|
277
301
|
|
278
|
-
# Uncomment all lines matching a given regex.
|
279
|
-
#
|
280
|
-
# between the comment hash and the beginning of the line.
|
302
|
+
# Uncomment all lines matching a given regex. Preserves indentation before
|
303
|
+
# the comment hash and removes the hash and any immediate following space.
|
281
304
|
#
|
282
305
|
# ==== Parameters
|
283
306
|
# path<String>:: path of the file to be changed
|
@@ -291,7 +314,7 @@ class Thor
|
|
291
314
|
def uncomment_lines(path, flag, *args)
|
292
315
|
flag = flag.respond_to?(:source) ? flag.source : flag
|
293
316
|
|
294
|
-
gsub_file(path, /^(\s*)#[[:blank:]]
|
317
|
+
gsub_file(path, /^(\s*)#[[:blank:]]?(.*#{flag})/, '\1\2', *args)
|
295
318
|
end
|
296
319
|
|
297
320
|
# Comment all lines matching a given regex. It will leave the space
|
@@ -350,7 +373,7 @@ class Thor
|
|
350
373
|
end
|
351
374
|
|
352
375
|
def with_output_buffer(buf = "".dup) #:nodoc:
|
353
|
-
raise ArgumentError, "Buffer
|
376
|
+
raise ArgumentError, "Buffer cannot be a frozen object" if buf.frozen?
|
354
377
|
old_buffer = output_buffer
|
355
378
|
self.output_buffer = buf
|
356
379
|
yield
|
@@ -359,6 +382,17 @@ class Thor
|
|
359
382
|
self.output_buffer = old_buffer
|
360
383
|
end
|
361
384
|
|
385
|
+
def actually_gsub_file(path, flag, args, error_on_no_change, &block)
|
386
|
+
content = File.binread(path)
|
387
|
+
success = content.gsub!(flag, *args, &block)
|
388
|
+
|
389
|
+
if success.nil? && error_on_no_change
|
390
|
+
raise Thor::Error, "The content of #{path} did not change"
|
391
|
+
end
|
392
|
+
|
393
|
+
File.open(path, "wb") { |file| file.write(content) }
|
394
|
+
end
|
395
|
+
|
362
396
|
# Thor::Actions#capture depends on what kind of buffer is used in ERB.
|
363
397
|
# Thus CapturableERB fixes ERB to use String buffer.
|
364
398
|
class CapturableERB < ERB
|
data/lib/thor/group.rb
CHANGED
@@ -211,6 +211,17 @@ class Thor::Group
|
|
211
211
|
raise error, msg
|
212
212
|
end
|
213
213
|
|
214
|
+
# Checks if a specified command exists.
|
215
|
+
#
|
216
|
+
# ==== Parameters
|
217
|
+
# command_name<String>:: The name of the command to check for existence.
|
218
|
+
#
|
219
|
+
# ==== Returns
|
220
|
+
# Boolean:: +true+ if the command exists, +false+ otherwise.
|
221
|
+
def command_exists?(command_name) #:nodoc:
|
222
|
+
commands.keys.include?(command_name)
|
223
|
+
end
|
224
|
+
|
214
225
|
protected
|
215
226
|
|
216
227
|
# The method responsible for dispatching given the args.
|
data/lib/thor/parser/argument.rb
CHANGED
data/lib/thor/parser/option.rb
CHANGED
@@ -89,8 +89,8 @@ class Thor
|
|
89
89
|
|
90
90
|
sample = "[#{sample}]".dup unless required?
|
91
91
|
|
92
|
-
if boolean?
|
93
|
-
sample << ", [#{dasherize('no-' + human_name)}]
|
92
|
+
if boolean? && name != "force" && !name.match(/\A(no|skip)[\-_]/)
|
93
|
+
sample << ", [#{dasherize('no-' + human_name)}], [#{dasherize('skip-' + human_name)}]"
|
94
94
|
end
|
95
95
|
|
96
96
|
aliases_for_usage.ljust(padding) + sample
|
data/lib/thor/parser/options.rb
CHANGED
@@ -144,7 +144,7 @@ class Thor
|
|
144
144
|
def check_exclusive!
|
145
145
|
opts = @assigns.keys
|
146
146
|
# When option A and B are exclusive, if A and B are given at the same time,
|
147
|
-
# the
|
147
|
+
# the difference of argument array size will decrease.
|
148
148
|
found = @exclusives.find{ |ex| (ex - opts).size < ex.size - 1 }
|
149
149
|
if found
|
150
150
|
names = names_to_switch_names(found & opts).map{|n| "'#{n}'"}
|
@@ -250,7 +250,8 @@ class Thor
|
|
250
250
|
@parsing_options
|
251
251
|
end
|
252
252
|
|
253
|
-
# Parse boolean values which can be given as --foo=true
|
253
|
+
# Parse boolean values which can be given as --foo=true or --foo for true values, or
|
254
|
+
# --foo=false, --no-foo or --skip-foo for false values.
|
254
255
|
#
|
255
256
|
def parse_boolean(switch)
|
256
257
|
if current_is_value?
|
data/lib/thor/runner.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require_relative "../thor"
|
2
2
|
require_relative "group"
|
3
3
|
|
4
|
-
require "yaml"
|
5
4
|
require "digest/sha2"
|
6
5
|
require "pathname"
|
7
6
|
|
@@ -195,6 +194,7 @@ private
|
|
195
194
|
def thor_yaml
|
196
195
|
@thor_yaml ||= begin
|
197
196
|
yaml_file = File.join(thor_root, "thor.yml")
|
197
|
+
require "yaml"
|
198
198
|
yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
|
199
199
|
yaml || {}
|
200
200
|
end
|
data/lib/thor/shell/basic.rb
CHANGED
@@ -67,15 +67,15 @@ class Thor
|
|
67
67
|
# Readline.
|
68
68
|
#
|
69
69
|
# ==== Example
|
70
|
-
#
|
70
|
+
# ask("What is your name?")
|
71
71
|
#
|
72
|
-
#
|
72
|
+
# ask("What is the planet furthest from the sun?", :default => "Neptune")
|
73
73
|
#
|
74
|
-
#
|
74
|
+
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
75
75
|
#
|
76
|
-
#
|
76
|
+
# ask("What is your password?", :echo => false)
|
77
77
|
#
|
78
|
-
#
|
78
|
+
# ask("Where should the file be saved?", :path => true)
|
79
79
|
#
|
80
80
|
def ask(statement, *args)
|
81
81
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -93,7 +93,7 @@ class Thor
|
|
93
93
|
# are passed straight to puts (behavior got from Highline).
|
94
94
|
#
|
95
95
|
# ==== Example
|
96
|
-
#
|
96
|
+
# say("I know you knew that.")
|
97
97
|
#
|
98
98
|
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
99
99
|
return if quiet?
|
@@ -110,7 +110,7 @@ class Thor
|
|
110
110
|
# are passed straight to puts (behavior got from Highline).
|
111
111
|
#
|
112
112
|
# ==== Example
|
113
|
-
#
|
113
|
+
# say_error("error: something went wrong")
|
114
114
|
#
|
115
115
|
def say_error(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
116
116
|
return if quiet?
|
@@ -143,14 +143,14 @@ class Thor
|
|
143
143
|
stdout.flush
|
144
144
|
end
|
145
145
|
|
146
|
-
#
|
146
|
+
# Asks the user a question and returns true if the user replies "y" or
|
147
147
|
# "yes".
|
148
148
|
#
|
149
149
|
def yes?(statement, color = nil)
|
150
150
|
!!(ask(statement, color, add_to_history: false) =~ is?(:yes))
|
151
151
|
end
|
152
152
|
|
153
|
-
#
|
153
|
+
# Asks the user a question and returns true if the user replies "n" or
|
154
154
|
# "no".
|
155
155
|
#
|
156
156
|
def no?(statement, color = nil)
|
@@ -314,7 +314,7 @@ class Thor
|
|
314
314
|
diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
|
315
315
|
|
316
316
|
require "tempfile"
|
317
|
-
Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
|
317
|
+
Tempfile.open(File.basename(destination), File.dirname(destination), binmode: true) do |temp|
|
318
318
|
temp.write content
|
319
319
|
temp.rewind
|
320
320
|
system %(#{diff_cmd} "#{destination}" "#{temp.path}")
|
@@ -372,16 +372,12 @@ class Thor
|
|
372
372
|
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
|
373
373
|
temp.write content
|
374
374
|
temp.rewind
|
375
|
-
system
|
375
|
+
system(merge_tool, temp.path, destination)
|
376
376
|
end
|
377
377
|
end
|
378
378
|
|
379
379
|
def merge_tool #:nodoc:
|
380
|
-
@merge_tool ||= ENV["THOR_MERGE"] ||
|
381
|
-
end
|
382
|
-
|
383
|
-
def git_merge_tool #:nodoc:
|
384
|
-
`git config merge.tool`.rstrip rescue ""
|
380
|
+
@merge_tool ||= ENV["THOR_MERGE"] || "git difftool --no-index"
|
385
381
|
end
|
386
382
|
end
|
387
383
|
end
|
data/lib/thor/shell/html.rb
CHANGED
@@ -102,33 +102,17 @@ class Thor
|
|
102
102
|
|
103
103
|
def truncate(string)
|
104
104
|
return string unless @truncate
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
chars[0, @truncate - 3 - @indent].join + "..."
|
111
|
-
end
|
105
|
+
chars = string.chars.to_a
|
106
|
+
if chars.length <= @truncate
|
107
|
+
chars.join
|
108
|
+
else
|
109
|
+
chars[0, @truncate - 3 - @indent].join + "..."
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
115
113
|
def indentation
|
116
114
|
" " * @indent
|
117
115
|
end
|
118
|
-
|
119
|
-
if "".respond_to?(:encode)
|
120
|
-
def as_unicode
|
121
|
-
yield
|
122
|
-
end
|
123
|
-
else
|
124
|
-
def as_unicode
|
125
|
-
old = $KCODE # rubocop:disable Style/GlobalVars
|
126
|
-
$KCODE = "U" # rubocop:disable Style/GlobalVars
|
127
|
-
yield
|
128
|
-
ensure
|
129
|
-
$KCODE = old # rubocop:disable Style/GlobalVars
|
130
|
-
end
|
131
|
-
end
|
132
116
|
end
|
133
117
|
end
|
134
118
|
end
|
data/lib/thor/util.rb
CHANGED
@@ -133,7 +133,7 @@ class Thor
|
|
133
133
|
*pieces, command = namespace.split(":")
|
134
134
|
namespace = pieces.join(":")
|
135
135
|
namespace = "default" if namespace.empty?
|
136
|
-
klass = Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.
|
136
|
+
klass = Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.command_exists?(command) }
|
137
137
|
end
|
138
138
|
unless klass # look for a Thor::Group with the right name
|
139
139
|
klass = Thor::Util.find_by_namespace(namespace)
|
data/lib/thor/version.rb
CHANGED
data/lib/thor.rb
CHANGED
@@ -439,6 +439,17 @@ class Thor
|
|
439
439
|
command && disable_required_check.include?(command.name.to_sym)
|
440
440
|
end
|
441
441
|
|
442
|
+
# Checks if a specified command exists.
|
443
|
+
#
|
444
|
+
# ==== Parameters
|
445
|
+
# command_name<String>:: The name of the command to check for existence.
|
446
|
+
#
|
447
|
+
# ==== Returns
|
448
|
+
# Boolean:: +true+ if the command exists, +false+ otherwise.
|
449
|
+
def command_exists?(command_name) #:nodoc:
|
450
|
+
commands.keys.include?(normalize_command_name(command_name))
|
451
|
+
end
|
452
|
+
|
442
453
|
protected
|
443
454
|
|
444
455
|
# Returns this class exclusive options array set.
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yehuda Katz
|
8
8
|
- José Valim
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
@@ -85,12 +84,11 @@ licenses:
|
|
85
84
|
- MIT
|
86
85
|
metadata:
|
87
86
|
bug_tracker_uri: https://github.com/rails/thor/issues
|
88
|
-
changelog_uri: https://github.com/rails/thor/releases/tag/v1.
|
87
|
+
changelog_uri: https://github.com/rails/thor/releases/tag/v1.4.0
|
89
88
|
documentation_uri: http://whatisthor.com/
|
90
|
-
source_code_uri: https://github.com/rails/thor/tree/v1.
|
89
|
+
source_code_uri: https://github.com/rails/thor/tree/v1.4.0
|
91
90
|
wiki_uri: https://github.com/rails/thor/wiki
|
92
91
|
rubygems_mfa_required: 'true'
|
93
|
-
post_install_message:
|
94
92
|
rdoc_options: []
|
95
93
|
require_paths:
|
96
94
|
- lib
|
@@ -105,8 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
103
|
- !ruby/object:Gem::Version
|
106
104
|
version: 1.3.5
|
107
105
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
109
|
-
signing_key:
|
106
|
+
rubygems_version: 3.6.7
|
110
107
|
specification_version: 4
|
111
108
|
summary: Thor is a toolkit for building powerful command-line interfaces.
|
112
109
|
test_files: []
|