thor 1.3.2 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b49f263d36f84d82f17f16852671ff9e2f529ea0adec4b664a2b8660923d091
4
- data.tar.gz: 2df9cade7c368e064377ec0f38737d5b379b38265f23d878cb4976588b94564c
3
+ metadata.gz: 83a74d97baca896e3f78dfdcb081c118c8599ecbcf79085cbff299f393ccdd7c
4
+ data.tar.gz: c96fd32b0d35ea099f176a8febae1eb8814bf81548c442eb3a43d05d1c58f407
5
5
  SHA512:
6
- metadata.gz: c4cca8a5e388509dd8a45a6484c13fa80d89f15c7bfde65ccc3d48d3f86c299269ce6019af1dfe3d2f6f172aff5ae7d7ef8f49ca69de189dcd721d5c9d48269f
7
- data.tar.gz: 85b9b4834a91e7fab98ee9f555461cee740bebcbcee3e0efffc9d117d1b8dce6f9967db594225cd32a3d82462b5edc2d6e4c77bb4ef799d6253f3e66f4f88042
6
+ metadata.gz: e81da702b50b15939c310e1f24b1410bfed9d29364aeaa1972e97c1faf34102853531ee55897358a43914b49351d7a1d213d888b302a24c3d1f779b26bf4d310
7
+ data.tar.gz: bf2139f49455edc3a076a4e2eefd7db7a2b8be46038638f1fc7203f378cffb49317044d0ad51af172b74c3fce163c5a8b8d85c5c99ee8227137475c0632b614a
data/CONTRIBUTING.md CHANGED
@@ -13,3 +13,20 @@ Here are some reasons why a pull request may not be merged:
13
13
  If you would like to help in this process, you can start by evaluating open pull requests against the criteria above. For example, if a pull request does not include specs for new functionality, you can add a comment like: “If you would like this feature to be added to Thor, please add specs to ensure that it does not break in the future.” This will help move a pull request closer to being merged.
14
14
 
15
15
  Include this emoji in the top of your ticket to signal to us that you read this file: 🌈
16
+
17
+ Specs
18
+ -----
19
+
20
+ Ensure that all specs and code linting checks pass before submitting a pull request.
21
+
22
+ To execute the specs locally, run:
23
+
24
+ ```bash
25
+ bundle exec rspec
26
+ ```
27
+
28
+ Linting checks are done with RuboCop. To run the linter, use:
29
+
30
+ ```bash
31
+ bundle exec rubocop
32
+ ```
data/README.md CHANGED
@@ -27,10 +27,9 @@ 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 check out the [official homepage][homepage].
30
+ Please see the [wiki][] for basic usage and other documentation on using Thor.
31
31
 
32
32
  [wiki]: https://github.com/rails/thor/wiki
33
- [homepage]: http://whatisthor.com/
34
33
 
35
34
  Contributing
36
35
  ------------
@@ -242,6 +242,35 @@ class Thor
242
242
  insert_into_file(path, *(args << config), &block)
243
243
  end
244
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
+
245
274
  # Run a regular expression replacement on a file.
246
275
  #
247
276
  # ==== Parameters
@@ -267,11 +296,7 @@ class Thor
267
296
  path = File.expand_path(path, destination_root)
268
297
  say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
269
298
 
270
- unless options[:pretend]
271
- content = File.binread(path)
272
- content.gsub!(flag, *args, &block)
273
- File.open(path, "wb") { |file| file.write(content) }
274
- end
299
+ actually_gsub_file(path, flag, args, false, &block) unless options[:pretend]
275
300
  end
276
301
 
277
302
  # Uncomment all lines matching a given regex. Preserves indentation before
@@ -348,7 +373,7 @@ class Thor
348
373
  end
349
374
 
350
375
  def with_output_buffer(buf = "".dup) #:nodoc:
351
- raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen?
376
+ raise ArgumentError, "Buffer cannot be a frozen object" if buf.frozen?
352
377
  old_buffer = output_buffer
353
378
  self.output_buffer = buf
354
379
  yield
@@ -357,6 +382,17 @@ class Thor
357
382
  self.output_buffer = old_buffer
358
383
  end
359
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
+
360
396
  # Thor::Actions#capture depends on what kind of buffer is used in ERB.
361
397
  # Thus CapturableERB fixes ERB to use String buffer.
362
398
  class CapturableERB < ERB
@@ -2,6 +2,38 @@ require_relative "empty_directory"
2
2
 
3
3
  class Thor
4
4
  module Actions
5
+ WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
6
+
7
+ # Injects the given content into a file, raising an error if the contents of
8
+ # the file are not changed. Different from gsub_file, this method is reversible.
9
+ #
10
+ # ==== Parameters
11
+ # destination<String>:: Relative path to the destination root
12
+ # data<String>:: Data to add to the file. Can be given as a block.
13
+ # config<Hash>:: give :verbose => false to not log the status and the flag
14
+ # for injection (:after or :before) or :force => true for
15
+ # insert two or more times the same content.
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
20
+ #
21
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
22
+ # gems = ask "Which gems would you like to add?"
23
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
24
+ # end
25
+ #
26
+ def insert_into_file!(destination, *args, &block)
27
+ data = block_given? ? block : args.shift
28
+
29
+ config = args.shift || {}
30
+ config[:after] = /\z/ unless config.key?(:before) || config.key?(:after)
31
+ config = config.merge({error_on_no_change: true})
32
+
33
+ action InjectIntoFile.new(self, destination, data, config)
34
+ end
35
+ alias_method :inject_into_file!, :insert_into_file!
36
+
5
37
  # Injects the given content into a file. Different from gsub_file, this
6
38
  # method is reversible.
7
39
  #
@@ -21,8 +53,6 @@ class Thor
21
53
  # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
22
54
  # end
23
55
  #
24
- WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
25
-
26
56
  def insert_into_file(destination, *args, &block)
27
57
  data = block_given? ? block : args.shift
28
58
 
@@ -47,6 +77,7 @@ class Thor
47
77
 
48
78
  @replacement = data.is_a?(Proc) ? data.call : data
49
79
  @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
80
+ @error_on_no_change = @config.fetch(:error_on_no_change, false)
50
81
  end
51
82
 
52
83
  def invoke!
@@ -59,6 +90,8 @@ class Thor
59
90
  if exists?
60
91
  if replace!(/#{flag}/, content, config[:force])
61
92
  say_status(:invoke)
93
+ elsif @error_on_no_change
94
+ raise Thor::Error, "The content of #{destination} did not change"
62
95
  elsif replacement_present?
63
96
  say_status(:unchanged, color: :blue)
64
97
  else
data/lib/thor/base.rb CHANGED
@@ -13,8 +13,9 @@ class Thor
13
13
  autoload :RakeCompat, File.expand_path("rake_compat", __dir__)
14
14
  autoload :Group, File.expand_path("group", __dir__)
15
15
 
16
- # Shortcuts for help.
16
+ # Shortcuts for help and tree commands.
17
17
  HELP_MAPPINGS = %w(-h -? --help -D)
18
+ TREE_MAPPINGS = %w(-t --tree)
18
19
 
19
20
  # Thor methods that should not be overwritten by the user.
20
21
  THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
@@ -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 diffrence of argument array size will decrease.
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}'"}
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
@@ -311,13 +311,11 @@ class Thor
311
311
  end
312
312
 
313
313
  def show_diff(destination, content) #:nodoc:
314
- diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
315
-
316
314
  require "tempfile"
317
- Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
315
+ Tempfile.open(File.basename(destination), File.dirname(destination), binmode: true) do |temp|
318
316
  temp.write content
319
317
  temp.rewind
320
- system %(#{diff_cmd} "#{destination}" "#{temp.path}")
318
+ system(*diff_tool, destination, temp.path)
321
319
  end
322
320
  end
323
321
 
@@ -369,19 +367,25 @@ class Thor
369
367
 
370
368
  def merge(destination, content) #:nodoc:
371
369
  require "tempfile"
372
- Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
370
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination), binmode: true) do |temp|
373
371
  temp.write content
374
372
  temp.rewind
375
- system %(#{merge_tool} "#{temp.path}" "#{destination}")
373
+ system(*merge_tool, temp.path, destination)
376
374
  end
377
375
  end
378
376
 
379
377
  def merge_tool #:nodoc:
380
- @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
378
+ @merge_tool ||= begin
379
+ require "shellwords"
380
+ Shellwords.split(ENV["THOR_MERGE"] || "git difftool --no-index")
381
+ end
381
382
  end
382
383
 
383
- def git_merge_tool #:nodoc:
384
- `git config merge.tool`.rstrip rescue ""
384
+ def diff_tool #:nodoc:
385
+ @diff_cmd ||= begin
386
+ require "shellwords"
387
+ Shellwords.split(ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u")
388
+ end
385
389
  end
386
390
  end
387
391
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "basic"
2
4
  require_relative "lcs_diff"
3
5
 
data/lib/thor/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "1.3.2"
2
+ VERSION = "1.5.0"
3
3
  end
data/lib/thor.rb CHANGED
@@ -625,7 +625,7 @@ class Thor
625
625
  # alias name.
626
626
  def find_command_possibilities(meth)
627
627
  len = meth.to_s.length
628
- possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
628
+ possibilities = all_commands.reject {|k, v| v.is_a?(HiddenCommand) }.merge(map).keys.select { |n| meth == n[0, len] }.sort
629
629
  unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
630
630
 
631
631
  if possibilities.include?(meth)
@@ -671,4 +671,37 @@ class Thor
671
671
  self.class.help(shell, subcommand)
672
672
  end
673
673
  end
674
+
675
+ map TREE_MAPPINGS => :tree
676
+
677
+ desc "tree", "Print a tree of all available commands"
678
+ def tree
679
+ build_command_tree(self.class, "")
680
+ end
681
+
682
+ private
683
+
684
+ def build_command_tree(klass, indent)
685
+ # Print current class name if it's not the root Thor class
686
+ unless klass == Thor
687
+ say "#{indent}#{klass.namespace || 'default'}", :blue
688
+ indent = "#{indent} "
689
+ end
690
+
691
+ # Print all commands for this class
692
+ visible_commands = klass.commands.reject { |_, cmd| cmd.hidden? || cmd.name == "help" }
693
+ commands_count = visible_commands.count
694
+ visible_commands.sort.each_with_index do |(command_name, command), i|
695
+ description = command.description.split("\n").first || ""
696
+ icon = i == (commands_count - 1) ? "└─" : "├─"
697
+ say "#{indent}#{icon} ", nil, false
698
+ say command_name, :green, false
699
+ say " (#{description})" unless description.empty?
700
+ end
701
+
702
+ # Print all subcommands (from registered Thor subclasses)
703
+ klass.subcommand_classes.each do |_, subclass|
704
+ build_command_tree(subclass, indent)
705
+ end
706
+ end
674
707
  end
data/thor.gemspec CHANGED
@@ -9,14 +9,14 @@ Gem::Specification.new do |spec|
9
9
  spec.licenses = %w(MIT)
10
10
  spec.authors = ["Yehuda Katz", "José Valim"]
11
11
  spec.email = "ruby-thor@googlegroups.com"
12
- spec.homepage = "http://whatisthor.com/"
12
+ spec.homepage = "https://github.com/rails/thor"
13
13
  spec.description = "Thor is a toolkit for building powerful command-line interfaces."
14
14
  spec.summary = spec.description
15
15
 
16
16
  spec.metadata = {
17
17
  "bug_tracker_uri" => "https://github.com/rails/thor/issues",
18
18
  "changelog_uri" => "https://github.com/rails/thor/releases/tag/v#{Thor::VERSION}",
19
- "documentation_uri" => "http://whatisthor.com/",
19
+ "documentation_uri" => "https://github.com/rails/thor/wiki",
20
20
  "source_code_uri" => "https://github.com/rails/thor/tree/v#{Thor::VERSION}",
21
21
  "wiki_uri" => "https://github.com/rails/thor/wiki",
22
22
  "rubygems_mfa_required" => "true",
@@ -29,5 +29,5 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = %w(thor)
30
30
  spec.require_paths = %w(lib)
31
31
 
32
- spec.add_development_dependency "bundler", ">= 1.0", "< 3"
32
+ spec.add_development_dependency "bundler", ">= 1.0"
33
33
  end
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.3.2
4
+ version: 1.5.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: 2024-08-29 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -18,9 +17,6 @@ dependencies:
18
17
  - - ">="
19
18
  - !ruby/object:Gem::Version
20
19
  version: '1.0'
21
- - - "<"
22
- - !ruby/object:Gem::Version
23
- version: '3'
24
20
  type: :development
25
21
  prerelease: false
26
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,9 +24,6 @@ dependencies:
28
24
  - - ">="
29
25
  - !ruby/object:Gem::Version
30
26
  version: '1.0'
31
- - - "<"
32
- - !ruby/object:Gem::Version
33
- version: '3'
34
27
  description: Thor is a toolkit for building powerful command-line interfaces.
35
28
  email: ruby-thor@googlegroups.com
36
29
  executables:
@@ -80,17 +73,16 @@ files:
80
73
  - lib/thor/util.rb
81
74
  - lib/thor/version.rb
82
75
  - thor.gemspec
83
- homepage: http://whatisthor.com/
76
+ homepage: https://github.com/rails/thor
84
77
  licenses:
85
78
  - MIT
86
79
  metadata:
87
80
  bug_tracker_uri: https://github.com/rails/thor/issues
88
- changelog_uri: https://github.com/rails/thor/releases/tag/v1.3.2
89
- documentation_uri: http://whatisthor.com/
90
- source_code_uri: https://github.com/rails/thor/tree/v1.3.2
81
+ changelog_uri: https://github.com/rails/thor/releases/tag/v1.5.0
82
+ documentation_uri: https://github.com/rails/thor/wiki
83
+ source_code_uri: https://github.com/rails/thor/tree/v1.5.0
91
84
  wiki_uri: https://github.com/rails/thor/wiki
92
85
  rubygems_mfa_required: 'true'
93
- post_install_message:
94
86
  rdoc_options: []
95
87
  require_paths:
96
88
  - lib
@@ -105,8 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
97
  - !ruby/object:Gem::Version
106
98
  version: 1.3.5
107
99
  requirements: []
108
- rubygems_version: 3.5.11
109
- signing_key:
100
+ rubygems_version: 3.6.7
110
101
  specification_version: 4
111
102
  summary: Thor is a toolkit for building powerful command-line interfaces.
112
103
  test_files: []