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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/{CHANGELOG.rdoc → CHANGELOG.md} +91 -31
  4. data/CONTRIBUTING.md +15 -0
  5. data/{LICENSE → LICENSE.md} +2 -2
  6. data/README.md +36 -296
  7. data/bin/thor +1 -1
  8. data/lib/thor/actions/create_file.rb +33 -35
  9. data/lib/thor/actions/create_link.rb +7 -5
  10. data/lib/thor/actions/directory.rb +49 -24
  11. data/lib/thor/actions/empty_directory.rb +68 -67
  12. data/lib/thor/actions/file_manipulation.rb +85 -28
  13. data/lib/thor/actions/inject_into_file.rb +26 -32
  14. data/lib/thor/actions.rb +70 -66
  15. data/lib/thor/base.rb +314 -237
  16. data/lib/thor/command.rb +133 -0
  17. data/lib/thor/core_ext/hash_with_indifferent_access.rb +34 -24
  18. data/lib/thor/core_ext/io_binary_read.rb +12 -0
  19. data/lib/thor/core_ext/ordered_hash.rb +94 -65
  20. data/lib/thor/error.rb +10 -8
  21. data/lib/thor/group.rb +74 -66
  22. data/lib/thor/invocation.rb +65 -56
  23. data/lib/thor/line_editor/basic.rb +35 -0
  24. data/lib/thor/line_editor/readline.rb +88 -0
  25. data/lib/thor/line_editor.rb +17 -0
  26. data/lib/thor/parser/argument.rb +32 -29
  27. data/lib/thor/parser/arguments.rb +107 -93
  28. data/lib/thor/parser/option.rb +39 -13
  29. data/lib/thor/parser/options.rb +144 -97
  30. data/lib/thor/parser.rb +4 -4
  31. data/lib/thor/rake_compat.rb +21 -16
  32. data/lib/thor/runner.rb +166 -153
  33. data/lib/thor/shell/basic.rb +268 -122
  34. data/lib/thor/shell/color.rb +84 -43
  35. data/lib/thor/shell/html.rb +71 -66
  36. data/lib/thor/shell.rb +30 -37
  37. data/lib/thor/util.rb +227 -188
  38. data/lib/thor/version.rb +1 -1
  39. data/lib/thor.rb +289 -131
  40. data/thor.gemspec +21 -0
  41. metadata +50 -189
  42. data/Thorfile +0 -24
  43. data/bin/rake2thor +0 -86
  44. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  45. data/lib/thor/task.rb +0 -114
  46. data/spec/actions/create_file_spec.rb +0 -170
  47. data/spec/actions/directory_spec.rb +0 -136
  48. data/spec/actions/empty_directory_spec.rb +0 -98
  49. data/spec/actions/file_manipulation_spec.rb +0 -310
  50. data/spec/actions/inject_into_file_spec.rb +0 -135
  51. data/spec/actions_spec.rb +0 -322
  52. data/spec/base_spec.rb +0 -269
  53. data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
  54. data/spec/core_ext/ordered_hash_spec.rb +0 -115
  55. data/spec/fixtures/application.rb +0 -2
  56. data/spec/fixtures/bundle/execute.rb +0 -6
  57. data/spec/fixtures/bundle/main.thor +0 -1
  58. data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
  59. data/spec/fixtures/doc/README +0 -3
  60. data/spec/fixtures/doc/block_helper.rb +0 -3
  61. data/spec/fixtures/doc/components/.empty_directory +0 -0
  62. data/spec/fixtures/doc/config.rb +0 -1
  63. data/spec/fixtures/group.thor +0 -114
  64. data/spec/fixtures/invoke.thor +0 -112
  65. data/spec/fixtures/path with spaces +0 -0
  66. data/spec/fixtures/script.thor +0 -184
  67. data/spec/fixtures/task.thor +0 -10
  68. data/spec/group_spec.rb +0 -178
  69. data/spec/invocation_spec.rb +0 -100
  70. data/spec/parser/argument_spec.rb +0 -47
  71. data/spec/parser/arguments_spec.rb +0 -64
  72. data/spec/parser/option_spec.rb +0 -202
  73. data/spec/parser/options_spec.rb +0 -319
  74. data/spec/rake_compat_spec.rb +0 -68
  75. data/spec/register_spec.rb +0 -92
  76. data/spec/runner_spec.rb +0 -210
  77. data/spec/shell/basic_spec.rb +0 -223
  78. data/spec/shell/color_spec.rb +0 -41
  79. data/spec/shell/html_spec.rb +0 -27
  80. data/spec/shell_spec.rb +0 -47
  81. data/spec/spec_helper.rb +0 -54
  82. data/spec/task_spec.rb +0 -69
  83. data/spec/thor_spec.rb +0 -334
  84. data/spec/util_spec.rb +0 -163
@@ -1,8 +1,7 @@
1
- require 'thor/actions/create_file'
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, &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.
@@ -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] ||= true
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 'thor/actions/empty_directory'
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. Remember that file paths can also be encoded, let's suppose a doc
11
- # directory with the following files:
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, { :recursive => true }.merge(config))
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
- protected
73
+ protected
68
74
 
69
- def execute!
70
- lookup = config[:recursive] ? File.join(source, '**') : source
71
- 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)
72
79
 
73
- Dir[lookup].sort.each do |file_source|
74
- next if File.directory?(file_source)
75
- file_destination = File.join(given_destination, file_source.gsub(source, '.'))
76
- 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!("/./", "/")
77
85
 
78
- case file_source
79
- when /\.empty_directory$/
80
- dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
81
- next if dirname == given_destination
82
- base.empty_directory(dirname, config)
83
- when /\.tt$/
84
- destination = base.template(file_source, file_destination[0..-4], config, &@block)
85
- else
86
- destination = base.copy_file(file_source, file_destination, config, &@block)
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, @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,7 +43,7 @@ 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!
@@ -58,77 +58,78 @@ class Thor
58
58
  given_destination
59
59
  end
60
60
 
61
- protected
61
+ protected
62
62
 
63
- # Shortcut for pretend.
64
- #
65
- def pretend?
66
- base.options[:pretend]
67
- end
63
+ # Shortcut for pretend.
64
+ #
65
+ def pretend?
66
+ base.options[:pretend]
67
+ end
68
68
 
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
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
- # Filenames in the encoded form are converted. If you have a file:
92
- #
93
- # %class_name%.rb
94
- #
95
- # It gets the class name from the base and replace it:
96
- #
97
- # user.rb
98
- #
99
- def convert_encoded_instructions(filename)
100
- filename.gsub(/%(.*?)%/) do |string|
101
- instruction = $1.strip
102
- base.respond_to?(instruction) ? base.send(instruction) : string
103
- end
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
- # Receives a hash of options and just execute the block if some
107
- # conditions are met.
108
- #
109
- def invoke_with_conflict_check(&block)
110
- if exists?
111
- on_conflict_behavior(&block)
112
- else
113
- say_status :create, :green
114
- block.call unless pretend?
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
- # What to do when the destination file already exists.
121
- #
122
- def on_conflict_behavior(&block)
123
- say_status :exist, :blue
124
- end
119
+ destination
120
+ end
125
121
 
126
- # Shortcut to say_status shell method.
127
- #
128
- def say_status(status, color)
129
- base.shell.say_status status, relative_destination, color if config[:verbose]
130
- end
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 'erb'
2
- require 'open-uri'
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 = block.call(content) if block
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, &block)
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 =~ /^https?\:\/\//
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 ? block.call(render) : block.call
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('binding')
113
+ context = config.delete(:context) || instance_eval("binding")
109
114
 
110
115
  create_file destination, nil, config do
111
- content = ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context)
112
- content = block.call(content) if block
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/*", 0755
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.merge!(:after => /\A/)
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.merge!(:before => /\z/)
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.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
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, 'wb') { |file| file.write(content) }
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 = File.expand_path(path, destination_root)
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.exists?(path)
291
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exist?(path)
249
292
  end
250
- alias :remove_dir :remove_file
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, &block)
259
- with_output_buffer { block.call(*args) }
304
+ def capture(*args)
305
+ with_output_buffer { yield(*args) }
260
306
  end
261
307
 
262
- def with_output_buffer(buf = '') #:nodoc:
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 'thor/actions/empty_directory'
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
- if block_given?
27
- data, config = block, args.shift
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, { :verbose => true }.merge(config))
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
- protected
73
+ protected
78
74
 
79
- def say_status(behavior)
80
- status = if behavior == :invoke
81
- if flag == /\A/
82
- :prepend
83
- elsif flag == /\z/
84
- :append
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
- :subtract
82
+ :insert
90
83
  end
91
-
92
- super(status, config[:verbose])
84
+ else
85
+ :subtract
93
86
  end
94
87
 
95
- # Adds the content to the file.
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