wijet-thor 0.14.6

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 (75) hide show
  1. data/CHANGELOG.rdoc +103 -0
  2. data/LICENSE +20 -0
  3. data/README.md +307 -0
  4. data/Thorfile +24 -0
  5. data/bin/rake2thor +86 -0
  6. data/bin/thor +6 -0
  7. data/lib/thor.rb +334 -0
  8. data/lib/thor/actions.rb +314 -0
  9. data/lib/thor/actions/create_file.rb +105 -0
  10. data/lib/thor/actions/create_link.rb +57 -0
  11. data/lib/thor/actions/directory.rb +93 -0
  12. data/lib/thor/actions/empty_directory.rb +134 -0
  13. data/lib/thor/actions/file_manipulation.rb +270 -0
  14. data/lib/thor/actions/inject_into_file.rb +109 -0
  15. data/lib/thor/base.rb +579 -0
  16. data/lib/thor/core_ext/file_binary_read.rb +9 -0
  17. data/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  18. data/lib/thor/core_ext/ordered_hash.rb +100 -0
  19. data/lib/thor/error.rb +30 -0
  20. data/lib/thor/group.rb +273 -0
  21. data/lib/thor/invocation.rb +168 -0
  22. data/lib/thor/parser.rb +4 -0
  23. data/lib/thor/parser/argument.rb +67 -0
  24. data/lib/thor/parser/arguments.rb +161 -0
  25. data/lib/thor/parser/option.rb +120 -0
  26. data/lib/thor/parser/options.rb +173 -0
  27. data/lib/thor/rake_compat.rb +66 -0
  28. data/lib/thor/runner.rb +309 -0
  29. data/lib/thor/shell.rb +88 -0
  30. data/lib/thor/shell/basic.rb +290 -0
  31. data/lib/thor/shell/color.rb +108 -0
  32. data/lib/thor/shell/html.rb +121 -0
  33. data/lib/thor/task.rb +114 -0
  34. data/lib/thor/util.rb +229 -0
  35. data/lib/thor/version.rb +3 -0
  36. data/spec/actions/create_file_spec.rb +170 -0
  37. data/spec/actions/directory_spec.rb +136 -0
  38. data/spec/actions/empty_directory_spec.rb +98 -0
  39. data/spec/actions/file_manipulation_spec.rb +310 -0
  40. data/spec/actions/inject_into_file_spec.rb +135 -0
  41. data/spec/actions_spec.rb +322 -0
  42. data/spec/base_spec.rb +269 -0
  43. data/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  44. data/spec/core_ext/ordered_hash_spec.rb +115 -0
  45. data/spec/fixtures/application.rb +2 -0
  46. data/spec/fixtures/bundle/execute.rb +6 -0
  47. data/spec/fixtures/bundle/main.thor +1 -0
  48. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  49. data/spec/fixtures/doc/README +3 -0
  50. data/spec/fixtures/doc/block_helper.rb +3 -0
  51. data/spec/fixtures/doc/components/.empty_directory +0 -0
  52. data/spec/fixtures/doc/config.rb +1 -0
  53. data/spec/fixtures/group.thor +114 -0
  54. data/spec/fixtures/invoke.thor +112 -0
  55. data/spec/fixtures/path with spaces b/data/spec/fixtures/path with → spaces +0 -0
  56. data/spec/fixtures/script.thor +184 -0
  57. data/spec/fixtures/task.thor +10 -0
  58. data/spec/group_spec.rb +178 -0
  59. data/spec/invocation_spec.rb +100 -0
  60. data/spec/parser/argument_spec.rb +47 -0
  61. data/spec/parser/arguments_spec.rb +64 -0
  62. data/spec/parser/option_spec.rb +202 -0
  63. data/spec/parser/options_spec.rb +319 -0
  64. data/spec/rake_compat_spec.rb +68 -0
  65. data/spec/register_spec.rb +104 -0
  66. data/spec/runner_spec.rb +210 -0
  67. data/spec/shell/basic_spec.rb +223 -0
  68. data/spec/shell/color_spec.rb +41 -0
  69. data/spec/shell/html_spec.rb +27 -0
  70. data/spec/shell_spec.rb +47 -0
  71. data/spec/spec_helper.rb +54 -0
  72. data/spec/task_spec.rb +74 -0
  73. data/spec/thor_spec.rb +334 -0
  74. data/spec/util_spec.rb +163 -0
  75. metadata +193 -0
@@ -0,0 +1,105 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root with the given data,
7
+ # which is the return value of a block or a data string.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: the relative path to the destination root.
11
+ # data<String|NilClass>:: the data to append to the file.
12
+ # config<Hash>:: give :verbose => false to not log the status.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_file "lib/fun_party.rb" do
17
+ # hostname = ask("What is the virtual hostname I should use?")
18
+ # "vhost.name = #{hostname}"
19
+ # end
20
+ #
21
+ # create_file "config/apache.conf", "your apache config"
22
+ #
23
+ def create_file(destination, *args, &block)
24
+ config = args.last.is_a?(Hash) ? args.pop : {}
25
+ data = args.first
26
+ action CreateFile.new(self, destination, block || data.to_s, config)
27
+ end
28
+ alias :add_file :create_file
29
+
30
+ # CreateFile is a subset of Template, which instead of rendering a file with
31
+ # ERB, it gets the content from the user.
32
+ #
33
+ class CreateFile < EmptyDirectory #:nodoc:
34
+ attr_reader :data
35
+
36
+ def initialize(base, destination, data, config={})
37
+ @data = data
38
+ super(base, destination, config)
39
+ end
40
+
41
+ # Checks if the content of the file at the destination is identical to the rendered result.
42
+ #
43
+ # ==== Returns
44
+ # Boolean:: true if it is identical, false otherwise.
45
+ #
46
+ def identical?
47
+ exists? && File.binread(destination) == render
48
+ end
49
+
50
+ # Holds the content to be added to the file.
51
+ #
52
+ def render
53
+ @render ||= if data.is_a?(Proc)
54
+ data.call
55
+ else
56
+ data
57
+ end
58
+ end
59
+
60
+ def invoke!
61
+ invoke_with_conflict_check do
62
+ FileUtils.mkdir_p(File.dirname(destination))
63
+ File.open(destination, 'wb') { |f| f.write render }
64
+ end
65
+ given_destination
66
+ end
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
80
+
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
95
+ end
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
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,57 @@
1
+ require 'thor/actions/create_file'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root from the given source.
7
+ #
8
+ # ==== Parameters
9
+ # destination<String>:: the relative path to the destination root.
10
+ # source<String|NilClass>:: the relative path to the source root.
11
+ # config<Hash>:: give :verbose => false to not log the status.
12
+ # :: give :symbolic => false for hard link.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_link "config/apache.conf", "/etc/apache.conf"
17
+ #
18
+ def create_link(destination, *args, &block)
19
+ config = args.last.is_a?(Hash) ? args.pop : {}
20
+ source = args.first
21
+ action CreateLink.new(self, destination, source, config)
22
+ end
23
+ alias :add_link :create_link
24
+
25
+ # CreateLink is a subset of CreateFile, which instead of taking a block of
26
+ # data, just takes a source string from the user.
27
+ #
28
+ class CreateLink < CreateFile #:nodoc:
29
+ attr_reader :data
30
+
31
+ # Checks if the content of the file at the destination is identical to the rendered result.
32
+ #
33
+ # ==== Returns
34
+ # Boolean:: true if it is identical, false otherwise.
35
+ #
36
+ def identical?
37
+ exists? && File.identical?(render, destination)
38
+ end
39
+
40
+ def invoke!
41
+ invoke_with_conflict_check do
42
+ FileUtils.mkdir_p(File.dirname(destination))
43
+ # Create a symlink by default
44
+ config[:symbolic] ||= true
45
+ File.unlink(destination) if exists?
46
+ if config[:symbolic]
47
+ File.symlink(render, destination)
48
+ else
49
+ File.link(render, destination)
50
+ end
51
+ end
52
+ given_destination
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,93 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Copies recursively the files from source directory to root directory.
7
+ # If any of the files finishes with .tt, it's considered to be a template
8
+ # and is placed in the destination without the extension .tt. If any
9
+ # 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:
12
+ #
13
+ # doc/
14
+ # components/.empty_directory
15
+ # README
16
+ # rdoc.rb.tt
17
+ # %app_name%.rb
18
+ #
19
+ # When invoked as:
20
+ #
21
+ # directory "doc"
22
+ #
23
+ # It will create a doc directory in the destination with the following
24
+ # files (assuming that the `app_name` method returns the value "blog"):
25
+ #
26
+ # doc/
27
+ # components/
28
+ # README
29
+ # rdoc.rb
30
+ # blog.rb
31
+ #
32
+ # ==== Parameters
33
+ # source<String>:: the relative path to the source root.
34
+ # destination<String>:: the relative path to the destination root.
35
+ # config<Hash>:: give :verbose => false to not log the status.
36
+ # If :recursive => false, does not look for paths recursively.
37
+ #
38
+ # ==== Examples
39
+ #
40
+ # directory "doc"
41
+ # directory "doc", "docs", :recursive => false
42
+ #
43
+ def directory(source, *args, &block)
44
+ config = args.last.is_a?(Hash) ? args.pop : {}
45
+ destination = args.first || source
46
+ action Directory.new(self, source, destination || source, config, &block)
47
+ end
48
+
49
+ class Directory < EmptyDirectory #:nodoc:
50
+ attr_reader :source
51
+
52
+ def initialize(base, source, destination=nil, config={}, &block)
53
+ @source = File.expand_path(base.find_in_source_paths(source.to_s))
54
+ @block = block
55
+ super(base, destination, { :recursive => true }.merge(config))
56
+ end
57
+
58
+ def invoke!
59
+ base.empty_directory given_destination, config
60
+ execute!
61
+ end
62
+
63
+ def revoke!
64
+ execute!
65
+ end
66
+
67
+ protected
68
+
69
+ def execute!
70
+ lookup = config[:recursive] ? File.join(source, '**') : source
71
+ lookup = File.join(lookup, '{*,.[a-z]*}')
72
+
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!('/./', '/')
77
+
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
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,134 @@
1
+ class Thor
2
+ module Actions
3
+
4
+ # Creates an empty directory.
5
+ #
6
+ # ==== Parameters
7
+ # destination<String>:: the relative path to the destination root.
8
+ # config<Hash>:: give :verbose => false to not log the status.
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # empty_directory "doc"
13
+ #
14
+ def empty_directory(destination, config={})
15
+ action EmptyDirectory.new(self, destination, config)
16
+ end
17
+
18
+ # Class which holds create directory logic. This is the base class for
19
+ # other actions like create_file and directory.
20
+ #
21
+ # This implementation is based in Templater actions, created by Jonas Nicklas
22
+ # and Michael S. Klishin under MIT LICENSE.
23
+ #
24
+ class EmptyDirectory #:nodoc:
25
+ attr_reader :base, :destination, :given_destination, :relative_destination, :config
26
+
27
+ # Initializes given the source and destination.
28
+ #
29
+ # ==== Parameters
30
+ # base<Thor::Base>:: A Thor::Base instance
31
+ # source<String>:: Relative path to the source of this file
32
+ # destination<String>:: Relative path to the destination of this file
33
+ # config<Hash>:: give :verbose => false to not log the status.
34
+ #
35
+ def initialize(base, destination, config={})
36
+ @base, @config = base, { :verbose => true }.merge(config)
37
+ self.destination = destination
38
+ end
39
+
40
+ # Checks if the destination file already exists.
41
+ #
42
+ # ==== Returns
43
+ # Boolean:: true if the file exists, false otherwise.
44
+ #
45
+ def exists?
46
+ ::File.exists?(destination)
47
+ end
48
+
49
+ def invoke!
50
+ invoke_with_conflict_check do
51
+ ::FileUtils.mkdir_p(destination)
52
+ end
53
+ end
54
+
55
+ def revoke!
56
+ say_status :remove, :red
57
+ ::FileUtils.rm_rf(destination) if !pretend? && exists?
58
+ given_destination
59
+ end
60
+
61
+ protected
62
+
63
+ # Shortcut for pretend.
64
+ #
65
+ def pretend?
66
+ base.options[:pretend]
67
+ end
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
90
+
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
104
+ end
105
+
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
118
+ end
119
+
120
+ # What to do when the destination file already exists.
121
+ #
122
+ def on_conflict_behavior(&block)
123
+ say_status :exist, :blue
124
+ end
125
+
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
131
+
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,270 @@
1
+ require 'erb'
2
+ require 'open-uri'
3
+
4
+ class Thor
5
+ module Actions
6
+
7
+ # Copies the file from the relative source to the relative destination. If
8
+ # the destination is not given it's assumed to be equal to the source.
9
+ #
10
+ # ==== Parameters
11
+ # source<String>:: the relative path to the source root.
12
+ # destination<String>:: the relative path to the destination root.
13
+ # config<Hash>:: give :verbose => false to not log the status.
14
+ #
15
+ # ==== Examples
16
+ #
17
+ # copy_file "README", "doc/README"
18
+ #
19
+ # copy_file "doc/README"
20
+ #
21
+ def copy_file(source, *args, &block)
22
+ config = args.last.is_a?(Hash) ? args.pop : {}
23
+ destination = args.first || source
24
+ source = File.expand_path(find_in_source_paths(source.to_s))
25
+
26
+ create_file destination, nil, config do
27
+ content = File.binread(source)
28
+ content = block.call(content) if block
29
+ content
30
+ end
31
+ end
32
+
33
+ # Links the file from the relative source to the relative destination. If
34
+ # the destination is not given it's assumed to be equal to the source.
35
+ #
36
+ # ==== Parameters
37
+ # source<String>:: the relative path to the source root.
38
+ # destination<String>:: the relative path to the destination root.
39
+ # config<Hash>:: give :verbose => false to not log the status.
40
+ #
41
+ # ==== Examples
42
+ #
43
+ # link_file "README", "doc/README"
44
+ #
45
+ # link_file "doc/README"
46
+ #
47
+ def link_file(source, *args, &block)
48
+ config = args.last.is_a?(Hash) ? args.pop : {}
49
+ destination = args.first || source
50
+ source = File.expand_path(find_in_source_paths(source.to_s))
51
+
52
+ create_link destination, source, config
53
+ end
54
+
55
+ # Gets the content at the given address and places it at the given relative
56
+ # destination. If a block is given instead of destination, the content of
57
+ # the url is yielded and used as location.
58
+ #
59
+ # ==== Parameters
60
+ # source<String>:: the address of the given content.
61
+ # destination<String>:: the relative path to the destination root.
62
+ # config<Hash>:: give :verbose => false to not log the status.
63
+ #
64
+ # ==== Examples
65
+ #
66
+ # get "http://gist.github.com/103208", "doc/README"
67
+ #
68
+ # get "http://gist.github.com/103208" do |content|
69
+ # content.split("\n").first
70
+ # end
71
+ #
72
+ def get(source, *args, &block)
73
+ config = args.last.is_a?(Hash) ? args.pop : {}
74
+ destination = args.first
75
+
76
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^https?\:\/\//
77
+ render = open(source) {|input| input.binmode.read }
78
+
79
+ destination ||= if block_given?
80
+ block.arity == 1 ? block.call(render) : block.call
81
+ else
82
+ File.basename(source)
83
+ end
84
+
85
+ create_file destination, render, config
86
+ end
87
+
88
+ # Gets an ERB template at the relative source, executes it and makes a copy
89
+ # at the relative destination. If the destination is not given it's assumed
90
+ # to be equal to the source removing .tt from the filename.
91
+ #
92
+ # ==== Parameters
93
+ # source<String>:: the relative path to the source root.
94
+ # destination<String>:: the relative path to the destination root.
95
+ # config<Hash>:: give :verbose => false to not log the status.
96
+ #
97
+ # ==== Examples
98
+ #
99
+ # template "README", "doc/README"
100
+ #
101
+ # template "doc/README"
102
+ #
103
+ def template(source, *args, &block)
104
+ config = args.last.is_a?(Hash) ? args.pop : {}
105
+ destination = args.first || source
106
+
107
+ source = File.expand_path(find_in_source_paths(source.to_s))
108
+ context = instance_eval('binding')
109
+
110
+ 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
113
+ content
114
+ end
115
+ end
116
+
117
+ # Changes the mode of the given file or directory.
118
+ #
119
+ # ==== Parameters
120
+ # mode<Integer>:: the file mode
121
+ # path<String>:: the name of the file to change mode
122
+ # config<Hash>:: give :verbose => false to not log the status.
123
+ #
124
+ # ==== Example
125
+ #
126
+ # chmod "script/*", 0755
127
+ #
128
+ def chmod(path, mode, config={})
129
+ return unless behavior == :invoke
130
+ path = File.expand_path(path, destination_root)
131
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
132
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
133
+ end
134
+
135
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
136
+ #
137
+ # ==== Parameters
138
+ # path<String>:: path of the file to be changed
139
+ # data<String>:: the data to prepend to the file, can be also given as a block.
140
+ # config<Hash>:: give :verbose => false to not log the status.
141
+ #
142
+ # ==== Example
143
+ #
144
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
145
+ #
146
+ # prepend_to_file 'config/environments/test.rb' do
147
+ # 'config.gem "rspec"'
148
+ # end
149
+ #
150
+ def prepend_to_file(path, *args, &block)
151
+ config = args.last.is_a?(Hash) ? args.pop : {}
152
+ config.merge!(:after => /\A/)
153
+ insert_into_file(path, *(args << config), &block)
154
+ end
155
+ alias_method :prepend_file, :prepend_to_file
156
+
157
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
158
+ #
159
+ # ==== Parameters
160
+ # path<String>:: path of the file to be changed
161
+ # data<String>:: the data to append to the file, can be also given as a block.
162
+ # config<Hash>:: give :verbose => false to not log the status.
163
+ #
164
+ # ==== Example
165
+ #
166
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
167
+ #
168
+ # append_to_file 'config/environments/test.rb' do
169
+ # 'config.gem "rspec"'
170
+ # end
171
+ #
172
+ def append_to_file(path, *args, &block)
173
+ config = args.last.is_a?(Hash) ? args.pop : {}
174
+ config.merge!(:before => /\z/)
175
+ insert_into_file(path, *(args << config), &block)
176
+ end
177
+ alias_method :append_file, :append_to_file
178
+
179
+ # Injects text right after the class definition. Since it depends on
180
+ # insert_into_file, it's reversible.
181
+ #
182
+ # ==== Parameters
183
+ # path<String>:: path of the file to be changed
184
+ # klass<String|Class>:: the class to be manipulated
185
+ # data<String>:: the data to append to the class, can be also given as a block.
186
+ # config<Hash>:: give :verbose => false to not log the status.
187
+ #
188
+ # ==== Examples
189
+ #
190
+ # inject_into_class "app/controllers/application_controller.rb", " filter_parameter :password\n"
191
+ #
192
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController do
193
+ # " filter_parameter :password\n"
194
+ # end
195
+ #
196
+ def inject_into_class(path, klass, *args, &block)
197
+ config = args.last.is_a?(Hash) ? args.pop : {}
198
+ config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
199
+ insert_into_file(path, *(args << config), &block)
200
+ end
201
+
202
+ # Run a regular expression replacement on a file.
203
+ #
204
+ # ==== Parameters
205
+ # path<String>:: path of the file to be changed
206
+ # flag<Regexp|String>:: the regexp or string to be replaced
207
+ # replacement<String>:: the replacement, can be also given as a block
208
+ # config<Hash>:: give :verbose => false to not log the status.
209
+ #
210
+ # ==== Example
211
+ #
212
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
213
+ #
214
+ # gsub_file 'README', /rake/, :green do |match|
215
+ # match << " no more. Use thor!"
216
+ # end
217
+ #
218
+ def gsub_file(path, flag, *args, &block)
219
+ return unless behavior == :invoke
220
+ config = args.last.is_a?(Hash) ? args.pop : {}
221
+
222
+ path = File.expand_path(path, destination_root)
223
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
224
+
225
+ unless options[:pretend]
226
+ content = File.binread(path)
227
+ content.gsub!(flag, *args, &block)
228
+ File.open(path, 'wb') { |file| file.write(content) }
229
+ end
230
+ end
231
+
232
+ # Removes a file at the given location.
233
+ #
234
+ # ==== Parameters
235
+ # path<String>:: path of the file to be changed
236
+ # config<Hash>:: give :verbose => false to not log the status.
237
+ #
238
+ # ==== Example
239
+ #
240
+ # remove_file 'README'
241
+ # remove_file 'app/controllers/application_controller.rb'
242
+ #
243
+ def remove_file(path, config={})
244
+ return unless behavior == :invoke
245
+ path = File.expand_path(path, destination_root)
246
+
247
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
248
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
249
+ end
250
+ alias :remove_dir :remove_file
251
+
252
+ private
253
+ attr_accessor :output_buffer
254
+ def concat(string)
255
+ @output_buffer.concat(string)
256
+ end
257
+
258
+ def capture(*args, &block)
259
+ with_output_buffer { block.call(*args) }
260
+ end
261
+
262
+ def with_output_buffer(buf = '') #:nodoc:
263
+ self.output_buffer, old_buffer = buf, output_buffer
264
+ yield
265
+ output_buffer
266
+ ensure
267
+ self.output_buffer = old_buffer
268
+ end
269
+ end
270
+ end