2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4 # See LICENSE.txt for permissions.
9 require 'rubygems/user_interaction'
13 # Base class for all Gem commands. When creating a new gem command, define
14 # #arguments, #defaults_str, #description and #usage (as appropriate).
17 include UserInteraction
19 # The name of the command.
22 # The options for the command.
25 # The default options for the command.
26 attr_accessor :defaults
28 # The name of the command for command-line invocation.
29 attr_accessor :program_name
31 # A short description of the command.
32 attr_accessor :summary
34 # Initializes a generic gem command named +command+. +summary+ is a short
35 # description displayed in `gem help commands`. +defaults+ are the
36 # default options. Defaults should be mirrored in #defaults_str, unless
39 # Use add_option to add command-line switches.
40 def initialize(command, summary=nil, defaults={})
43 @program_name = "gem #{command}"
45 @options = defaults.dup
46 @option_groups = Hash.new { |h,k| h[k] = [] }
51 # True if +long+ begins with the characters from +short+.
52 def begins?(long, short)
53 return false if short.nil?
54 long[0, short.length] == short
57 # Override to provide command handling.
59 fail "Generic command has no actions"
62 # Get all gem names from the command line.
66 if args.nil? or args.empty? then
67 raise Gem::CommandLineError,
68 "Please specify at least one gem name (e.g. gem build GEMNAME)"
71 gem_names = args.select { |arg| arg !~ /^-/ }
74 # Get the single gem name from the command line. Fail if there is no gem
75 # name or if there is more than one gem name given.
79 if args.nil? or args.empty? then
80 raise Gem::CommandLineError,
81 "Please specify a gem name on the command line (e.g. gem build GEMNAME)"
85 raise Gem::CommandLineError,
86 "Too many gem names (#{args.join(', ')}); please specify only one"
92 # Get a single optional argument from the command line. If more than one
93 # argument is given, return only the first. Return nil if none are given.
94 def get_one_optional_argument
95 args = options[:args] || []
99 # Override to provide details of the arguments a command takes.
100 # It should return a left-justified string, one argument per line.
105 # Override to display the default values of the command
106 # options. (similar to +arguments+, but displays the default
112 # Override to display a longer description of what this command does.
117 # Override to display the usage for an individual gem command.
122 # Display the help message for the command.
124 parser.program_name = usage
128 # Invoke the command with the given list of arguments.
134 @when_invoked.call(options)
140 # Call the given block when invoked.
142 # Normal command invocations just executes the +execute+ method of
143 # the command. Specifying an invocation block allows the test
144 # methods to override the normal action of a command to determine
145 # that it has been invoked correctly.
146 def when_invoked(&block)
147 @when_invoked = block
150 # Add a command-line option and handler to the command.
152 # See OptionParser#make_switch for an explanation of +opts+.
154 # +handler+ will be called with two values, the value of the argument and
156 def add_option(*opts, &handler) # :yields: value, options
157 group_name = Symbol === opts.first ? opts.shift : :options
159 @option_groups[group_name] << [opts, handler]
162 # Remove previously defined command-line argument +name+.
163 def remove_option(name)
164 @option_groups.each do |_, option_list|
165 option_list.reject! { |args, _| args.any? { |x| x =~ /^#{name}/ } }
169 # Merge a set of command options with the set of default options
170 # (without modifying the default option hash).
171 def merge_options(new_options)
172 @options = @defaults.clone
173 new_options.each do |k,v| @options[k] = v end
176 # True if the command handles the given argument list.
179 parser.parse!(args.dup)
186 # Handle the given list of arguments by parsing them and recording
188 def handle_options(args)
189 args = add_extra_args(args)
190 @options = @defaults.clone
192 @options[:args] = args
195 def add_extra_args(args)
197 s_extra = Command.specific_extra_args(@command)
198 extra = Command.extra_args + s_extra
202 ex << extra.shift if extra.first.to_s =~ /^[^-]/
203 result << ex if handles?(ex)
212 # Create on demand parser.
214 create_option_parser if @parser.nil?
218 def create_option_parser
219 @parser = OptionParser.new
221 @parser.separator("")
222 regular_options = @option_groups.delete :options
224 configure_options "", regular_options
226 @option_groups.sort_by { |n,_| n.to_s }.each do |group_name, option_list|
227 configure_options group_name, option_list
230 configure_options "Common", Command.common_options
232 @parser.separator("")
233 unless arguments.empty?
234 @parser.separator(" Arguments:")
235 arguments.split(/\n/).each do |arg_desc|
236 @parser.separator(" #{arg_desc}")
238 @parser.separator("")
241 @parser.separator(" Summary:")
242 wrap(@summary, 80 - 4).split("\n").each do |line|
243 @parser.separator(" #{line.strip}")
247 formatted = description.split("\n\n").map do |chunk|
252 @parser.separator " Description:"
253 formatted.split("\n").each do |line|
254 @parser.separator " #{line.rstrip}"
258 unless defaults_str.empty?
259 @parser.separator("")
260 @parser.separator(" Defaults:")
261 defaults_str.split(/\n/).each do |line|
262 @parser.separator(" #{line}")
267 def configure_options(header, option_list)
268 return if option_list.nil? or option_list.empty?
270 header = header.to_s.empty? ? '' : "#{header} "
271 @parser.separator " #{header}Options:"
273 option_list.each do |args, handler|
274 dashes = args.select { |arg| arg =~ /^-/ }
275 @parser.on(*args) do |value|
276 handler.call(value, @options)
283 # Wraps +text+ to +width+
284 def wrap(text, width)
285 text.gsub(/(.{1,#{width}})( +|$\n?)|(.{1,#{width}})/, "\\1\\3\n")
288 ##################################################################
289 # Class methods for Command.
292 @common_options ||= []
295 def add_common_option(*args, &handler)
296 Gem::Command.common_options << [args, handler]
303 def extra_args=(value)
308 @extra_args = value.split
312 # Return an array of extra arguments for the command. The extra
313 # arguments come from the gem configuration file read at program
315 def specific_extra_args(cmd)
316 specific_extra_args_hash[cmd]
319 # Add a list of extra arguments for the given command. +args+
320 # may be an array or a string to be split on white space.
321 def add_specific_extra_args(cmd,args)
322 args = args.split(/\s+/) if args.kind_of? String
323 specific_extra_args_hash[cmd] = args
326 # Accessor for the specific extra args hash (self initializing).
327 def specific_extra_args_hash
328 @specific_extra_args_hash ||= Hash.new do |h,k|
334 # ----------------------------------------------------------------
335 # Add the options common to all commands.
337 add_common_option('-h', '--help',
338 'Get help on this command') do
340 options[:help] = true
343 add_common_option('-V', '--[no-]verbose',
344 'Set the verbose level of output') do |value, options|
345 # Set us to "really verbose" so the progress meter works
346 if Gem.configuration.verbose and value then
347 Gem.configuration.verbose = 1
349 Gem.configuration.verbose = value
353 add_common_option('-q', '--quiet', 'Silence commands') do |value, options|
354 Gem.configuration.verbose = false
357 # Backtrace and config-file are added so they show up in the help
358 # commands. Both options are actually handled before the other
359 # options get parsed.
361 add_common_option('--config-file FILE',
362 "Use this config file instead of default") do
365 add_common_option('--backtrace',
366 'Show stack backtrace on errors') do
369 add_common_option('--debug',
370 'Turn on Ruby debugging') do
375 RubyGems is a sophisticated package manager for Ruby. This is a
376 basic help message containing pointers to more information.
381 gem command [arguments...] [options...]
386 gem build package.gemspec
390 gem help commands list all 'gem' commands
391 gem help examples show some examples of usage
392 gem help platforms show information about platforms
393 gem help <COMMAND> show help on COMMAND
394 (e.g. 'gem help install')
396 http://rubygems.rubyforge.org
403 # This is where Commands will be placed in the namespace