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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +15 -0
- data/README.md +23 -6
- data/bin/thor +1 -1
- data/lib/thor/actions/create_file.rb +34 -35
- data/lib/thor/actions/create_link.rb +9 -5
- data/lib/thor/actions/directory.rb +33 -23
- data/lib/thor/actions/empty_directory.rb +75 -85
- data/lib/thor/actions/file_manipulation.rb +103 -36
- data/lib/thor/actions/inject_into_file.rb +46 -36
- data/lib/thor/actions.rb +90 -68
- data/lib/thor/base.rb +302 -244
- data/lib/thor/command.rb +142 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
- data/lib/thor/error.rb +90 -10
- data/lib/thor/group.rb +70 -74
- data/lib/thor/invocation.rb +63 -55
- data/lib/thor/line_editor/basic.rb +37 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/nested_context.rb +29 -0
- data/lib/thor/parser/argument.rb +24 -28
- data/lib/thor/parser/arguments.rb +110 -102
- data/lib/thor/parser/option.rb +53 -15
- data/lib/thor/parser/options.rb +174 -97
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +12 -11
- data/lib/thor/runner.rb +159 -155
- data/lib/thor/shell/basic.rb +216 -93
- data/lib/thor/shell/color.rb +53 -40
- data/lib/thor/shell/html.rb +61 -58
- data/lib/thor/shell.rb +29 -36
- data/lib/thor/util.rb +231 -213
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +303 -166
- data/thor.gemspec +27 -24
- metadata +36 -226
- data/.gitignore +0 -44
- data/.rspec +0 -2
- data/.travis.yml +0 -7
- data/CHANGELOG.rdoc +0 -134
- data/Gemfile +0 -15
- data/Thorfile +0 -30
- data/bin/rake2thor +0 -86
- data/lib/thor/core_ext/dir_escape.rb +0 -0
- data/lib/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/thor/core_ext/ordered_hash.rb +0 -100
- data/lib/thor/task.rb +0 -132
- data/spec/actions/create_file_spec.rb +0 -170
- data/spec/actions/create_link_spec.rb +0 -81
- data/spec/actions/directory_spec.rb +0 -149
- data/spec/actions/empty_directory_spec.rb +0 -130
- data/spec/actions/file_manipulation_spec.rb +0 -370
- data/spec/actions/inject_into_file_spec.rb +0 -135
- data/spec/actions_spec.rb +0 -331
- data/spec/base_spec.rb +0 -279
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
- data/spec/core_ext/ordered_hash_spec.rb +0 -115
- data/spec/exit_condition_spec.rb +0 -19
- data/spec/fixtures/application.rb +0 -2
- data/spec/fixtures/app{1}/README +0 -3
- data/spec/fixtures/bundle/execute.rb +0 -6
- data/spec/fixtures/bundle/main.thor +0 -1
- data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
- data/spec/fixtures/doc/COMMENTER +0 -10
- data/spec/fixtures/doc/README +0 -3
- data/spec/fixtures/doc/block_helper.rb +0 -3
- data/spec/fixtures/doc/components/.empty_directory +0 -0
- data/spec/fixtures/doc/config.rb +0 -1
- data/spec/fixtures/doc/config.yaml.tt +0 -1
- data/spec/fixtures/enum.thor +0 -10
- data/spec/fixtures/group.thor +0 -114
- data/spec/fixtures/invoke.thor +0 -112
- data/spec/fixtures/path with spaces +0 -0
- data/spec/fixtures/script.thor +0 -190
- data/spec/fixtures/task.thor +0 -10
- data/spec/group_spec.rb +0 -216
- data/spec/invocation_spec.rb +0 -100
- data/spec/parser/argument_spec.rb +0 -53
- data/spec/parser/arguments_spec.rb +0 -66
- data/spec/parser/option_spec.rb +0 -202
- data/spec/parser/options_spec.rb +0 -330
- data/spec/rake_compat_spec.rb +0 -72
- data/spec/register_spec.rb +0 -135
- data/spec/runner_spec.rb +0 -241
- data/spec/shell/basic_spec.rb +0 -300
- data/spec/shell/color_spec.rb +0 -81
- data/spec/shell/html_spec.rb +0 -32
- data/spec/shell_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -59
- data/spec/task_spec.rb +0 -80
- data/spec/thor_spec.rb +0 -418
- 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
|
-
[](http://travis-ci.org/wycats/thor)
|
2
|
-
|
3
1
|
Thor
|
4
2
|
====
|
5
3
|
|
4
|
+
[][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
|
-
|
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
|
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][
|
43
|
+
Released under the MIT License. See the [LICENSE][] file for further details.
|
27
44
|
|
28
|
-
[license]:
|
45
|
+
[license]: LICENSE.md
|
data/bin/thor
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
|
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
|
-
|
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,
|
63
|
+
File.open(destination, "wb") { |f| f.write render }
|
64
64
|
end
|
65
65
|
given_destination
|
66
66
|
end
|
67
67
|
|
68
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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, {
|
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
|
-
|
73
|
+
protected
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
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.
|
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
|
-
|
63
|
+
protected
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
# Shortcut for pretend.
|
66
|
+
#
|
67
|
+
def pretend?
|
68
|
+
base.options[:pretend]
|
69
|
+
end
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
142
|
-
say_status :exist, :blue
|
143
|
-
end
|
126
|
+
def on_file_clash_behavior
|
127
|
+
say_status :file_clash, :red
|
128
|
+
end
|
144
129
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|