wycats-thor 0.11.1 → 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/thor/actions.rb CHANGED
@@ -136,21 +136,20 @@ class Thor
136
136
  #
137
137
  # ==== Parameters
138
138
  # dir<String>:: the directory to move to.
139
+ # config<Hash>:: give :verbose => true to log and use padding.
139
140
  #
140
- def inside(dir='', &block)
141
+ def inside(dir='', config={}, &block)
142
+ verbose = config.fetch(:verbose, false)
143
+
144
+ say_status :inside, dir, verbose
145
+ shell.padding += 1 if verbose
141
146
  @destination_stack.push File.expand_path(dir, destination_root)
147
+
142
148
  FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
143
149
  FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
144
- @destination_stack.pop
145
- end
146
150
 
147
- # Same as inside, but log status and use padding.
148
- #
149
- def inside_with_padding(dir='', config={}, &block)
150
- say_status :inside, dir, config.fetch(:verbose, true)
151
- shell.padding += 1
152
- inside(dir, &block)
153
- shell.padding -= 1
151
+ @destination_stack.pop
152
+ shell.padding -= 1 if verbose
154
153
  end
155
154
 
156
155
  # Goes to the root and execute the given block.
@@ -159,24 +158,6 @@ class Thor
159
158
  inside(@destination_stack.first) { yield }
160
159
  end
161
160
 
162
- # Changes the mode of the given file or directory.
163
- #
164
- # ==== Parameters
165
- # mode<Integer>:: the file mode
166
- # path<String>:: the name of the file to change mode
167
- # config<Hash>:: give :verbose => false to not log the status.
168
- #
169
- # ==== Example
170
- #
171
- # chmod "script/*", 0755
172
- #
173
- def chmod(path, mode, config={})
174
- return unless behavior == :invoke
175
- path = File.expand_path(path, destination_root)
176
- say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
177
- FileUtils.chmod_R(mode, path) unless options[:pretend]
178
- end
179
-
180
161
  # Executes a command.
181
162
  #
182
163
  # ==== Parameters
@@ -191,8 +172,7 @@ class Thor
191
172
  #
192
173
  def run(command, config={})
193
174
  return unless behavior == :invoke
194
- description = "#{command.inspect} from #{relative_to_original_destination_root(destination_root, false)}"
195
- say_status :run, description, config.fetch(:verbose, true)
175
+ say_status :run, command, config.fetch(:verbose, true)
196
176
  `#{command}` unless options[:pretend]
197
177
  end
198
178
 
@@ -214,8 +194,8 @@ class Thor
214
194
  # ==== Parameters
215
195
  # task<String>:: the task to be invoked
216
196
  # args<Array>:: arguments to the task
217
- # options<Hash>:: give :verbose => false to not log the status. Other options
218
- # are given as parameter to Thor.
197
+ # config<Hash>:: give :verbose => false to not log the status. Other options
198
+ # are given as parameter to Thor.
219
199
  #
220
200
  # ==== Examples
221
201
  #
@@ -237,96 +217,6 @@ class Thor
237
217
  run "thor #{command}", :verbose => false
238
218
  end
239
219
 
240
- # Removes a file at the given location.
241
- #
242
- # ==== Parameters
243
- # path<String>:: path of the file to be changed
244
- # config<Hash>:: give :verbose => false to not log the status.
245
- #
246
- # ==== Example
247
- #
248
- # remove_file 'README'
249
- # remove_file 'app/controllers/application_controller.rb'
250
- #
251
- def remove_file(path, config={})
252
- return unless behavior == :invoke
253
- path = File.expand_path(path, destination_root)
254
-
255
- say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
256
- ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
257
- end
258
-
259
- # Run a regular expression replacement on a file.
260
- #
261
- # ==== Parameters
262
- # path<String>:: path of the file to be changed
263
- # flag<Regexp|String>:: the regexp or string to be replaced
264
- # replacement<String>:: the replacement, can be also given as a block
265
- # config<Hash>:: give :verbose => false to not log the status.
266
- #
267
- # ==== Example
268
- #
269
- # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
270
- #
271
- # gsub_file 'README', /rake/, :green do |match|
272
- # match << " no more. Use thor!"
273
- # end
274
- #
275
- def gsub_file(path, flag, *args, &block)
276
- return unless behavior == :invoke
277
- config = args.last.is_a?(Hash) ? args.pop : {}
278
-
279
- path = File.expand_path(path, destination_root)
280
- say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
281
-
282
- unless options[:pretend]
283
- content = File.read(path)
284
- content.gsub!(flag, *args, &block)
285
- File.open(path, 'wb') { |file| file.write(content) }
286
- end
287
- end
288
-
289
- # Append text to a file.
290
- #
291
- # ==== Parameters
292
- # path<String>:: path of the file to be changed
293
- # data<String>:: the data to append to the file, can be also given as a block.
294
- # config<Hash>:: give :verbose => false to not log the status.
295
- #
296
- # ==== Example
297
- #
298
- # append_file 'config/environments/test.rb', 'config.gem "rspec"'
299
- #
300
- def append_file(path, data=nil, config={}, &block)
301
- return unless behavior == :invoke
302
- path = File.expand_path(path, destination_root)
303
- say_status :append, relative_to_original_destination_root(path), config.fetch(:verbose, true)
304
- File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
305
- end
306
-
307
- # Prepend text to a file.
308
- #
309
- # ==== Parameters
310
- # path<String>:: path of the file to be changed
311
- # data<String>:: the data to prepend to the file, can be also given as a block.
312
- # config<Hash>:: give :verbose => false to not log the status.
313
- #
314
- # ==== Example
315
- #
316
- # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
317
- #
318
- def prepend_file(path, data=nil, config={}, &block)
319
- return unless behavior == :invoke
320
- path = File.expand_path(path, destination_root)
321
- say_status :prepend, relative_to_original_destination_root(path), config.fetch(:verbose, true)
322
-
323
- unless options[:pretend]
324
- content = data || block.call
325
- content << File.read(path)
326
- File.open(path, 'wb') { |file| file.write(content) }
327
- end
328
- end
329
-
330
220
  protected
331
221
 
332
222
  # Allow current root to be shared between invocations.
@@ -1,4 +1,4 @@
1
- require 'thor/actions/templater'
1
+ require 'thor/actions/empty_directory'
2
2
 
3
3
  class Thor
4
4
  module Actions
@@ -28,14 +28,25 @@ class Thor
28
28
  # AddFile is a subset of Template, which instead of rendering a file with
29
29
  # ERB, it gets the content from the user.
30
30
  #
31
- class CreateFile < Templater #:nodoc:
31
+ class CreateFile < EmptyDirectory #:nodoc:
32
32
  attr_reader :data
33
33
 
34
34
  def initialize(base, destination, data, config={})
35
- super(base, nil, destination, config)
36
35
  @data = data
36
+ super(base, destination, config)
37
37
  end
38
38
 
39
+ # Checks if the content of the file at the destination is identical to the rendered result.
40
+ #
41
+ # ==== Returns
42
+ # Boolean:: true if it is identical, false otherwise.
43
+ #
44
+ def identical?
45
+ exists? && File.read(destination) == render
46
+ end
47
+
48
+ # Holds the content to be added to the file.
49
+ #
39
50
  def render
40
51
  @render ||= if data.is_a?(Proc)
41
52
  data.call
@@ -44,6 +55,48 @@ class Thor
44
55
  end
45
56
  end
46
57
 
58
+ def invoke!
59
+ invoke_with_conflict_check do
60
+ FileUtils.mkdir_p(File.dirname(destination))
61
+ File.open(destination, 'w'){ |f| f.write render }
62
+ end
63
+ end
64
+
65
+ protected
66
+
67
+ # Now on conflict we check if the file is identical or not.
68
+ #
69
+ def on_conflict_behavior(&block)
70
+ if identical?
71
+ say_status :identical, :blue
72
+ else
73
+ options = base.options.merge(config)
74
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
75
+ end
76
+ end
77
+
78
+ # If force is true, run the action, otherwise check if it's not being
79
+ # skipped. If both are false, show the file_collision menu, if the menu
80
+ # returns true, force it, otherwise skip.
81
+ #
82
+ def force_or_skip_or_conflict(force, skip, &block)
83
+ if force
84
+ say_status :force, :yellow
85
+ block.call unless pretend?
86
+ elsif skip
87
+ say_status :skip, :yellow
88
+ else
89
+ say_status :conflict, :red
90
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
91
+ end
92
+ end
93
+
94
+ # Shows the file collision menu to the user and gets the result.
95
+ #
96
+ def force_on_collision?
97
+ base.shell.file_collision(destination){ render }
98
+ end
99
+
47
100
  end
48
101
  end
49
102
  end
@@ -1,4 +1,4 @@
1
- require 'thor/actions/templater'
1
+ require 'thor/actions/empty_directory'
2
2
 
3
3
  class Thor
4
4
  module Actions
@@ -44,9 +44,12 @@ class Thor
44
44
  action Directory.new(self, source, destination || source, config)
45
45
  end
46
46
 
47
- class Directory < Templater #:nodoc:
47
+ class Directory < EmptyDirectory #:nodoc:
48
+ attr_reader :source
49
+
48
50
  def initialize(base, source, destination=nil, config={})
49
- super(base, source, destination, { :recursive => true }.merge(config))
51
+ @source = File.expand_path(base.find_in_source_paths(source.to_s))
52
+ super(base, destination, { :recursive => true }.merge(config))
50
53
  end
51
54
 
52
55
  def invoke!
@@ -1,5 +1,3 @@
1
- require 'thor/actions/templater'
2
-
3
1
  class Thor
4
2
  module Actions
5
3
 
@@ -14,17 +12,122 @@ class Thor
14
12
  # empty_directory "doc"
15
13
  #
16
14
  def empty_directory(destination, config={})
17
- action EmptyDirectory.new(self, nil, destination, config)
15
+ action EmptyDirectory.new(self, destination, config)
18
16
  end
19
17
 
20
- class EmptyDirectory < Templater #:nodoc:
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
21
48
 
22
49
  def invoke!
23
- invoke_with_options!(base.options.merge(config)) do
50
+ invoke_with_conflict_check do
24
51
  ::FileUtils.mkdir_p(destination)
25
52
  end
26
53
  end
27
54
 
55
+ def revoke!
56
+ say_status :remove, :red
57
+ ::FileUtils.rm_rf(destination) if !pretend? && exists?
58
+ end
59
+
60
+ protected
61
+
62
+ # Shortcut for pretend.
63
+ #
64
+ def pretend?
65
+ base.options[:pretend]
66
+ end
67
+
68
+ # Sets the absolute destination value from a relative destination value.
69
+ # It also stores the given and relative destination. Let's suppose our
70
+ # script is being executed on "dest", it sets the destination root to
71
+ # "dest". The destination, given_destination and relative_destination
72
+ # are related in the following way:
73
+ #
74
+ # inside "bar" do
75
+ # empty_directory "baz"
76
+ # end
77
+ #
78
+ # destination #=> dest/bar/baz
79
+ # relative_destination #=> bar/baz
80
+ # given_destination #=> baz
81
+ #
82
+ def destination=(destination)
83
+ if destination
84
+ @given_destination = convert_encoded_instructions(destination.to_s)
85
+ @destination = ::File.expand_path(@given_destination, base.destination_root)
86
+ @relative_destination = base.relative_to_original_destination_root(@destination)
87
+ end
88
+ end
89
+
90
+ # Filenames in the encoded form are converted. If you have a file:
91
+ #
92
+ # %class_name%.rb
93
+ #
94
+ # It gets the class name from the base and replace it:
95
+ #
96
+ # user.rb
97
+ #
98
+ def convert_encoded_instructions(filename)
99
+ filename.gsub(/%(.*?)%/) do |string|
100
+ instruction = $1.strip
101
+ base.respond_to?(instruction) ? base.send(instruction) : string
102
+ end
103
+ end
104
+
105
+ # Receives a hash of options and just execute the block if some
106
+ # conditions are met.
107
+ #
108
+ def invoke_with_conflict_check(&block)
109
+ if exists?
110
+ on_conflict_behavior(&block)
111
+ else
112
+ say_status :create, :green
113
+ block.call unless pretend?
114
+ end
115
+
116
+ destination
117
+ end
118
+
119
+ # What to do when the destination file already exists.
120
+ #
121
+ def on_conflict_behavior(&block)
122
+ say_status :exist, :blue
123
+ end
124
+
125
+ # Shortcut to say_status shell method.
126
+ #
127
+ def say_status(status, color)
128
+ base.shell.say_status status, relative_destination, color if config[:verbose]
129
+ end
130
+
28
131
  end
29
132
  end
30
133
  end
@@ -0,0 +1,194 @@
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, destination=nil, config={})
22
+ destination ||= source
23
+ source = File.expand_path(find_in_source_paths(source.to_s))
24
+
25
+ create_file destination, nil, config do
26
+ File.read(source)
27
+ end
28
+ end
29
+
30
+ # Gets the content at the given address and places it at the given relative
31
+ # destination. If a block is given instead of destination, the content of
32
+ # the url is yielded and used as location.
33
+ #
34
+ # ==== Parameters
35
+ # source<String>:: the address of the given content.
36
+ # destination<String>:: the relative path to the destination root.
37
+ # config<Hash>:: give :verbose => false to not log the status.
38
+ #
39
+ # ==== Examples
40
+ #
41
+ # get "http://gist.github.com/103208", "doc/README"
42
+ #
43
+ # get "http://gist.github.com/103208" do |content|
44
+ # content.split("\n").first
45
+ # end
46
+ #
47
+ def get(source, destination=nil, config={}, &block)
48
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
49
+ render = open(source).read
50
+
51
+ destination ||= if block_given?
52
+ block.arity == 1 ? block.call(render) : block.call
53
+ else
54
+ File.basename(source)
55
+ end
56
+
57
+ create_file destination, render, config
58
+ end
59
+
60
+ # Gets an ERB template at the relative source, executes it and makes a copy
61
+ # at the relative destination. If the destination is not given it's assumed
62
+ # to be equal to the source removing .tt from the filename.
63
+ #
64
+ # ==== Parameters
65
+ # source<String>:: the relative path to the source root.
66
+ # destination<String>:: the relative path to the destination root.
67
+ # config<Hash>:: give :verbose => false to not log the status.
68
+ #
69
+ # ==== Examples
70
+ #
71
+ # template "README", "doc/README"
72
+ #
73
+ # template "doc/README"
74
+ #
75
+ def template(source, destination=nil, config={})
76
+ destination ||= source
77
+ source = File.expand_path(find_in_source_paths(source.to_s))
78
+ context = instance_eval('binding')
79
+
80
+ create_file destination, nil, config do
81
+ ERB.new(::File.read(source), nil, '-').result(context)
82
+ end
83
+ end
84
+
85
+ # Changes the mode of the given file or directory.
86
+ #
87
+ # ==== Parameters
88
+ # mode<Integer>:: the file mode
89
+ # path<String>:: the name of the file to change mode
90
+ # config<Hash>:: give :verbose => false to not log the status.
91
+ #
92
+ # ==== Example
93
+ #
94
+ # chmod "script/*", 0755
95
+ #
96
+ def chmod(path, mode, config={})
97
+ return unless behavior == :invoke
98
+ path = File.expand_path(path, destination_root)
99
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
100
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
101
+ end
102
+
103
+ # Prepend text to a file.
104
+ #
105
+ # ==== Parameters
106
+ # path<String>:: path of the file to be changed
107
+ # data<String>:: the data to prepend to the file, can be also given as a block.
108
+ # config<Hash>:: give :verbose => false to not log the status.
109
+ #
110
+ # ==== Example
111
+ #
112
+ # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
113
+ #
114
+ def prepend_file(path, data=nil, config={}, &block)
115
+ return unless behavior == :invoke
116
+ path = File.expand_path(path, destination_root)
117
+ say_status :prepend, relative_to_original_destination_root(path), config.fetch(:verbose, true)
118
+
119
+ unless options[:pretend]
120
+ content = data || block.call
121
+ content << File.read(path)
122
+ File.open(path, 'wb') { |file| file.write(content) }
123
+ end
124
+ end
125
+
126
+ # Append text to a file.
127
+ #
128
+ # ==== Parameters
129
+ # path<String>:: path of the file to be changed
130
+ # data<String>:: the data to append to the file, can be also given as a block.
131
+ # config<Hash>:: give :verbose => false to not log the status.
132
+ #
133
+ # ==== Example
134
+ #
135
+ # append_file 'config/environments/test.rb', 'config.gem "rspec"'
136
+ #
137
+ def append_file(path, data=nil, config={}, &block)
138
+ return unless behavior == :invoke
139
+ path = File.expand_path(path, destination_root)
140
+ say_status :append, relative_to_original_destination_root(path), config.fetch(:verbose, true)
141
+ File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
142
+ end
143
+
144
+ # Run a regular expression replacement on a file.
145
+ #
146
+ # ==== Parameters
147
+ # path<String>:: path of the file to be changed
148
+ # flag<Regexp|String>:: the regexp or string to be replaced
149
+ # replacement<String>:: the replacement, can be also given as a block
150
+ # config<Hash>:: give :verbose => false to not log the status.
151
+ #
152
+ # ==== Example
153
+ #
154
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
155
+ #
156
+ # gsub_file 'README', /rake/, :green do |match|
157
+ # match << " no more. Use thor!"
158
+ # end
159
+ #
160
+ def gsub_file(path, flag, *args, &block)
161
+ return unless behavior == :invoke
162
+ config = args.last.is_a?(Hash) ? args.pop : {}
163
+
164
+ path = File.expand_path(path, destination_root)
165
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
166
+
167
+ unless options[:pretend]
168
+ content = File.read(path)
169
+ content.gsub!(flag, *args, &block)
170
+ File.open(path, 'wb') { |file| file.write(content) }
171
+ end
172
+ end
173
+
174
+ # Removes a file at the given location.
175
+ #
176
+ # ==== Parameters
177
+ # path<String>:: path of the file to be changed
178
+ # config<Hash>:: give :verbose => false to not log the status.
179
+ #
180
+ # ==== Example
181
+ #
182
+ # remove_file 'README'
183
+ # remove_file 'app/controllers/application_controller.rb'
184
+ #
185
+ def remove_file(path, config={})
186
+ return unless behavior == :invoke
187
+ path = File.expand_path(path, destination_root)
188
+
189
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
190
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
191
+ end
192
+
193
+ end
194
+ end
@@ -1,3 +1,5 @@
1
+ require 'thor/actions/empty_directory'
2
+
1
3
  class Thor
2
4
  module Actions
3
5
 
@@ -32,13 +34,12 @@ class Thor
32
34
  action InjectIntoFile.new(self, destination, data, config)
33
35
  end
34
36
 
35
- class InjectIntoFile #:nodoc:
36
- attr_reader :base, :destination, :relative_destination, :flag, :replacement, :config
37
+ class InjectIntoFile < EmptyDirectory
38
+ attr_reader :flag, :replacement
37
39
 
38
40
  def initialize(base, destination, data, config)
39
- @base, @config = base, { :verbose => true }.merge(config)
41
+ super(base, destination, { :verbose => true }.merge(config))
40
42
 
41
- self.destination = destination
42
43
  data = data.call if data.is_a?(Proc)
43
44
 
44
45
  @replacement = if @config.key?(:after)
@@ -51,33 +52,17 @@ class Thor
51
52
  end
52
53
 
53
54
  def invoke!
54
- say_status :inject
55
+ say_status :inject, config[:verbose]
55
56
  replace!(flag, replacement)
56
57
  end
57
58
 
58
59
  def revoke!
59
- say_status :deinject
60
+ say_status :deinject, config[:verbose]
60
61
  replace!(replacement, flag)
61
62
  end
62
63
 
63
64
  protected
64
65
 
65
- # Sets the destination value from a relative destination value. The
66
- # relative destination is kept to be used in output messages.
67
- #
68
- def destination=(destination)
69
- if destination
70
- @destination = ::File.expand_path(destination.to_s, base.destination_root)
71
- @relative_destination = base.relative_to_original_destination_root(@destination)
72
- end
73
- end
74
-
75
- # Shortcut to say_status shell method.
76
- #
77
- def say_status(status)
78
- base.shell.say_status status, relative_destination, config[:verbose]
79
- end
80
-
81
66
  # Adds the content to the file.
82
67
  #
83
68
  def replace!(regexp, string)
data/lib/thor/group.rb CHANGED
@@ -87,7 +87,7 @@ class Thor::Group
87
87
  if klass
88
88
  say_status :invoke, #{name.inspect}, #{verbose.inspect}
89
89
  block = self.class.invocation_blocks[#{name.inspect}]
90
- invoke_with_padding klass, task, &block
90
+ _invoke_for_class_method klass, task, &block
91
91
  else
92
92
  say_status :error, %(#{name.inspect} [not found]), :red
93
93
  end
@@ -150,7 +150,7 @@ class Thor::Group
150
150
  if klass
151
151
  say_status :invoke, value, #{verbose.inspect}
152
152
  block = self.class.invocation_blocks[#{name.inspect}]
153
- invoke_with_padding klass, task, &block
153
+ _invoke_for_class_method klass, task, &block
154
154
  else
155
155
  say_status :error, %(\#{value} [not found]), :red
156
156
  end
@@ -237,4 +237,26 @@ class Thor::Group
237
237
  end
238
238
 
239
239
  include Thor::Base
240
+
241
+ protected
242
+
243
+ # Shortcut to invoke with padding and block handling. Use internally by
244
+ # invoke and invoke_from_option class methods.
245
+ #
246
+ def _invoke_for_class_method(klass, task=nil, *args, &block)
247
+ shell.padding += 1
248
+
249
+ result = if block_given?
250
+ if block.arity == 2
251
+ block.call(self, klass)
252
+ else
253
+ block.call(self, klass, task)
254
+ end
255
+ else
256
+ invoke klass, task, *args
257
+ end
258
+
259
+ shell.padding -= 1
260
+ result
261
+ end
240
262
  end
@@ -130,26 +130,6 @@ class Thor
130
130
  end
131
131
  end
132
132
 
133
- # Shortcut for invoke with padding and status handling. Used internally by
134
- # class options invoke and invoke_from_option.
135
- #
136
- def invoke_with_padding(klass, task=nil, *args, &block)
137
- shell.padding += 1
138
-
139
- result = if block_given?
140
- if block.arity == 2
141
- block.call(self, klass)
142
- else
143
- block.call(self, klass, task)
144
- end
145
- else
146
- invoke klass, task, *args
147
- end
148
-
149
- shell.padding -= 1
150
- result
151
- end
152
-
153
133
  protected
154
134
 
155
135
  # Configuration values that are shared between invocations.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wycats-thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -37,14 +37,11 @@ files:
37
37
  - lib/thor/base.rb
38
38
  - lib/thor/group.rb
39
39
  - lib/thor/actions
40
- - lib/thor/actions/templater.rb
41
- - lib/thor/actions/copy_file.rb
42
40
  - lib/thor/actions/inject_into_file.rb
43
41
  - lib/thor/actions/directory.rb
44
- - lib/thor/actions/template.rb
45
- - lib/thor/actions/get.rb
46
42
  - lib/thor/actions/create_file.rb
47
43
  - lib/thor/actions/empty_directory.rb
44
+ - lib/thor/actions/file_manipulation.rb
48
45
  - lib/thor/util.rb
49
46
  - lib/thor/runner.rb
50
47
  - lib/thor/actions.rb
@@ -1,32 +0,0 @@
1
- require 'thor/actions/templater'
2
-
3
- class Thor
4
- module Actions
5
-
6
- # Copies the file from the relative source to the relative destination. If
7
- # the destination is not given it's assumed to be equal to the source.
8
- #
9
- # ==== Parameters
10
- # source<String>:: the relative path to the source root.
11
- # destination<String>:: the relative path to the destination root.
12
- # config<Hash>:: give :verbose => false to not log the status.
13
- #
14
- # ==== Examples
15
- #
16
- # copy_file "README", "doc/README"
17
- #
18
- # copy_file "doc/README"
19
- #
20
- def copy_file(source, destination=nil, config={})
21
- action CopyFile.new(self, source, destination || source, config)
22
- end
23
-
24
- class CopyFile < Templater #:nodoc:
25
-
26
- def render
27
- @render ||= ::File.read(source)
28
- end
29
-
30
- end
31
- end
32
- end
@@ -1,58 +0,0 @@
1
- require 'thor/actions/templater'
2
- require 'open-uri'
3
-
4
- class Thor
5
- module Actions
6
-
7
- # Gets the content at the given address and places it at the given relative
8
- # destination. If a block is given instead of destination, the content of
9
- # the url is yielded and used as location.
10
- #
11
- # ==== Parameters
12
- # source<String>:: the address of the given content.
13
- # destination<String>:: the relative path to the destination root.
14
- # config<Hash>:: give :verbose => false to not log the status.
15
- #
16
- # ==== Examples
17
- #
18
- # get "http://gist.github.com/103208", "doc/README"
19
- #
20
- # get "http://gist.github.com/103208" do |content|
21
- # content.split("\n").first
22
- # end
23
- #
24
- def get(source, destination=nil, config={}, &block)
25
- action Get.new(self, source, block || destination, config)
26
- end
27
-
28
- class Get < Templater #:nodoc:
29
-
30
- def render
31
- @render ||= open(source).read
32
- end
33
-
34
- protected
35
-
36
- def source=(source)
37
- if source =~ /^http\:\/\//
38
- @source = source
39
- else
40
- super(source)
41
- end
42
- end
43
-
44
- def destination=(destination)
45
- destination = if destination.nil?
46
- File.basename(source)
47
- elsif destination.is_a?(Proc)
48
- destination.arity == 1 ? destination.call(render) : destination.call
49
- else
50
- destination
51
- end
52
-
53
- super(destination)
54
- end
55
-
56
- end
57
- end
58
- end
@@ -1,38 +0,0 @@
1
- require 'thor/actions/templater'
2
- require 'erb'
3
-
4
- class Thor
5
- module Actions
6
-
7
- # Gets an ERB template at the relative source, executes it and makes a copy
8
- # at the relative destination. If the destination is not given it's assumed
9
- # to be equal to the source removing .tt from the filename.
10
- #
11
- # ==== Parameters
12
- # source<String>:: the relative path to the source root.
13
- # destination<String>:: the relative path to the destination root.
14
- # config<Hash>:: give :verbose => false to not log the status.
15
- #
16
- # ==== Examples
17
- #
18
- # template "README", "doc/README"
19
- #
20
- # template "doc/README"
21
- #
22
- def template(source, destination=nil, config={})
23
- destination ||= source.gsub(/.tt$/, '')
24
- action Template.new(self, source, destination, config)
25
- end
26
-
27
- class Template < Templater #:nodoc:
28
-
29
- def render
30
- @render ||= begin
31
- context = base.instance_eval('binding')
32
- ERB.new(::File.read(source), nil, '-').result(context)
33
- end
34
- end
35
-
36
- end
37
- end
38
- end
@@ -1,194 +0,0 @@
1
- class Thor
2
- module Actions
3
-
4
- # This is the base class for templater actions, ie. that copies something
5
- # from some directory (source) to another (destination).
6
- #
7
- # This implementation is completely based in Templater actions, created
8
- # by Jonas Nicklas and Michael S. Klishin under MIT LICENSE.
9
- #
10
- class Templater #:nodoc:
11
- attr_reader :base, :source, :destination, :given_destination, :relative_destination, :config
12
-
13
- # Initializes given the source and destination.
14
- #
15
- # ==== Parameters
16
- # base<Thor::Base>:: A Thor::Base instance
17
- # source<String>:: Relative path to the source of this file
18
- # destination<String>:: Relative path to the destination of this file
19
- # config<Hash>:: give :verbose => false to not log the status.
20
- #
21
- def initialize(base, source, destination, config={})
22
- @base, @config = base, { :verbose => true }.merge(config)
23
- self.source = source
24
- self.destination = destination
25
- end
26
-
27
- # Returns the contents of the source file as a String. If render is
28
- # available, a diff option is shown in the file collision menu.
29
- #
30
- # ==== Returns
31
- # String:: The source file.
32
- #
33
- # def render
34
- # end
35
-
36
- # Checks if the destination file already exists.
37
- #
38
- # ==== Returns
39
- # Boolean:: true if the file exists, false otherwise.
40
- #
41
- def exists?
42
- ::File.exists?(destination)
43
- end
44
-
45
- # Checks if the content of the file at the destination is identical to the rendered result.
46
- #
47
- # ==== Returns
48
- # Boolean:: true if it is identical, false otherwise.
49
- #
50
- def identical?
51
- exists? && (is_not_comparable? || ::File.read(destination) == render)
52
- end
53
-
54
- # Invokes the action. By default it adds to the file the content rendered,
55
- # but you can modify in the subclass.
56
- #
57
- def invoke!
58
- invoke_with_options!(base.options.merge(config)) do
59
- ::FileUtils.mkdir_p(::File.dirname(destination))
60
- ::File.open(destination, 'w'){ |f| f.write render }
61
- end
62
- end
63
-
64
- # Revokes the action.
65
- #
66
- def revoke!
67
- say_status :remove, :red
68
- ::FileUtils.rm_rf(destination) if !pretend? && exists?
69
- end
70
-
71
- protected
72
-
73
- # Shortcut for pretend.
74
- #
75
- def pretend?
76
- base.options[:pretend]
77
- end
78
-
79
- # A templater is comparable if responds to render. In such cases, we have
80
- # to show the conflict menu to the user unless the files are identical.
81
- #
82
- def is_not_comparable?
83
- !respond_to?(:render)
84
- end
85
-
86
- # Sets the absolute source value from a relative source value. Notice
87
- # that we need to take into consideration both the source_root as the
88
- # relative_root.
89
- #
90
- # Let's suppose that we are on the directory "dest", with source root set
91
- # to "source" and with the following scenario:
92
- #
93
- # inside "bar" do
94
- # copy_file "baz.rb"
95
- # end
96
- #
97
- # In this case, the user wants to copy the file at "source/bar/baz.rb"
98
- # to "dest/bar/baz.rb". If we don't take into account the relative_root
99
- # (in this case, "bar"), it would copy the contents at "source/baz.rb".
100
- #
101
- def source=(source)
102
- if source
103
- @source = ::File.expand_path(base.find_in_source_paths(source.to_s))
104
- end
105
- end
106
-
107
- # Sets the absolute destination value from a relative destination value.
108
- # It also stores the given and relative destination. Let's suppose our
109
- # script is being executed on "dest", it sets the destination root to
110
- # "dest". The destination, given_destination and relative_destination
111
- # are related in the following way:
112
- #
113
- # inside "bar" do
114
- # empty_directory "baz"
115
- # end
116
- #
117
- # destination #=> dest/bar/baz
118
- # relative_destination #=> bar/baz
119
- # given_destination #=> baz
120
- #
121
- def destination=(destination)
122
- if destination
123
- @given_destination = convert_encoded_instructions(destination.to_s)
124
- @destination = ::File.expand_path(@given_destination, base.destination_root)
125
- @relative_destination = base.relative_to_original_destination_root(@destination)
126
- end
127
- end
128
-
129
- # Filenames in the encoded form are converted. If you have a file:
130
- #
131
- # %class_name%.rb
132
- #
133
- # It gets the class name from the base and replace it:
134
- #
135
- # user.rb
136
- #
137
- def convert_encoded_instructions(filename)
138
- filename.gsub(/%(.*?)%/) do |string|
139
- instruction = $1.strip
140
- base.respond_to?(instruction) ? base.send(instruction) : string
141
- end
142
- end
143
-
144
- # Receives a hash of options and just execute the block if some
145
- # conditions are met.
146
- #
147
- def invoke_with_options!(options, &block)
148
- if exists?
149
- if is_not_comparable?
150
- say_status :exist, :blue
151
- elsif identical?
152
- say_status :identical, :blue
153
- else
154
- force_or_skip_or_conflict(options[:force], options[:skip], &block)
155
- end
156
- else
157
- say_status :create, :green
158
- block.call unless pretend?
159
- end
160
-
161
- destination
162
- end
163
-
164
- # If force is true, run the action, otherwise check if it's not being
165
- # skipped. If both are false, show the file_collision menu, if the menu
166
- # returns true, force it, otherwise skip.
167
- #
168
- def force_or_skip_or_conflict(force, skip, &block)
169
- if force
170
- say_status :force, :yellow
171
- block.call unless pretend?
172
- elsif skip
173
- say_status :skip, :yellow
174
- else
175
- say_status :conflict, :red
176
- force_or_skip_or_conflict(force_on_collision?, true, &block)
177
- end
178
- end
179
-
180
- # Shows the file collision menu to the user and gets the result.
181
- #
182
- def force_on_collision?
183
- base.shell.file_collision(destination){ render }
184
- end
185
-
186
- # Shortcut to say_status shell method.
187
- #
188
- def say_status(status, color)
189
- base.shell.say_status status, relative_destination, color if config[:verbose]
190
- end
191
-
192
- end
193
- end
194
- end