josevalim-thor 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,27 @@ class Thor
4
4
  module Actions
5
5
 
6
6
  # Copies interactively the files from source directory to root directory.
7
- # Use it just to copy static files.
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. Remember that
9
+ # file paths can also be encoded, let's suppose a doc directory with the
10
+ # following files:
11
+ #
12
+ # doc/
13
+ # README
14
+ # rdoc.rb.tt
15
+ # %app_name%.rb
16
+ #
17
+ # When invoked as:
18
+ #
19
+ # directory "doc"
20
+ #
21
+ # It will create a doc directory in the destination with the following
22
+ # files (assuming that the app_name is "blog"):
23
+ #
24
+ # doc/
25
+ # README
26
+ # rdoc.rb
27
+ # blog.rb
8
28
  #
9
29
  # ==== Parameters
10
30
  # source<String>:: the relative path to the source root
@@ -22,12 +42,17 @@ class Thor
22
42
  class Directory < Templater #:nodoc:
23
43
 
24
44
  def invoke!
25
- files = Dir[File.join(source, '**', '*')].select{ |f| !File.directory?(f) }
45
+ Dir[File.join(source, '**', '*')].each do |file_source|
46
+ next if File.directory?(file_source)
26
47
 
27
- files.each do |file_source|
28
48
  file_destination = File.join(relative_destination, file_source.gsub(source, ''))
29
49
  file_source.gsub!(base.source_root, '.')
30
- base.copy_file(file_source, file_destination, @log_status)
50
+
51
+ if file_source =~ /.tt$/
52
+ base.template(file_source, file_destination[0..-4], @log_status)
53
+ else
54
+ base.copy_file(file_source, file_destination, @log_status)
55
+ end
31
56
  end
32
57
  end
33
58
 
@@ -6,7 +6,7 @@ class Thor
6
6
 
7
7
  # Gets an ERB template at the relative source, executes it and makes a copy
8
8
  # at the relative destination. If the destination is not given it's assumed
9
- # to be equal to the source.
9
+ # to be equal to the source removing .tt from the filename.
10
10
  #
11
11
  # ==== Parameters
12
12
  # source<String>:: the relative path to the source root
@@ -20,7 +20,8 @@ class Thor
20
20
  # template "doc/README"
21
21
  #
22
22
  def template(source, destination=nil, log_status=true)
23
- action Template.new(self, source, destination || source, log_status)
23
+ destination ||= source.gsub('.tt$', '')
24
+ action Template.new(self, source, destination, log_status)
24
25
  end
25
26
 
26
27
  class Template < Templater #:nodoc:
@@ -97,11 +97,26 @@ class Thor
97
97
  #
98
98
  def destination=(destination)
99
99
  if destination
100
- @destination = ::File.expand_path(destination.to_s, base.destination_root)
100
+ @destination = ::File.expand_path(convert_encoded_instructions(destination.to_s), base.destination_root)
101
101
  @relative_destination = base.relative_to_absolute_root(@destination)
102
102
  end
103
103
  end
104
104
 
105
+ # Filenames in the encoded form are converted. If you have a file:
106
+ #
107
+ # %class_name%.rb
108
+ #
109
+ # It gets the class name from the base and replace it:
110
+ #
111
+ # user.rb
112
+ #
113
+ def convert_encoded_instructions(filename)
114
+ filename.gsub(/%(.*?)%/) do |string|
115
+ instruction = $1.strip
116
+ base.respond_to?(instruction) ? base.send(instruction) : string
117
+ end
118
+ end
119
+
105
120
  # Receives a hash of options and just execute the block if some
106
121
  # conditions are met.
107
122
  #
@@ -118,6 +133,8 @@ class Thor
118
133
  say_status :create, :green
119
134
  block.call unless pretend?
120
135
  end
136
+
137
+ destination
121
138
  end
122
139
 
123
140
  # If force is true, run the action, otherwise check if it's not being
@@ -148,16 +165,6 @@ class Thor
148
165
  base.shell.say_status status, relative_destination, color if @log_status
149
166
  end
150
167
 
151
- # TODO Add this behavior to all actions.
152
- #
153
- def after_invoke
154
- # Optionally change permissions.
155
- FileUtils.chmod(base.options[:chmod], destination) if base.options[:chmod]
156
-
157
- # Optionally add file to subversion or git
158
- system("git add -v #{relative_destination}") if options[:git]
159
- end
160
-
161
168
  end
162
169
  end
163
170
  end
data/lib/thor/actions.rb CHANGED
@@ -13,25 +13,17 @@ class Thor
13
13
  def self.included(base) #:nodoc:
14
14
  return unless base.respond_to?(:class_option)
15
15
 
16
- base.class_option :pretend, :type => :boolean, :aliases => "-p",
16
+ base.class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
17
17
  :desc => "Run but do not make any changes"
18
18
 
19
- base.class_option :force, :type => :boolean, :aliases => "-f",
19
+ base.class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
20
20
  :desc => "Overwrite files that already exist"
21
21
 
22
- base.class_option :skip, :type => :boolean, :aliases => "-s",
22
+ base.class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
23
23
  :desc => "Skip files that already exist"
24
24
 
25
- base.class_option :quiet, :type => :boolean, :aliases => "-q",
25
+ base.class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
26
26
  :desc => "Supress status output"
27
-
28
- # TODO Add git support
29
- base.class_option :git, :type => :boolean, :aliases => "-g",
30
- :desc => "Modify files with git (note: git must be on the path)"
31
-
32
- # TODO Add chmod support
33
- base.class_option :chmod, :type => :string, :aliases => "-c",
34
- :desc => "Set the mode of added/copied files"
35
27
  end
36
28
 
37
29
  # Extends initializer to add more configuration options.
@@ -136,6 +128,154 @@ class Thor
136
128
  inside(@root_stack.first) { yield }
137
129
  end
138
130
 
131
+ # Changes the mode of the given file or directory.
132
+ #
133
+ # ==== Parameters
134
+ # mode<Integer>:: the file mode
135
+ # path<String>:: the name of the file to change mode
136
+ # log_status<Boolean>:: if false, does not log the status. True by default.
137
+ # If a symbol is given, uses it as the output color.
138
+ #
139
+ # ==== Example
140
+ #
141
+ # chmod "script/*", 0755
142
+ #
143
+ def chmod(mode, path, log_status=true)
144
+ path = File.expand_path(path, root)
145
+ say_status_if_log :chmod, relative_to_absolute_root(path), log_status
146
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
147
+ end
148
+
149
+ # Executes a command.
150
+ #
151
+ # ==== Parameters
152
+ # command<String>:: the command to be executed.
153
+ # log_status<Boolean>:: if false, does not log the status. True by default.
154
+ # If a symbol is given, uses it as the output color.
155
+ #
156
+ # ==== Example
157
+ #
158
+ # inside('vendor') do
159
+ # run('ln -s ~/edge rails')
160
+ # end
161
+ #
162
+ def run(command, log_status=true)
163
+ say_status_if_log :run, "#{command} from #{relative_to_absolute_root(root, false)}", log_status
164
+ `#{command}` unless options[:pretend]
165
+ end
166
+
167
+ # Executes a ruby script (taking into account WIN32 platform quirks).
168
+ #
169
+ # ==== Parameters
170
+ # command<String>:: the command to be executed.
171
+ # log_status<Boolean>:: if false, does not log the status. True by default.
172
+ # If a symbol is given, uses it as the output color.
173
+ #
174
+ def run_ruby_script(command, log_status=true)
175
+ run("ruby #{command}", log_status)
176
+ end
177
+
178
+ # Run a thor command. A hash of options can be given and it's converted to
179
+ # switches.
180
+ #
181
+ # ==== Parameters
182
+ # task<String>:: the task to be invoked
183
+ # args<Array>:: arguments to the task
184
+ # options<Hash>:: a hash with options used on invocation
185
+ # log_status<Boolean>:: if false, does not log the status. True by default.
186
+ # If a symbol is given, uses it as the output color.
187
+ #
188
+ # ==== Examples
189
+ #
190
+ # thor :install, "http://gist.github.com/103208"
191
+ # #=> thor install http://gist.github.com/103208
192
+ #
193
+ # thor :list, :all => true, :substring => 'rails'
194
+ # #=> thor list --all --substring=rails
195
+ #
196
+ def thor(task, *args)
197
+ log_status = args.last.is_a?(Symbol) || [true, false].include?(args.last) ? args.pop : true
198
+ options = args.last.is_a?(Hash) ? args.pop : {}
199
+
200
+ in_root do
201
+ args.unshift "thor #{task}"
202
+ args.push Thor::Options.to_switches(options)
203
+ run args.join(' ').strip, log_status
204
+ end
205
+ end
206
+
207
+ # Run a regular expression replacement on a file.
208
+ #
209
+ # ==== Parameters
210
+ # path<String>:: path of the file to be changed
211
+ # flag<Regexp|String>:: the regexp or string to be replaced
212
+ # replacement<String>:: the replacement, can be also given as a block
213
+ # log_status<Boolean>:: if false, does not log the status. True by default.
214
+ # If a symbol is given, uses it as the output color.
215
+ #
216
+ # ==== Example
217
+ #
218
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
219
+ #
220
+ # gsub_file 'README', /rake/, :green do |match|
221
+ # match << " no more. Use thor!"
222
+ # end
223
+ #
224
+ def gsub_file(path, flag, *args, &block)
225
+ log_status = args.last.is_a?(Symbol) || [ true, false ].include?(args.last) ? args.pop : true
226
+
227
+ path = File.expand_path(path, root)
228
+ say_status_if_log :gsub, relative_to_absolute_root(path), log_status
229
+
230
+ unless options[:pretend]
231
+ content = File.read(path)
232
+ content.gsub!(flag, *args, &block)
233
+ File.open(path, 'wb') { |file| file.write(content) }
234
+ end
235
+ end
236
+
237
+ # Append text to a file.
238
+ #
239
+ # ==== Parameters
240
+ # path<String>:: path of the file to be changed
241
+ # data<String>:: the data to append to the file, can be also given as a block.
242
+ # log_status<Boolean>:: if false, does not log the status. True by default.
243
+ # If a symbol is given, uses it as the output color.
244
+ #
245
+ # ==== Example
246
+ #
247
+ # append_file 'config/environments/test.rb', 'config.gem "rspec"'
248
+ #
249
+ def append_file(path, data=nil, log_status=true, &block)
250
+ path = File.expand_path(path, root)
251
+ say_status_if_log :append, relative_to_absolute_root(path), log_status
252
+
253
+ File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
254
+ end
255
+
256
+ # Prepend text to a file.
257
+ #
258
+ # ==== Parameters
259
+ # path<String>:: path of the file to be changed
260
+ # data<String>:: the data to prepend to the file, can be also given as a block.
261
+ # log_status<Boolean>:: if false, does not log the status. True by default.
262
+ # If a symbol is given, uses it as the output color.
263
+ #
264
+ # ==== Example
265
+ #
266
+ # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
267
+ #
268
+ def prepend_file(path, data=nil, log_status=true, &block)
269
+ path = File.expand_path(path, root)
270
+ say_status_if_log :prepend, relative_to_absolute_root(path), log_status
271
+
272
+ unless options[:pretend]
273
+ content = data || block.call
274
+ content << File.read(path)
275
+ File.open(path, 'wb') { |file| file.write(content) }
276
+ end
277
+ end
278
+
139
279
  protected
140
280
 
141
281
  def say_status_if_log(status, message, log_status)
data/lib/thor/base.rb CHANGED
@@ -83,8 +83,14 @@ class Thor
83
83
  #
84
84
  # ==== Parameters
85
85
  # name<Symbol>:: The name of the argument.
86
- # options<Hash>:: The description, type, default value for this argument.
87
- # The type can be :string, :numeric, :hash or :array. If none, string is assumed.
86
+ # options<Hash>:: Described below.
87
+ #
88
+ # ==== Options
89
+ # :desc - Description for the argument.
90
+ # :required - If the argument is required or not.
91
+ # :optional - If the argument is optional or not.
92
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric.
93
+ # :default - Default value for this argument. It cannot be required and have default values.
88
94
  #
89
95
  # ==== Errors
90
96
  # ArgumentError:: Raised if you supply a required argument after a non required one.
@@ -138,9 +144,16 @@ class Thor
138
144
  #
139
145
  # ==== Parameters
140
146
  # name<Symbol>:: The name of the argument.
141
- # options<Hash>:: The description, type, default value, aliases and if this option is required or not.
142
- # The type can be :string, :boolean, :numeric, :hash or :array. If none is given
143
- # a default type which accepts both (--name and --name=NAME) entries is assumed.
147
+ # options<Hash>:: Described below.
148
+ #
149
+ # ==== Options
150
+ # :desc - Description for the argument.
151
+ # :required - If the argument is required or not.
152
+ # :default - Default value for this argument. It cannot be required and have default values.
153
+ # :group - The group for this options. Use by class options to output options in different levels.
154
+ # :aliases - Aliases for this option.
155
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default.
156
+ # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE).
144
157
  #
145
158
  def class_option(name, options)
146
159
  build_option(name, options, class_options)
@@ -277,17 +290,53 @@ class Thor
277
290
 
278
291
  protected
279
292
 
293
+ # Prints the class optins per group. If a class options does not belong
294
+ # to any group, it's grouped as "Class options" in Thor classes and as
295
+ # "Options" in Thor::Group (since Thor::Group does not have method
296
+ # options, there is not need to add "Class" frist).
297
+ #
298
+ def class_options_help(shell, ungrouped_name=nil) #:nodoc:
299
+ unless self.class_options.empty?
300
+ groups = self.class_options.group_values_by { |o| o.group }
301
+
302
+ printer = lambda do |group_name, options|
303
+ unless options.empty?
304
+ options.map! do |option|
305
+ next if option.argument?
306
+ [ option.usage, option.description || '' ]
307
+ end
308
+
309
+ options.compact!
310
+
311
+ if group_name
312
+ shell.say "#{group_name} options:"
313
+ else
314
+ shell.say "Options:"
315
+ end
316
+
317
+ shell.print_table(options, :emphasize_last => true, :ident => 2)
318
+ shell.say ""
319
+ end
320
+ end
321
+
322
+ # Deal with default group
323
+ global_options = groups.delete(nil)
324
+ printer.call(ungrouped_name, global_options) if global_options
325
+
326
+ # Print all others
327
+ groups.each(&printer)
328
+ end
329
+ end
330
+
280
331
  # Build an option and adds it to the given scope.
281
332
  #
282
333
  # ==== Parameters
283
334
  # name<Symbol>:: The name of the argument.
284
- # options<Hash>:: The desc, type, default value and aliases for this option.
285
- # The type can be :string, :boolean, :numeric, :hash or :array. If none is given
286
- # a default type which accepts both (--name and --name=NAME) entries is assumed.
335
+ # options<Hash>:: Described in both class_option and method_option.
287
336
  #
288
337
  def build_option(name, options, scope)
289
- scope[name] = Thor::Option.new(name, options[:desc], options[:required],
290
- options[:type], options[:default], options[:aliases])
338
+ scope[name] = Thor::Option.new(name, options[:desc], options[:required], options[:type],
339
+ options[:default], options[:aliases], options[:group])
291
340
  end
292
341
 
293
342
  # Receives a hash of options, parse them and add to the scope. This is a
@@ -43,12 +43,18 @@ class Thor
43
43
 
44
44
  # Magic predicates. For instance:
45
45
  #
46
- # options.force? # => !!options['force']
46
+ # options.force? # => !!options['force']
47
+ # options.shebang # => "/usr/lib/local/ruby"
48
+ # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
47
49
  #
48
50
  def method_missing(method, *args, &block)
49
51
  method = method.to_s
50
52
  if method =~ /^(\w+)\?$/
51
- !!self[$1]
53
+ if args.empty?
54
+ !!self[$1]
55
+ else
56
+ self[$1] == args.first
57
+ end
52
58
  else
53
59
  self[method]
54
60
  end
@@ -7,9 +7,10 @@ class Thor #:nodoc:
7
7
  # while also keeping track of the order in which elements were set.
8
8
  #
9
9
  class OrderedHash #:nodoc:
10
- Node = Struct.new(:key, :value, :next, :prev)
11
10
  include Enumerable
12
11
 
12
+ Node = Struct.new(:key, :value, :next, :prev)
13
+
13
14
  def initialize
14
15
  @hash = {}
15
16
  end
@@ -82,6 +83,14 @@ class Thor #:nodoc:
82
83
  value
83
84
  end
84
85
 
86
+ def keys
87
+ self.map { |k, v| k }
88
+ end
89
+
90
+ def values
91
+ self.map { |k, v| v }
92
+ end
93
+
85
94
  def each
86
95
  return unless @first
87
96
  yield [@first.key, @first.value]
@@ -90,12 +99,14 @@ class Thor #:nodoc:
90
99
  self
91
100
  end
92
101
 
93
- def keys
94
- self.map { |k, v| k }
95
- end
96
-
97
- def values
98
- self.map { |k, v| v }
102
+ def group_values_by
103
+ assoc = self.class.new
104
+ each do |_, element|
105
+ key = yield(element)
106
+ assoc[key] ||= []
107
+ assoc[key] << element
108
+ end
109
+ assoc
99
110
  end
100
111
 
101
112
  def merge(other)
@@ -118,10 +129,9 @@ class Thor #:nodoc:
118
129
  end
119
130
 
120
131
  def to_a
121
- inject([]) do |array, (key, value)|
122
- array << [key, value]
123
- array
124
- end
132
+ array = []
133
+ each { |k, v| array << [k, v] }
134
+ array
125
135
  end
126
136
 
127
137
  def to_s
data/lib/thor/group.rb CHANGED
@@ -44,23 +44,12 @@ class Thor::Group
44
44
  #
45
45
  def help(shell, options={})
46
46
  if options[:short]
47
- shell.say "#{self.namespace} #{self.class_options.map {|_,o| o.usage}.join(' ')}"
47
+ shell.say "#{self.namespace} #{self.arguments.map {|o| o.usage }.join(' ')}"
48
48
  else
49
49
  shell.say "Usage:"
50
- shell.say " #{self.namespace} #{self.arguments.map{|o| o.usage}.join(' ')}"
50
+ shell.say " #{self.namespace} #{self.arguments.map {|o| o.usage }.join(' ')}"
51
51
  shell.say
52
-
53
- list = self.class_options.map do |_, option|
54
- next if option.argument?
55
- [ option.usage, option.description || '' ]
56
- end.compact
57
-
58
- unless list.empty?
59
- shell.say "Global options:"
60
- shell.print_table(list, :emphasize_last => true, :ident => 2)
61
- shell.say
62
- end
63
-
52
+ class_options_help(shell)
64
53
  shell.say self.desc if self.desc
65
54
  end
66
55
  end
data/lib/thor/option.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  class Thor
2
2
  class Option
3
- attr_reader :name, :description, :required, :type, :default, :aliases
3
+ attr_reader :name, :description, :required, :type, :default, :aliases, :group
4
4
 
5
5
  VALID_TYPES = [:boolean, :numeric, :hash, :array, :string, :default]
6
6
 
7
- def initialize(name, description=nil, required=nil, type=nil, default=nil, aliases=nil)
7
+ def initialize(name, description=nil, required=nil, type=nil, default=nil, aliases=nil, group=nil)
8
8
  raise ArgumentError, "Option name can't be nil." if name.nil?
9
9
  raise ArgumentError, "Option cannot be required and have default values." if required && !default.nil?
10
10
  raise ArgumentError, "Type :#{type} is not valid for options." if type && !VALID_TYPES.include?(type.to_sym)
@@ -15,6 +15,7 @@ class Thor
15
15
  @type = (type || :default).to_sym
16
16
  @default = default
17
17
  @aliases = [*aliases].compact
18
+ @group = group.to_s.capitalize if group
18
19
  end
19
20
 
20
21
  # This parse quick options given as method_options. It makes several
@@ -196,7 +197,7 @@ class Thor
196
197
  raise ArgumentError, "Argument name can't be nil." if name.nil?
197
198
  raise ArgumentError, "Type :#{type} is not valid for arguments." if type && !VALID_TYPES.include?(type.to_sym)
198
199
 
199
- super(name, description, required, type || :string, default, [])
200
+ super(name, description, required, type || :string, default)
200
201
  end
201
202
 
202
203
  def argument?
@@ -22,10 +22,10 @@ class Thor
22
22
  # ==== Example
23
23
  # say("I know you knew that.")
24
24
  #
25
- def say(statement="", color=nil)
25
+ def say(statement="", color=nil, force_new_line=false)
26
26
  statement = statement.to_s
27
27
 
28
- if statement[-1, 1] == " " || statement[-1, 1] == "\t"
28
+ if !force_new_line && (statement[-1, 1] == " " || statement[-1, 1] == "\t")
29
29
  $stdout.print(statement)
30
30
  $stdout.flush
31
31
  else
@@ -40,7 +40,7 @@ class Thor
40
40
  return if base && base.options[:quiet]
41
41
 
42
42
  status_flag = "[#{status.to_s.upcase}]".rjust(12)
43
- say "#{status_flag} #{message}"
43
+ say "#{status_flag} #{message}", color, true
44
44
  end
45
45
 
46
46
  # Make a question the to user and returns true if the user replies "y" or
data/lib/thor/task.rb CHANGED
@@ -29,7 +29,7 @@ class Thor
29
29
  backtrace = sans_backtrace(e.backtrace, caller)
30
30
 
31
31
  if instance.is_a?(Thor) && backtrace.empty?
32
- raise InvocationError, "'#{name}' was called incorrectly. Call as '#{formatted_usage(instance.class)}'"
32
+ raise InvocationError, "'#{name}' was called incorrectly. Call as '#{formatted_usage(instance.class, true)}'"
33
33
  else
34
34
  raise e
35
35
  end
@@ -47,18 +47,30 @@ class Thor
47
47
  description.split("\n").first if description
48
48
  end
49
49
 
50
- # Returns the formatted usage. If a klass is given, the klass default options
51
- # are merged with the task options providinf a full description.
50
+ # Returns the formatted usage. If a klass is given, the klass arguments are
51
+ # injected in the usage.
52
52
  #
53
- def formatted_usage(klass=nil)
53
+ def formatted_usage(klass=nil, namespace=false)
54
54
  formatted = ''
55
- formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass
56
- formatted << usage.to_s
55
+ formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass && namespace
56
+ formatted << formatted_arguments(klass)
57
57
  formatted << " #{formatted_options}"
58
58
  formatted.strip!
59
59
  formatted
60
60
  end
61
61
 
62
+ # Injects the klass arguments into the defined usage.
63
+ #
64
+ def formatted_arguments(klass)
65
+ if klass && !klass.arguments.empty?
66
+ usage.to_s.gsub(/^#{name}/) do |match|
67
+ match << " " << klass.arguments.map{ |a| a.usage }.join(' ')
68
+ end
69
+ else
70
+ usage.to_s
71
+ end
72
+ end
73
+
62
74
  # Returns the options usage for this task.
63
75
  #
64
76
  def formatted_options
data/lib/thor/tasks.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # This only loads all tasks inside tasks.
1
2
  Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task|
2
3
  require task
3
4
  end
data/lib/thor.rb CHANGED
@@ -95,9 +95,15 @@ class Thor
95
95
  #
96
96
  # ==== Parameters
97
97
  # name<Symbol>:: The name of the argument.
98
- # options<Hash>:: The description, type, default value, aliases and if this option is required or not.
99
- # The type can be :string, :boolean, :numeric, :hash or :array. If none is given
100
- # a default type which accepts both (--name and --name=NAME) entries is assumed.
98
+ # options<Hash>:: Described below.
99
+ #
100
+ # ==== Options
101
+ # :desc - Description for the argument.
102
+ # :required - If the argument is required or not.
103
+ # :default - Default value for this argument. It cannot be required and have default values.
104
+ # :aliases - Aliases for this option.
105
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default.
106
+ # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE).
101
107
  #
102
108
  def method_option(name, options)
103
109
  scope = if options[:for]
@@ -145,33 +151,29 @@ class Thor
145
151
  #
146
152
  def help(shell, meth=nil, options={})
147
153
  meth, options = nil, meth if meth.is_a?(Hash)
148
- namespace = options[:namespace] ? self : nil
149
154
 
150
155
  if meth
151
156
  task = self.all_tasks[meth]
152
157
  raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task
153
158
 
154
159
  shell.say "Usage:"
155
- shell.say " #{task.formatted_usage(namespace)}"
160
+ shell.say " #{task.formatted_usage(self, options[:namespace])}"
156
161
  shell.say
157
- options_help(shell)
162
+ class_options_help(shell, "Class")
158
163
  shell.say task.description
159
164
  else
160
- if options[:short]
161
- list = self.tasks.map do |_, task|
162
- [ task.formatted_usage(namespace), task.short_description || '' ]
163
- end
165
+ list = (options[:short] ? tasks : all_tasks).map do |_, task|
166
+ [ task.formatted_usage(self, options[:namespace]), task.short_description || '' ]
167
+ end
164
168
 
169
+ if options[:short]
165
170
  shell.print_table(list, :emphasize_last => true)
166
171
  else
167
- options_help(shell)
168
-
169
- list = self.all_tasks.map do |_, task|
170
- [ task.formatted_usage(namespace), task.short_description || '' ]
171
- end
172
-
173
172
  shell.say "Tasks:"
174
173
  shell.print_table(list, :ident => 2, :emphasize_last => true)
174
+ shell.say
175
+
176
+ class_options_help(shell, "Class")
175
177
  end
176
178
  end
177
179
  end
@@ -205,17 +207,6 @@ class Thor
205
207
  meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
206
208
  end
207
209
 
208
- def options_help(shell) #:nodoc:
209
- unless self.class_options.empty?
210
- list = self.class_options.map do |_, option|
211
- [ option.usage, option.description || '' ]
212
- end
213
-
214
- shell.say "Global arguments:"
215
- shell.print_table(list, :emphasize_last => true, :ident => 2)
216
- shell.say ""
217
- end
218
- end
219
210
  end
220
211
 
221
212
  include Thor::Base
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: josevalim-thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-14 00:00:00 -07:00
12
+ date: 2009-06-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -42,10 +42,8 @@ files:
42
42
  - lib/thor/actions/inject_into_file.rb
43
43
  - lib/thor/actions/directory.rb
44
44
  - lib/thor/actions/template.rb
45
- - lib/thor/actions/gsub_file.rb
46
45
  - lib/thor/actions/get.rb
47
46
  - lib/thor/actions/create_file.rb
48
- - lib/thor/actions/commands.rb
49
47
  - lib/thor/actions/empty_directory.rb
50
48
  - lib/thor/util.rb
51
49
  - lib/thor/runner.rb
@@ -1,61 +0,0 @@
1
- class Thor
2
- module Actions
3
- # Executes a command.
4
- #
5
- # ==== Parameters
6
- # command<String>:: the command to be executed.
7
- # log_status<Boolean>:: if false, does not log the status. True by default.
8
- # If a symbol is given, uses it as the output color.
9
- #
10
- # ==== Example
11
- #
12
- # inside('vendor') do
13
- # run('ln -s ~/edge rails')
14
- # end
15
- #
16
- def run(command, log_status=true)
17
- say_status_if_log :run, "#{command} from #{relative_to_absolute_root(root, false)}", log_status
18
- `#{command}` unless options[:pretend]
19
- end
20
-
21
- # Executes a ruby script (taking into account WIN32 platform quirks).
22
- #
23
- # ==== Parameters
24
- # command<String>:: the command to be executed.
25
- # log_status<Boolean>:: if false, does not log the status. True by default.
26
- # If a symbol is given, uses it as the output color.
27
- #
28
- def run_ruby_script(command, log_status=true)
29
- run("ruby #{command}", log_status)
30
- end
31
-
32
- # Run a thor command. A hash of options can be given and it's converted to
33
- # switches.
34
- #
35
- # ==== Parameters
36
- # task<String>:: the task to be invoked
37
- # args<Array>:: arguments to the task
38
- # options<Hash>:: a hash with options used on invocation
39
- # log_status<Boolean>:: if false, does not log the status. True by default.
40
- # If a symbol is given, uses it as the output color.
41
- #
42
- # ==== Examples
43
- #
44
- # thor :install, "http://gist.github.com/103208"
45
- # #=> thor install http://gist.github.com/103208
46
- #
47
- # thor :list, :all => true, :substring => 'rails'
48
- # #=> thor list --all --substring=rails
49
- #
50
- def thor(task, *args)
51
- log_status = args.last.is_a?(Symbol) || [true, false].include?(args.last) ? args.pop : true
52
- options = args.last.is_a?(Hash) ? args.pop : {}
53
-
54
- in_root do
55
- args.unshift "thor #{task}"
56
- args.push Thor::Options.to_switches(options)
57
- run args.join(' ').strip, log_status
58
- end
59
- end
60
- end
61
- end
@@ -1,77 +0,0 @@
1
- class Thor
2
- module Actions
3
-
4
- # Run a regular expression replacement on a file.
5
- #
6
- # ==== Parameters
7
- # path<String>:: path of the file to be changed
8
- # flag<Regexp|String>:: the regexp or string to be replaced
9
- # replacement<String>:: the replacement, can be also given as a block
10
- # log_status<Boolean>:: if false, does not log the status. True by default.
11
- # If a symbol is given, uses it as the output color.
12
- #
13
- # ==== Example
14
- #
15
- # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
16
- #
17
- # gsub_file 'README', /rake/, :green do |match|
18
- # match << " no more. Use thor!"
19
- # end
20
- #
21
- def gsub_file(path, flag, *args, &block)
22
- log_status = args.last.is_a?(Symbol) || [ true, false ].include?(args.last) ? args.pop : true
23
-
24
- path = File.expand_path(path, root)
25
- say_status_if_log :gsub, relative_to_absolute_root(path), log_status
26
-
27
- unless options[:pretend]
28
- content = File.read(path)
29
- content.gsub!(flag, *args, &block)
30
- File.open(path, 'wb') { |file| file.write(content) }
31
- end
32
- end
33
-
34
- # Append text to a file.
35
- #
36
- # ==== Parameters
37
- # path<String>:: path of the file to be changed
38
- # data<String>:: the data to append to the file, can be also given as a block.
39
- # log_status<Boolean>:: if false, does not log the status. True by default.
40
- # If a symbol is given, uses it as the output color.
41
- #
42
- # ==== Example
43
- #
44
- # append_file 'config/environments/test.rb', 'config.gem "rspec"'
45
- #
46
- def append_file(path, data=nil, log_status=true, &block)
47
- path = File.expand_path(path, root)
48
- say_status_if_log :append, relative_to_absolute_root(path), log_status
49
-
50
- File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
51
- end
52
-
53
- # Prepend text to a file.
54
- #
55
- # ==== Parameters
56
- # path<String>:: path of the file to be changed
57
- # data<String>:: the data to prepend to the file, can be also given as a block.
58
- # log_status<Boolean>:: if false, does not log the status. True by default.
59
- # If a symbol is given, uses it as the output color.
60
- #
61
- # ==== Example
62
- #
63
- # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
64
- #
65
- def prepend_file(path, data=nil, log_status=true, &block)
66
- path = File.expand_path(path, root)
67
- say_status_if_log :prepend, relative_to_absolute_root(path), log_status
68
-
69
- unless options[:pretend]
70
- content = data || block.call
71
- content << File.read(path)
72
- File.open(path, 'wb') { |file| file.write(content) }
73
- end
74
- end
75
-
76
- end
77
- end