thor 0.16.0 → 1.2.1

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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +15 -0
  3. data/README.md +23 -6
  4. data/bin/thor +1 -1
  5. data/lib/thor/actions/create_file.rb +34 -35
  6. data/lib/thor/actions/create_link.rb +9 -5
  7. data/lib/thor/actions/directory.rb +33 -23
  8. data/lib/thor/actions/empty_directory.rb +75 -85
  9. data/lib/thor/actions/file_manipulation.rb +103 -36
  10. data/lib/thor/actions/inject_into_file.rb +46 -36
  11. data/lib/thor/actions.rb +90 -68
  12. data/lib/thor/base.rb +302 -244
  13. data/lib/thor/command.rb +142 -0
  14. data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
  15. data/lib/thor/error.rb +90 -10
  16. data/lib/thor/group.rb +70 -74
  17. data/lib/thor/invocation.rb +63 -55
  18. data/lib/thor/line_editor/basic.rb +37 -0
  19. data/lib/thor/line_editor/readline.rb +88 -0
  20. data/lib/thor/line_editor.rb +17 -0
  21. data/lib/thor/nested_context.rb +29 -0
  22. data/lib/thor/parser/argument.rb +24 -28
  23. data/lib/thor/parser/arguments.rb +110 -102
  24. data/lib/thor/parser/option.rb +53 -15
  25. data/lib/thor/parser/options.rb +174 -97
  26. data/lib/thor/parser.rb +4 -4
  27. data/lib/thor/rake_compat.rb +12 -11
  28. data/lib/thor/runner.rb +159 -155
  29. data/lib/thor/shell/basic.rb +216 -93
  30. data/lib/thor/shell/color.rb +53 -40
  31. data/lib/thor/shell/html.rb +61 -58
  32. data/lib/thor/shell.rb +29 -36
  33. data/lib/thor/util.rb +231 -213
  34. data/lib/thor/version.rb +1 -1
  35. data/lib/thor.rb +303 -166
  36. data/thor.gemspec +27 -24
  37. metadata +36 -226
  38. data/.gitignore +0 -44
  39. data/.rspec +0 -2
  40. data/.travis.yml +0 -7
  41. data/CHANGELOG.rdoc +0 -134
  42. data/Gemfile +0 -15
  43. data/Thorfile +0 -30
  44. data/bin/rake2thor +0 -86
  45. data/lib/thor/core_ext/dir_escape.rb +0 -0
  46. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  47. data/lib/thor/core_ext/ordered_hash.rb +0 -100
  48. data/lib/thor/task.rb +0 -132
  49. data/spec/actions/create_file_spec.rb +0 -170
  50. data/spec/actions/create_link_spec.rb +0 -81
  51. data/spec/actions/directory_spec.rb +0 -149
  52. data/spec/actions/empty_directory_spec.rb +0 -130
  53. data/spec/actions/file_manipulation_spec.rb +0 -370
  54. data/spec/actions/inject_into_file_spec.rb +0 -135
  55. data/spec/actions_spec.rb +0 -331
  56. data/spec/base_spec.rb +0 -279
  57. data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
  58. data/spec/core_ext/ordered_hash_spec.rb +0 -115
  59. data/spec/exit_condition_spec.rb +0 -19
  60. data/spec/fixtures/application.rb +0 -2
  61. data/spec/fixtures/app{1}/README +0 -3
  62. data/spec/fixtures/bundle/execute.rb +0 -6
  63. data/spec/fixtures/bundle/main.thor +0 -1
  64. data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
  65. data/spec/fixtures/doc/COMMENTER +0 -10
  66. data/spec/fixtures/doc/README +0 -3
  67. data/spec/fixtures/doc/block_helper.rb +0 -3
  68. data/spec/fixtures/doc/components/.empty_directory +0 -0
  69. data/spec/fixtures/doc/config.rb +0 -1
  70. data/spec/fixtures/doc/config.yaml.tt +0 -1
  71. data/spec/fixtures/enum.thor +0 -10
  72. data/spec/fixtures/group.thor +0 -114
  73. data/spec/fixtures/invoke.thor +0 -112
  74. data/spec/fixtures/path with spaces +0 -0
  75. data/spec/fixtures/script.thor +0 -190
  76. data/spec/fixtures/task.thor +0 -10
  77. data/spec/group_spec.rb +0 -216
  78. data/spec/invocation_spec.rb +0 -100
  79. data/spec/parser/argument_spec.rb +0 -53
  80. data/spec/parser/arguments_spec.rb +0 -66
  81. data/spec/parser/option_spec.rb +0 -202
  82. data/spec/parser/options_spec.rb +0 -330
  83. data/spec/rake_compat_spec.rb +0 -72
  84. data/spec/register_spec.rb +0 -135
  85. data/spec/runner_spec.rb +0 -241
  86. data/spec/shell/basic_spec.rb +0 -300
  87. data/spec/shell/color_spec.rb +0 -81
  88. data/spec/shell/html_spec.rb +0 -32
  89. data/spec/shell_spec.rb +0 -47
  90. data/spec/spec_helper.rb +0 -59
  91. data/spec/task_spec.rb +0 -80
  92. data/spec/thor_spec.rb +0 -418
  93. data/spec/util_spec.rb +0 -196
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 30e79d2b0a96e87c8e6348467db577c6ad1e9acbbbac5d375417bc3e5a2b7698
4
+ data.tar.gz: 701f1ab842da90e599b96bd00d90481d716eb29e39e0283b5ff527c2033fc742
5
+ SHA512:
6
+ metadata.gz: 73b1ac80575d4422204cd8072950b5594739db3b6f3fde0f2f04359d51b1d4428524d25b9a3003ae9ec3f6be615cf635f3057bbc65558e6a17ba490ff045988b
7
+ data.tar.gz: eb7761a5e6f3674cb3231398145978b0eb53a6fa2c10e4cb9e99d8d523988efcefc8cae5dd163b8a3d6ead7424422d58b92311c200790ad6e2416e3f9757a90e
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,15 @@
1
+ Pull Requests
2
+ -------------
3
+ Here are some reasons why a pull request may not be merged:
4
+
5
+ 1. It hasn’t been reviewed.
6
+ 2. It doesn’t include specs for new functionality.
7
+ 3. It doesn’t include documentation for new functionality.
8
+ 4. It changes behavior without changing the relevant documentation, comments, or specs.
9
+ 5. It changes behavior of an existing public API, breaking backward compatibility.
10
+ 6. It breaks the tests on a supported platform.
11
+ 7. It doesn’t merge cleanly (requiring Git rebasing and conflict resolution).
12
+
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
+
15
+ Include this emoji in the top of your ticket to signal to us that you read this file: 🌈
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
- [![Build Status](https://secure.travis-ci.org/wycats/thor.png?branch=master)](http://travis-ci.org/wycats/thor)
2
-
3
1
  Thor
4
2
  ====
5
3
 
4
+ [![Gem Version](http://img.shields.io/gem/v/thor.svg)][gem]
5
+
6
+ [gem]: https://rubygems.org/gems/thor
7
+
6
8
  Description
7
9
  -----------
8
10
  Thor is a simple and efficient tool for building self-documenting command line
@@ -11,7 +13,13 @@ utilities. It removes the pain of parsing command line options, writing
11
13
  build tool. The syntax is Rake-like, so it should be familiar to most Rake
12
14
  users.
13
15
 
14
- [rake]: https://github.com/jimweirich/rake
16
+ Please note: Thor, by design, is a system tool created to allow seamless file and url
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
19
+ vector.
20
+
21
+ [rake]: https://github.com/ruby/rake
22
+ [open-uri]: https://ruby-doc.org/stdlib-2.5.1/libdoc/open-uri/rdoc/index.html
15
23
 
16
24
  Installation
17
25
  ------------
@@ -19,10 +27,19 @@ Installation
19
27
 
20
28
  Usage and documentation
21
29
  -----------------------
22
- Please see [the wiki](https://github.com/wycats/thor/wiki) for basic usage and other documentation on using Thor.
30
+ Please see the [wiki][] for basic usage and other documentation on using Thor. You can also checkout the [official homepage][homepage].
31
+
32
+ [wiki]: https://github.com/rails/thor/wiki
33
+ [homepage]: http://whatisthor.com/
34
+
35
+ Contributing
36
+ ------------
37
+ If you would like to help, please read the [CONTRIBUTING][] file for suggestions.
38
+
39
+ [contributing]: CONTRIBUTING.md
23
40
 
24
41
  License
25
42
  -------
26
- Released under the MIT License. See the [LICENSE][license] file for further details.
43
+ Released under the MIT License. See the [LICENSE][] file for further details.
27
44
 
28
- [license]: https://github.com/wycats/thor/blob/master/LICENSE.md
45
+ [license]: LICENSE.md
data/bin/thor CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- mode: ruby -*-
3
3
 
4
- require 'thor/runner'
4
+ require "thor/runner"
5
5
  $thor_runner = true
6
6
  Thor::Runner.start
@@ -1,8 +1,7 @@
1
- require 'thor/actions/empty_directory'
1
+ require_relative "empty_directory"
2
2
 
3
3
  class Thor
4
4
  module Actions
5
-
6
5
  # Create a new file relative to the destination root with the given data,
7
6
  # which is the return value of a block or a data string.
8
7
  #
@@ -25,7 +24,7 @@ class Thor
25
24
  data = args.first
26
25
  action CreateFile.new(self, destination, block || data.to_s, config)
27
26
  end
28
- alias :add_file :create_file
27
+ alias_method :add_file, :create_file
29
28
 
30
29
  # CreateFile is a subset of Template, which instead of rendering a file with
31
30
  # ERB, it gets the content from the user.
@@ -33,7 +32,7 @@ class Thor
33
32
  class CreateFile < EmptyDirectory #:nodoc:
34
33
  attr_reader :data
35
34
 
36
- def initialize(base, destination, data, config={})
35
+ def initialize(base, destination, data, config = {})
37
36
  @data = data
38
37
  super(base, destination, config)
39
38
  end
@@ -59,47 +58,47 @@ class Thor
59
58
 
60
59
  def invoke!
61
60
  invoke_with_conflict_check do
61
+ require "fileutils"
62
62
  FileUtils.mkdir_p(File.dirname(destination))
63
- File.open(destination, 'wb') { |f| f.write render }
63
+ File.open(destination, "wb") { |f| f.write render }
64
64
  end
65
65
  given_destination
66
66
  end
67
67
 
68
- protected
69
-
70
- # Now on conflict we check if the file is identical or not.
71
- #
72
- def on_conflict_behavior(&block)
73
- if identical?
74
- say_status :identical, :blue
75
- else
76
- options = base.options.merge(config)
77
- force_or_skip_or_conflict(options[:force], options[:skip], &block)
78
- end
79
- end
68
+ protected
80
69
 
81
- # If force is true, run the action, otherwise check if it's not being
82
- # skipped. If both are false, show the file_collision menu, if the menu
83
- # returns true, force it, otherwise skip.
84
- #
85
- def force_or_skip_or_conflict(force, skip, &block)
86
- if force
87
- say_status :force, :yellow
88
- block.call unless pretend?
89
- elsif skip
90
- say_status :skip, :yellow
91
- else
92
- say_status :conflict, :red
93
- force_or_skip_or_conflict(force_on_collision?, true, &block)
94
- end
70
+ # Now on conflict we check if the file is identical or not.
71
+ #
72
+ def on_conflict_behavior(&block)
73
+ if identical?
74
+ say_status :identical, :blue
75
+ else
76
+ options = base.options.merge(config)
77
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
95
78
  end
79
+ end
96
80
 
97
- # Shows the file collision menu to the user and gets the result.
98
- #
99
- def force_on_collision?
100
- base.shell.file_collision(destination){ render }
81
+ # If force is true, run the action, otherwise check if it's not being
82
+ # skipped. If both are false, show the file_collision menu, if the menu
83
+ # returns true, force it, otherwise skip.
84
+ #
85
+ def force_or_skip_or_conflict(force, skip, &block)
86
+ if force
87
+ say_status :force, :yellow
88
+ yield unless pretend?
89
+ elsif skip
90
+ say_status :skip, :yellow
91
+ else
92
+ say_status :conflict, :red
93
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
101
94
  end
95
+ end
102
96
 
97
+ # Shows the file collision menu to the user and gets the result.
98
+ #
99
+ def force_on_collision?
100
+ base.shell.file_collision(destination) { render }
101
+ end
103
102
  end
104
103
  end
105
104
  end
@@ -1,8 +1,7 @@
1
- require 'thor/actions/create_file'
1
+ require_relative "create_file"
2
2
 
3
3
  class Thor
4
4
  module Actions
5
-
6
5
  # Create a new file relative to the destination root from the given source.
7
6
  #
8
7
  # ==== Parameters
@@ -15,12 +14,12 @@ class Thor
15
14
  #
16
15
  # create_link "config/apache.conf", "/etc/apache.conf"
17
16
  #
18
- def create_link(destination, *args, &block)
17
+ def create_link(destination, *args)
19
18
  config = args.last.is_a?(Hash) ? args.pop : {}
20
19
  source = args.first
21
20
  action CreateLink.new(self, destination, source, config)
22
21
  end
23
- alias :add_link :create_link
22
+ alias_method :add_link, :create_link
24
23
 
25
24
  # CreateLink is a subset of CreateFile, which instead of taking a block of
26
25
  # data, just takes a source string from the user.
@@ -34,11 +33,13 @@ class Thor
34
33
  # Boolean:: true if it is identical, false otherwise.
35
34
  #
36
35
  def identical?
37
- exists? && File.identical?(render, destination)
36
+ source = File.expand_path(render, File.dirname(destination))
37
+ exists? && File.identical?(source, destination)
38
38
  end
39
39
 
40
40
  def invoke!
41
41
  invoke_with_conflict_check do
42
+ require "fileutils"
42
43
  FileUtils.mkdir_p(File.dirname(destination))
43
44
  # Create a symlink by default
44
45
  config[:symbolic] = true if config[:symbolic].nil?
@@ -52,6 +53,9 @@ class Thor
52
53
  given_destination
53
54
  end
54
55
 
56
+ def exists?
57
+ super || File.symlink?(destination)
58
+ end
55
59
  end
56
60
  end
57
61
  end
@@ -1,4 +1,4 @@
1
- require 'thor/actions/empty_directory'
1
+ require_relative "empty_directory"
2
2
 
3
3
  class Thor
4
4
  module Actions
@@ -38,6 +38,8 @@ class Thor
38
38
  # destination<String>:: the relative path to the destination root.
39
39
  # config<Hash>:: give :verbose => false to not log the status.
40
40
  # If :recursive => false, does not look for paths recursively.
41
+ # If :mode => :preserve, preserve the file mode from the source.
42
+ # If :exclude_pattern => /regexp/, prevents copying files that match that regexp.
41
43
  #
42
44
  # ==== Examples
43
45
  #
@@ -53,10 +55,10 @@ class Thor
53
55
  class Directory < EmptyDirectory #:nodoc:
54
56
  attr_reader :source
55
57
 
56
- def initialize(base, source, destination=nil, config={}, &block)
57
- @source = File.expand_path(base.find_in_source_paths(source.to_s))
58
+ def initialize(base, source, destination = nil, config = {}, &block)
59
+ @source = File.expand_path(Dir[Util.escape_globs(base.find_in_source_paths(source.to_s))].first)
58
60
  @block = block
59
- super(base, destination, { :recursive => true }.merge(config))
61
+ super(base, destination, {:recursive => true}.merge(config))
60
62
  end
61
63
 
62
64
  def invoke!
@@ -68,31 +70,39 @@ class Thor
68
70
  execute!
69
71
  end
70
72
 
71
- protected
73
+ protected
72
74
 
73
- def execute!
74
- lookup = Util.escape_globs(source)
75
- lookup = config[:recursive] ? File.join(lookup, '**') : lookup
76
- lookup = File.join(lookup, '{*,.[a-z]*}')
75
+ def execute!
76
+ lookup = Util.escape_globs(source)
77
+ lookup = config[:recursive] ? File.join(lookup, "**") : lookup
78
+ lookup = file_level_lookup(lookup)
77
79
 
78
- Dir[lookup].sort.each do |file_source|
79
- next if File.directory?(file_source)
80
- file_destination = File.join(given_destination, file_source.gsub(source, '.'))
81
- file_destination.gsub!('/./', '/')
80
+ files(lookup).sort.each do |file_source|
81
+ next if File.directory?(file_source)
82
+ next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern])
83
+ file_destination = File.join(given_destination, file_source.gsub(source, "."))
84
+ file_destination.gsub!("/./", "/")
82
85
 
83
- case file_source
84
- when /\.empty_directory$/
85
- dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
86
- next if dirname == given_destination
87
- base.empty_directory(dirname, config)
88
- when /\.tt$/
89
- destination = base.template(file_source, file_destination[0..-4], config, &@block)
90
- else
91
- destination = base.copy_file(file_source, file_destination, config, &@block)
92
- end
86
+ case file_source
87
+ when /\.empty_directory$/
88
+ dirname = File.dirname(file_destination).gsub(%r{/\.$}, "")
89
+ next if dirname == given_destination
90
+ base.empty_directory(dirname, config)
91
+ when /#{TEMPLATE_EXTNAME}$/
92
+ base.template(file_source, file_destination[0..-4], config, &@block)
93
+ else
94
+ base.copy_file(file_source, file_destination, config, &@block)
93
95
  end
94
96
  end
97
+ end
98
+
99
+ def file_level_lookup(previous_lookup)
100
+ File.join(previous_lookup, "*")
101
+ end
95
102
 
103
+ def files(lookup)
104
+ Dir.glob(lookup, File::FNM_DOTMATCH)
105
+ end
96
106
  end
97
107
  end
98
108
  end
@@ -1,6 +1,5 @@
1
1
  class Thor
2
2
  module Actions
3
-
4
3
  # Creates an empty directory.
5
4
  #
6
5
  # ==== Parameters
@@ -11,7 +10,7 @@ class Thor
11
10
  #
12
11
  # empty_directory "doc"
13
12
  #
14
- def empty_directory(destination, config={})
13
+ def empty_directory(destination, config = {})
15
14
  action EmptyDirectory.new(self, destination, config)
16
15
  end
17
16
 
@@ -32,8 +31,9 @@ class Thor
32
31
  # destination<String>:: Relative path to the destination of this file
33
32
  # config<Hash>:: give :verbose => false to not log the status.
34
33
  #
35
- def initialize(base, destination, config={})
36
- @base, @config = base, { :verbose => true }.merge(config)
34
+ def initialize(base, destination, config = {})
35
+ @base = base
36
+ @config = {:verbose => true}.merge(config)
37
37
  self.destination = destination
38
38
  end
39
39
 
@@ -43,111 +43,101 @@ class Thor
43
43
  # Boolean:: true if the file exists, false otherwise.
44
44
  #
45
45
  def exists?
46
- ::File.exists?(destination)
46
+ ::File.exist?(destination)
47
47
  end
48
48
 
49
49
  def invoke!
50
50
  invoke_with_conflict_check do
51
+ require "fileutils"
51
52
  ::FileUtils.mkdir_p(destination)
52
53
  end
53
54
  end
54
55
 
55
56
  def revoke!
56
57
  say_status :remove, :red
58
+ require "fileutils"
57
59
  ::FileUtils.rm_rf(destination) if !pretend? && exists?
58
60
  given_destination
59
61
  end
60
62
 
61
- protected
63
+ protected
62
64
 
63
- # Shortcut for pretend.
64
- #
65
- def pretend?
66
- base.options[:pretend]
67
- end
65
+ # Shortcut for pretend.
66
+ #
67
+ def pretend?
68
+ base.options[:pretend]
69
+ end
68
70
 
69
- # Sets the absolute destination value from a relative destination value.
70
- # It also stores the given and relative destination. Let's suppose our
71
- # script is being executed on "dest", it sets the destination root to
72
- # "dest". The destination, given_destination and relative_destination
73
- # are related in the following way:
74
- #
75
- # inside "bar" do
76
- # empty_directory "baz"
77
- # end
78
- #
79
- # destination #=> dest/bar/baz
80
- # relative_destination #=> bar/baz
81
- # given_destination #=> baz
82
- #
83
- def destination=(destination)
84
- if destination
85
- @given_destination = convert_encoded_instructions(destination.to_s)
86
- @destination = ::File.expand_path(@given_destination, base.destination_root)
87
- @relative_destination = base.relative_to_original_destination_root(@destination)
88
- end
89
- end
71
+ # Sets the absolute destination value from a relative destination value.
72
+ # It also stores the given and relative destination. Let's suppose our
73
+ # script is being executed on "dest", it sets the destination root to
74
+ # "dest". The destination, given_destination and relative_destination
75
+ # are related in the following way:
76
+ #
77
+ # inside "bar" do
78
+ # empty_directory "baz"
79
+ # end
80
+ #
81
+ # destination #=> dest/bar/baz
82
+ # relative_destination #=> bar/baz
83
+ # given_destination #=> baz
84
+ #
85
+ def destination=(destination)
86
+ return unless destination
87
+ @given_destination = convert_encoded_instructions(destination.to_s)
88
+ @destination = ::File.expand_path(@given_destination, base.destination_root)
89
+ @relative_destination = base.relative_to_original_destination_root(@destination)
90
+ end
90
91
 
91
- # Filenames in the encoded form are converted. If you have a file:
92
- #
93
- # %file_name%.rb
94
- #
95
- # It calls #file_name from the base and replaces %-string with the
96
- # return value (should be String) of #file_name:
97
- #
98
- # user.rb
99
- #
100
- # The method referenced by %-string SHOULD be public. Otherwise you
101
- # get the exception with the corresponding error message.
102
- #
103
- def convert_encoded_instructions(filename)
104
- filename.gsub(/%(.*?)%/) do |initial_string|
105
- call_public_method($1.strip) or initial_string
106
- end
92
+ # Filenames in the encoded form are converted. If you have a file:
93
+ #
94
+ # %file_name%.rb
95
+ #
96
+ # It calls #file_name from the base and replaces %-string with the
97
+ # return value (should be String) of #file_name:
98
+ #
99
+ # user.rb
100
+ #
101
+ # The method referenced can be either public or private.
102
+ #
103
+ def convert_encoded_instructions(filename)
104
+ filename.gsub(/%(.*?)%/) do |initial_string|
105
+ method = $1.strip
106
+ base.respond_to?(method, true) ? base.send(method) : initial_string
107
107
  end
108
+ end
108
109
 
109
- # Calls `base`'s public method `sym`.
110
- # Returns:: result of `base.sym` or `nil` if `sym` wasn't found in
111
- # `base`
112
- # Raises:: Thor::PrivateMethodEncodedError if `sym` references
113
- # a private method.
114
- def call_public_method(sym)
115
- if base.respond_to?(sym)
116
- base.send(sym)
117
- elsif base.respond_to?(sym, true)
118
- raise Thor::PrivateMethodEncodedError,
119
- "Method #{base.class}##{sym} should be public, not private"
120
- else
121
- nil
122
- end
110
+ # Receives a hash of options and just execute the block if some
111
+ # conditions are met.
112
+ #
113
+ def invoke_with_conflict_check(&block)
114
+ if exists?
115
+ on_conflict_behavior(&block)
116
+ else
117
+ yield unless pretend?
118
+ say_status :create, :green
123
119
  end
124
120
 
125
- # Receives a hash of options and just execute the block if some
126
- # conditions are met.
127
- #
128
- def invoke_with_conflict_check(&block)
129
- if exists?
130
- on_conflict_behavior(&block)
131
- else
132
- say_status :create, :green
133
- block.call unless pretend?
134
- end
135
-
136
- destination
137
- end
121
+ destination
122
+ rescue Errno::EISDIR, Errno::EEXIST
123
+ on_file_clash_behavior
124
+ end
138
125
 
139
- # What to do when the destination file already exists.
140
- #
141
- def on_conflict_behavior(&block)
142
- say_status :exist, :blue
143
- end
126
+ def on_file_clash_behavior
127
+ say_status :file_clash, :red
128
+ end
144
129
 
145
- # Shortcut to say_status shell method.
146
- #
147
- def say_status(status, color)
148
- base.shell.say_status status, relative_destination, color if config[:verbose]
149
- end
130
+ # What to do when the destination file already exists.
131
+ #
132
+ def on_conflict_behavior
133
+ say_status :exist, :blue
134
+ end
150
135
 
136
+ # Shortcut to say_status shell method.
137
+ #
138
+ def say_status(status, color)
139
+ base.shell.say_status status, relative_destination, color if config[:verbose]
140
+ end
151
141
  end
152
142
  end
153
143
  end