thor 0.14.6 → 0.19.4
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/.document +5 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +91 -31
- data/CONTRIBUTING.md +15 -0
- data/{LICENSE → LICENSE.md} +2 -2
- data/README.md +36 -296
- data/bin/thor +1 -1
- data/lib/thor/actions/create_file.rb +33 -35
- data/lib/thor/actions/create_link.rb +7 -5
- data/lib/thor/actions/directory.rb +49 -24
- data/lib/thor/actions/empty_directory.rb +68 -67
- data/lib/thor/actions/file_manipulation.rb +85 -28
- data/lib/thor/actions/inject_into_file.rb +26 -32
- data/lib/thor/actions.rb +70 -66
- data/lib/thor/base.rb +314 -237
- data/lib/thor/command.rb +133 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +34 -24
- data/lib/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/thor/core_ext/ordered_hash.rb +94 -65
- data/lib/thor/error.rb +10 -8
- data/lib/thor/group.rb +74 -66
- data/lib/thor/invocation.rb +65 -56
- data/lib/thor/line_editor/basic.rb +35 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/parser/argument.rb +32 -29
- data/lib/thor/parser/arguments.rb +107 -93
- data/lib/thor/parser/option.rb +39 -13
- data/lib/thor/parser/options.rb +144 -97
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +21 -16
- data/lib/thor/runner.rb +166 -153
- data/lib/thor/shell/basic.rb +268 -122
- data/lib/thor/shell/color.rb +84 -43
- data/lib/thor/shell/html.rb +71 -66
- data/lib/thor/shell.rb +30 -37
- data/lib/thor/util.rb +227 -188
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +289 -131
- data/thor.gemspec +21 -0
- metadata +50 -189
- data/Thorfile +0 -24
- data/bin/rake2thor +0 -86
- data/lib/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/thor/task.rb +0 -114
- data/spec/actions/create_file_spec.rb +0 -170
- data/spec/actions/directory_spec.rb +0 -136
- data/spec/actions/empty_directory_spec.rb +0 -98
- data/spec/actions/file_manipulation_spec.rb +0 -310
- data/spec/actions/inject_into_file_spec.rb +0 -135
- data/spec/actions_spec.rb +0 -322
- data/spec/base_spec.rb +0 -269
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
- data/spec/core_ext/ordered_hash_spec.rb +0 -115
- data/spec/fixtures/application.rb +0 -2
- 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/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/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 -184
- data/spec/fixtures/task.thor +0 -10
- data/spec/group_spec.rb +0 -178
- data/spec/invocation_spec.rb +0 -100
- data/spec/parser/argument_spec.rb +0 -47
- data/spec/parser/arguments_spec.rb +0 -64
- data/spec/parser/option_spec.rb +0 -202
- data/spec/parser/options_spec.rb +0 -319
- data/spec/rake_compat_spec.rb +0 -68
- data/spec/register_spec.rb +0 -92
- data/spec/runner_spec.rb +0 -210
- data/spec/shell/basic_spec.rb +0 -223
- data/spec/shell/color_spec.rb +0 -41
- data/spec/shell/html_spec.rb +0 -27
- data/spec/shell_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -54
- data/spec/task_spec.rb +0 -69
- data/spec/thor_spec.rb +0 -334
- data/spec/util_spec.rb +0 -163
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "thor/actions/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.
|
|
@@ -41,7 +40,7 @@ class Thor
|
|
|
41
40
|
invoke_with_conflict_check do
|
|
42
41
|
FileUtils.mkdir_p(File.dirname(destination))
|
|
43
42
|
# Create a symlink by default
|
|
44
|
-
config[:symbolic]
|
|
43
|
+
config[:symbolic] = true if config[:symbolic].nil?
|
|
45
44
|
File.unlink(destination) if exists?
|
|
46
45
|
if config[:symbolic]
|
|
47
46
|
File.symlink(render, destination)
|
|
@@ -52,6 +51,9 @@ class Thor
|
|
|
52
51
|
given_destination
|
|
53
52
|
end
|
|
54
53
|
|
|
54
|
+
def exists?
|
|
55
|
+
super || File.symlink?(destination)
|
|
56
|
+
end
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "thor/actions/empty_directory"
|
|
2
2
|
|
|
3
3
|
class Thor
|
|
4
4
|
module Actions
|
|
5
|
-
|
|
6
5
|
# Copies recursively the files from source directory to root directory.
|
|
7
6
|
# If any of the files finishes with .tt, it's considered to be a template
|
|
8
7
|
# and is placed in the destination without the extension .tt. If any
|
|
9
8
|
# empty directory is found, it's copied and all .empty_directory files are
|
|
10
|
-
# ignored.
|
|
11
|
-
#
|
|
9
|
+
# ignored. If any file name is wrapped within % signs, the text within
|
|
10
|
+
# the % signs will be executed as a method and replaced with the returned
|
|
11
|
+
# value. Let's suppose a doc directory with the following files:
|
|
12
12
|
#
|
|
13
13
|
# doc/
|
|
14
14
|
# components/.empty_directory
|
|
@@ -29,11 +29,17 @@ class Thor
|
|
|
29
29
|
# rdoc.rb
|
|
30
30
|
# blog.rb
|
|
31
31
|
#
|
|
32
|
+
# <b>Encoded path note:</b> Since Thor internals use Object#respond_to? to check if it can
|
|
33
|
+
# expand %something%, this `something` should be a public method in the class calling
|
|
34
|
+
# #directory. If a method is private, Thor stack raises PrivateMethodEncodedError.
|
|
35
|
+
#
|
|
32
36
|
# ==== Parameters
|
|
33
37
|
# source<String>:: the relative path to the source root.
|
|
34
38
|
# destination<String>:: the relative path to the destination root.
|
|
35
39
|
# config<Hash>:: give :verbose => false to not log the status.
|
|
36
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.
|
|
37
43
|
#
|
|
38
44
|
# ==== Examples
|
|
39
45
|
#
|
|
@@ -49,10 +55,10 @@ class Thor
|
|
|
49
55
|
class Directory < EmptyDirectory #:nodoc:
|
|
50
56
|
attr_reader :source
|
|
51
57
|
|
|
52
|
-
def initialize(base, source, destination=nil, config={}, &block)
|
|
58
|
+
def initialize(base, source, destination = nil, config = {}, &block)
|
|
53
59
|
@source = File.expand_path(base.find_in_source_paths(source.to_s))
|
|
54
60
|
@block = block
|
|
55
|
-
super(base, destination, {
|
|
61
|
+
super(base, destination, {:recursive => true}.merge(config))
|
|
56
62
|
end
|
|
57
63
|
|
|
58
64
|
def invoke!
|
|
@@ -64,30 +70,49 @@ class Thor
|
|
|
64
70
|
execute!
|
|
65
71
|
end
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
protected
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
def execute!
|
|
76
|
+
lookup = Util.escape_globs(source)
|
|
77
|
+
lookup = config[:recursive] ? File.join(lookup, "**") : lookup
|
|
78
|
+
lookup = file_level_lookup(lookup)
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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!("/./", "/")
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
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)
|
|
88
95
|
end
|
|
89
96
|
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if RUBY_VERSION < "2.0"
|
|
100
|
+
def file_level_lookup(previous_lookup)
|
|
101
|
+
File.join(previous_lookup, "{*,.[a-z]*}")
|
|
102
|
+
end
|
|
90
103
|
|
|
104
|
+
def files(lookup)
|
|
105
|
+
Dir[lookup]
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
def file_level_lookup(previous_lookup)
|
|
109
|
+
File.join(previous_lookup, "*")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def files(lookup)
|
|
113
|
+
Dir.glob(lookup, File::FNM_DOTMATCH)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
91
116
|
end
|
|
92
117
|
end
|
|
93
118
|
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,7 +43,7 @@ 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!
|
|
@@ -58,77 +58,78 @@ class Thor
|
|
|
58
58
|
given_destination
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
protected
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
# Shortcut for pretend.
|
|
64
|
+
#
|
|
65
|
+
def pretend?
|
|
66
|
+
base.options[:pretend]
|
|
67
|
+
end
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
end
|
|
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
|
+
return unless 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
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
# Filenames in the encoded form are converted. If you have a file:
|
|
91
|
+
#
|
|
92
|
+
# %file_name%.rb
|
|
93
|
+
#
|
|
94
|
+
# It calls #file_name from the base and replaces %-string with the
|
|
95
|
+
# return value (should be String) of #file_name:
|
|
96
|
+
#
|
|
97
|
+
# user.rb
|
|
98
|
+
#
|
|
99
|
+
# The method referenced can be either public or private.
|
|
100
|
+
#
|
|
101
|
+
def convert_encoded_instructions(filename)
|
|
102
|
+
filename.gsub(/%(.*?)%/) do |initial_string|
|
|
103
|
+
method = $1.strip
|
|
104
|
+
base.respond_to?(method, true) ? base.send(method) : initial_string
|
|
104
105
|
end
|
|
106
|
+
end
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
destination
|
|
108
|
+
# Receives a hash of options and just execute the block if some
|
|
109
|
+
# conditions are met.
|
|
110
|
+
#
|
|
111
|
+
def invoke_with_conflict_check(&block)
|
|
112
|
+
if exists?
|
|
113
|
+
on_conflict_behavior(&block)
|
|
114
|
+
else
|
|
115
|
+
say_status :create, :green
|
|
116
|
+
yield unless pretend?
|
|
118
117
|
end
|
|
119
118
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def on_conflict_behavior(&block)
|
|
123
|
-
say_status :exist, :blue
|
|
124
|
-
end
|
|
119
|
+
destination
|
|
120
|
+
end
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
122
|
+
# What to do when the destination file already exists.
|
|
123
|
+
#
|
|
124
|
+
def on_conflict_behavior
|
|
125
|
+
say_status :exist, :blue
|
|
126
|
+
end
|
|
131
127
|
|
|
128
|
+
# Shortcut to say_status shell method.
|
|
129
|
+
#
|
|
130
|
+
def say_status(status, color)
|
|
131
|
+
base.shell.say_status status, relative_destination, color if config[:verbose]
|
|
132
|
+
end
|
|
132
133
|
end
|
|
133
134
|
end
|
|
134
135
|
end
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "erb"
|
|
2
|
+
require "open-uri"
|
|
3
3
|
|
|
4
4
|
class Thor
|
|
5
5
|
module Actions
|
|
6
|
-
|
|
7
6
|
# Copies the file from the relative source to the relative destination. If
|
|
8
7
|
# the destination is not given it's assumed to be equal to the source.
|
|
9
8
|
#
|
|
10
9
|
# ==== Parameters
|
|
11
10
|
# source<String>:: the relative path to the source root.
|
|
12
11
|
# destination<String>:: the relative path to the destination root.
|
|
13
|
-
# config<Hash>:: give :verbose => false to not log the status
|
|
12
|
+
# config<Hash>:: give :verbose => false to not log the status, and
|
|
13
|
+
# :mode => :preserve, to preserve the file mode from the source.
|
|
14
|
+
|
|
14
15
|
#
|
|
15
16
|
# ==== Examples
|
|
16
17
|
#
|
|
@@ -25,9 +26,13 @@ class Thor
|
|
|
25
26
|
|
|
26
27
|
create_file destination, nil, config do
|
|
27
28
|
content = File.binread(source)
|
|
28
|
-
content =
|
|
29
|
+
content = yield(content) if block
|
|
29
30
|
content
|
|
30
31
|
end
|
|
32
|
+
if config[:mode] == :preserve
|
|
33
|
+
mode = File.stat(source).mode
|
|
34
|
+
chmod(destination, mode, config)
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
# Links the file from the relative source to the relative destination. If
|
|
@@ -44,7 +49,7 @@ class Thor
|
|
|
44
49
|
#
|
|
45
50
|
# link_file "doc/README"
|
|
46
51
|
#
|
|
47
|
-
def link_file(source, *args
|
|
52
|
+
def link_file(source, *args)
|
|
48
53
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
49
54
|
destination = args.first || source
|
|
50
55
|
source = File.expand_path(find_in_source_paths(source.to_s))
|
|
@@ -73,11 +78,11 @@ class Thor
|
|
|
73
78
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
74
79
|
destination = args.first
|
|
75
80
|
|
|
76
|
-
source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~
|
|
77
|
-
render = open(source) {|input| input.binmode.read }
|
|
81
|
+
source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ %r{^https?\://}
|
|
82
|
+
render = open(source) { |input| input.binmode.read }
|
|
78
83
|
|
|
79
84
|
destination ||= if block_given?
|
|
80
|
-
block.arity == 1 ?
|
|
85
|
+
block.arity == 1 ? yield(render) : yield
|
|
81
86
|
else
|
|
82
87
|
File.basename(source)
|
|
83
88
|
end
|
|
@@ -102,14 +107,14 @@ class Thor
|
|
|
102
107
|
#
|
|
103
108
|
def template(source, *args, &block)
|
|
104
109
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
105
|
-
destination = args.first || source
|
|
110
|
+
destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "")
|
|
106
111
|
|
|
107
112
|
source = File.expand_path(find_in_source_paths(source.to_s))
|
|
108
|
-
context = instance_eval(
|
|
113
|
+
context = config.delete(:context) || instance_eval("binding")
|
|
109
114
|
|
|
110
115
|
create_file destination, nil, config do
|
|
111
|
-
content =
|
|
112
|
-
content =
|
|
116
|
+
content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context)
|
|
117
|
+
content = yield(content) if block
|
|
113
118
|
content
|
|
114
119
|
end
|
|
115
120
|
end
|
|
@@ -123,9 +128,9 @@ class Thor
|
|
|
123
128
|
#
|
|
124
129
|
# ==== Example
|
|
125
130
|
#
|
|
126
|
-
# chmod "script
|
|
131
|
+
# chmod "script/server", 0755
|
|
127
132
|
#
|
|
128
|
-
def chmod(path, mode, config={})
|
|
133
|
+
def chmod(path, mode, config = {})
|
|
129
134
|
return unless behavior == :invoke
|
|
130
135
|
path = File.expand_path(path, destination_root)
|
|
131
136
|
say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
|
@@ -149,7 +154,7 @@ class Thor
|
|
|
149
154
|
#
|
|
150
155
|
def prepend_to_file(path, *args, &block)
|
|
151
156
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
152
|
-
config
|
|
157
|
+
config[:after] = /\A/
|
|
153
158
|
insert_into_file(path, *(args << config), &block)
|
|
154
159
|
end
|
|
155
160
|
alias_method :prepend_file, :prepend_to_file
|
|
@@ -171,7 +176,7 @@ class Thor
|
|
|
171
176
|
#
|
|
172
177
|
def append_to_file(path, *args, &block)
|
|
173
178
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
174
|
-
config
|
|
179
|
+
config[:before] = /\z/
|
|
175
180
|
insert_into_file(path, *(args << config), &block)
|
|
176
181
|
end
|
|
177
182
|
alias_method :append_file, :append_to_file
|
|
@@ -187,7 +192,7 @@ class Thor
|
|
|
187
192
|
#
|
|
188
193
|
# ==== Examples
|
|
189
194
|
#
|
|
190
|
-
# inject_into_class "app/controllers/application_controller.rb", " filter_parameter :password\n"
|
|
195
|
+
# inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
|
|
191
196
|
#
|
|
192
197
|
# inject_into_class "app/controllers/application_controller.rb", ApplicationController do
|
|
193
198
|
# " filter_parameter :password\n"
|
|
@@ -195,7 +200,7 @@ class Thor
|
|
|
195
200
|
#
|
|
196
201
|
def inject_into_class(path, klass, *args, &block)
|
|
197
202
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
198
|
-
config
|
|
203
|
+
config[:after] = /class #{klass}\n|class #{klass} .*\n/
|
|
199
204
|
insert_into_file(path, *(args << config), &block)
|
|
200
205
|
end
|
|
201
206
|
|
|
@@ -225,10 +230,48 @@ class Thor
|
|
|
225
230
|
unless options[:pretend]
|
|
226
231
|
content = File.binread(path)
|
|
227
232
|
content.gsub!(flag, *args, &block)
|
|
228
|
-
File.open(path,
|
|
233
|
+
File.open(path, "wb") { |file| file.write(content) }
|
|
229
234
|
end
|
|
230
235
|
end
|
|
231
236
|
|
|
237
|
+
# Uncomment all lines matching a given regex. It will leave the space
|
|
238
|
+
# which existed before the comment hash in tact but will remove any spacing
|
|
239
|
+
# between the comment hash and the beginning of the line.
|
|
240
|
+
#
|
|
241
|
+
# ==== Parameters
|
|
242
|
+
# path<String>:: path of the file to be changed
|
|
243
|
+
# flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
|
|
244
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
|
245
|
+
#
|
|
246
|
+
# ==== Example
|
|
247
|
+
#
|
|
248
|
+
# uncomment_lines 'config/initializers/session_store.rb', /active_record/
|
|
249
|
+
#
|
|
250
|
+
def uncomment_lines(path, flag, *args)
|
|
251
|
+
flag = flag.respond_to?(:source) ? flag.source : flag
|
|
252
|
+
|
|
253
|
+
gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Comment all lines matching a given regex. It will leave the space
|
|
257
|
+
# which existed before the beginning of the line in tact and will insert
|
|
258
|
+
# a single space after the comment hash.
|
|
259
|
+
#
|
|
260
|
+
# ==== Parameters
|
|
261
|
+
# path<String>:: path of the file to be changed
|
|
262
|
+
# flag<Regexp|String>:: the regexp or string used to decide which lines to comment
|
|
263
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
|
264
|
+
#
|
|
265
|
+
# ==== Example
|
|
266
|
+
#
|
|
267
|
+
# comment_lines 'config/initializers/session_store.rb', /cookie_store/
|
|
268
|
+
#
|
|
269
|
+
def comment_lines(path, flag, *args)
|
|
270
|
+
flag = flag.respond_to?(:source) ? flag.source : flag
|
|
271
|
+
|
|
272
|
+
gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
|
|
273
|
+
end
|
|
274
|
+
|
|
232
275
|
# Removes a file at the given location.
|
|
233
276
|
#
|
|
234
277
|
# ==== Parameters
|
|
@@ -240,31 +283,45 @@ class Thor
|
|
|
240
283
|
# remove_file 'README'
|
|
241
284
|
# remove_file 'app/controllers/application_controller.rb'
|
|
242
285
|
#
|
|
243
|
-
def remove_file(path, config={})
|
|
286
|
+
def remove_file(path, config = {})
|
|
244
287
|
return unless behavior == :invoke
|
|
245
|
-
path
|
|
288
|
+
path = File.expand_path(path, destination_root)
|
|
246
289
|
|
|
247
290
|
say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
|
248
|
-
::FileUtils.rm_rf(path) if !options[:pretend] && File.
|
|
291
|
+
::FileUtils.rm_rf(path) if !options[:pretend] && File.exist?(path)
|
|
249
292
|
end
|
|
250
|
-
|
|
293
|
+
alias_method :remove_dir, :remove_file
|
|
251
294
|
|
|
252
|
-
private
|
|
253
295
|
attr_accessor :output_buffer
|
|
296
|
+
private :output_buffer, :output_buffer=
|
|
297
|
+
|
|
298
|
+
private
|
|
299
|
+
|
|
254
300
|
def concat(string)
|
|
255
301
|
@output_buffer.concat(string)
|
|
256
302
|
end
|
|
257
303
|
|
|
258
|
-
def capture(*args
|
|
259
|
-
with_output_buffer {
|
|
304
|
+
def capture(*args)
|
|
305
|
+
with_output_buffer { yield(*args) }
|
|
260
306
|
end
|
|
261
307
|
|
|
262
|
-
def with_output_buffer(buf =
|
|
308
|
+
def with_output_buffer(buf = "") #:nodoc:
|
|
263
309
|
self.output_buffer, old_buffer = buf, output_buffer
|
|
264
310
|
yield
|
|
265
311
|
output_buffer
|
|
266
312
|
ensure
|
|
267
313
|
self.output_buffer = old_buffer
|
|
268
314
|
end
|
|
315
|
+
|
|
316
|
+
# Thor::Actions#capture depends on what kind of buffer is used in ERB.
|
|
317
|
+
# Thus CapturableERB fixes ERB to use String buffer.
|
|
318
|
+
class CapturableERB < ERB
|
|
319
|
+
def set_eoutvar(compiler, eoutvar = "_erbout")
|
|
320
|
+
compiler.put_cmd = "#{eoutvar}.concat"
|
|
321
|
+
compiler.insert_cmd = "#{eoutvar}.concat"
|
|
322
|
+
compiler.pre_cmd = ["#{eoutvar} = ''"]
|
|
323
|
+
compiler.post_cmd = [eoutvar]
|
|
324
|
+
end
|
|
325
|
+
end
|
|
269
326
|
end
|
|
270
327
|
end
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "thor/actions/empty_directory"
|
|
2
2
|
|
|
3
3
|
class Thor
|
|
4
4
|
module Actions
|
|
5
|
-
|
|
6
5
|
# Injects the given content into a file. Different from gsub_file, this
|
|
7
6
|
# method is reversible.
|
|
8
7
|
#
|
|
@@ -23,11 +22,8 @@ class Thor
|
|
|
23
22
|
# end
|
|
24
23
|
#
|
|
25
24
|
def insert_into_file(destination, *args, &block)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
else
|
|
29
|
-
data, config = args.shift, args.shift
|
|
30
|
-
end
|
|
25
|
+
data = block_given? ? block : args.shift
|
|
26
|
+
config = args.shift
|
|
31
27
|
action InjectIntoFile.new(self, destination, data, config)
|
|
32
28
|
end
|
|
33
29
|
alias_method :inject_into_file, :insert_into_file
|
|
@@ -36,7 +32,7 @@ class Thor
|
|
|
36
32
|
attr_reader :replacement, :flag, :behavior
|
|
37
33
|
|
|
38
34
|
def initialize(base, destination, data, config)
|
|
39
|
-
super(base, destination, {
|
|
35
|
+
super(base, destination, {:verbose => true}.merge(config))
|
|
40
36
|
|
|
41
37
|
@behavior, @flag = if @config.key?(:after)
|
|
42
38
|
[:after, @config.delete(:after)]
|
|
@@ -74,36 +70,34 @@ class Thor
|
|
|
74
70
|
replace!(regexp, content, true)
|
|
75
71
|
end
|
|
76
72
|
|
|
77
|
-
|
|
73
|
+
protected
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
else
|
|
86
|
-
:insert
|
|
87
|
-
end
|
|
75
|
+
def say_status(behavior)
|
|
76
|
+
status = if behavior == :invoke
|
|
77
|
+
if flag == /\A/
|
|
78
|
+
:prepend
|
|
79
|
+
elsif flag == /\z/
|
|
80
|
+
:append
|
|
88
81
|
else
|
|
89
|
-
:
|
|
82
|
+
:insert
|
|
90
83
|
end
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
else
|
|
85
|
+
:subtract
|
|
93
86
|
end
|
|
94
87
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def replace!(regexp, string, force)
|
|
98
|
-
unless base.options[:pretend]
|
|
99
|
-
content = File.binread(destination)
|
|
100
|
-
if force || !content.include?(replacement)
|
|
101
|
-
content.gsub!(regexp, string)
|
|
102
|
-
File.open(destination, 'wb') { |file| file.write(content) }
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
88
|
+
super(status, config[:verbose])
|
|
89
|
+
end
|
|
106
90
|
|
|
91
|
+
# Adds the content to the file.
|
|
92
|
+
#
|
|
93
|
+
def replace!(regexp, string, force)
|
|
94
|
+
return if base.options[:pretend]
|
|
95
|
+
content = File.binread(destination)
|
|
96
|
+
if force || !content.include?(replacement)
|
|
97
|
+
content.gsub!(regexp, string)
|
|
98
|
+
File.open(destination, "wb") { |file| file.write(content) }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
107
101
|
end
|
|
108
102
|
end
|
|
109
103
|
end
|