Class Drydock::Command

  1. lib/drydock.rb
Parent: Object

The base class for all command objects. There is an instance of this class for every command defined. Global and command-specific options are added as attributes to this class dynamically.

i.e. "example -v select --location kumamoto"

global :v, :verbose, "I want mooooore!"
option :l, :location, String, "Source location"
command :select do |obj|
  puts obj.global.verbose   #=> true
  puts obj.option.location  #=> "kumamoto"
end

You can sub-class it to create your own:

class Malpeque < Drydock::Command
  # ... sea to it
end

And then specify your class in the command definition:

command :eat => Malpeque do |obj|
  # ... do stuff with your obj
end

Methods

public class

  1. new

public instance

  1. call
  2. name
  3. prepare
  4. show_commands
  5. to_s

Constants

VERSION = "0.6.9"

Attributes

actions [RW] An array of action names specified in the command definition
alias [R] The name used to evoke this command (it’s either the canonical name or the alias used).
argv [RW] An instance of Drydock::FancyArray. Acts like an array of unnamed arguments but also allows field names if supplied.
b [R] The block that will be executed when this command is evoked. If the block is nil it will check if there is a method named cmd. If so, that will be executed.
cmd [R] The canonical name of the command (the one used in the command definition). If you inherit from this class and add a method named cmd, you can leave omit the block in the command definition. That method will be called instead. See bin/examples.
desc [RW] A friendly description of the command.
executable [R] The basename of the executable or script: File.basename($0)
global [R] An OpenStruct object containing the global options specified at run-time.
option [R] An OpenStruct object containing the command options specified at run-time.
stdin [R] Either an IO handle to STDIN or the output of the Drydock#stdin handler.

Public class methods

new (cmd, &b)

The default constructor sets the short name of the command and stores a reference to the block (if supplied). You don’t need to override this method to add functionality to your custom Command classes. Define an init method instead. It will be called just before the block is executed. cmd is the short name of this command. b is the block associated to this command.

[show source]
     # File lib/drydock.rb, line 118
118:     def initialize(cmd, &b)
119:       @cmd = (cmd.kind_of?(Symbol)) ? cmd : cmd.to_sym
120:       @b = b
121:       @actions = []
122:       @argv = Drydock::FancyArray.new # an array with field names
123:       @stdin = STDIN
124:       @option = OpenStruct.new
125:       @global = OpenStruct.new
126:       @executable = File.basename($0)
127:       @global.verbose = 0
128:       @global.quiet = false
129:     end

Public instance methods

call ()

Calls the command in the following order:

  • print_header
  • validation (if methodname_valid? exists)
  • command block (@b)
  • print_footer
[show source]
     # File lib/drydock.rb, line 175
175:     def call  
176:       self.print_header if self.respond_to? :print_header
177:       
178:       # Execute the command block if it exists
179:       if @b 
180:         run_validation
181:         @b.call(self) 
182:       
183:       # Otherwise check to see if an action was specified
184:       elsif !(chosen = find_action(self.option)).empty?
185:         raise "Only one action at a time please! I can't #{chosen.join(' AND ')}." if chosen.size > 1
186:         criteria = [[@cmd, chosen.first], [chosen.first, @cmd]]
187:         meth = name = nil
188:         # Try command_action, then action_command
189:         criteria.each do |tuple|
190:           name = tuple.join('_')
191:           meth = name if self.respond_to?(name)  
192:         end
193:         
194:         raise "#{self.class} needs a #{name} method!" unless meth
195:         
196:         run_validation(meth)
197:         self.send(meth)
198:         
199:       # No block and no action. We'll try for the method name in the Drydock::Command class. 
200:       elsif self.respond_to? @cmd.to_sym
201:         run_validation(@cmd)
202:         self.send(@cmd)
203:         
204:       # Well, then I have no idea what you want me to do!
205:       else
206:         raise "The command #{@alias} has no block and #{self.class} has no #{@cmd} method!"
207:       end
208:       
209:       self.print_footer if respond_to? :print_footer
210:     end
name ()

Returns the command name (not the alias)

[show source]
     # File lib/drydock.rb, line 132
132:     def name
133:       @cmd
134:     end
prepare (cmd_str=nil, argv=[], stdin=[], global_options={}, options={})

Prepare this command object to be called.

Calls self.init after setting attributes (if the method exists). You can implement an init method in your subclasses of Drydock::Command to handle your own initialization stuff.

  • cmd_str is the short name used to evoke this command. It will equal @cmd unless an alias was used used to evoke this command.
  • argv an array of unnamed arguments. If ignore :options was declared this
  • will contain the arguments exactly as they were defined on the command-line.
  • stdin contains the output of stdin do; …; end otherwise it’s a STDIN IO handle.
  • global_options a hash of the global options specified on the command-line
  • options a hash of the command-specific options specific on the command-line.
  • [show source]
         # File lib/drydock.rb, line 149
    149:     def prepare(cmd_str=nil, argv=[], stdin=[], global_options={}, options={})
    150:       @alias = cmd_str.nil? ? @cmd : cmd_str
    151: 
    152:       global_options.each_pair do |n,v|
    153:         self.global.send("#{n}=", v)    # Populate the object's globals
    154:       end
    155:       
    156:       options.each_pair do |n,v|
    157:         self.option.send("#{n}=", v)    # ... and also the command options
    158:       end
    159:       
    160:       @argv << argv    # TODO: Using += returns an Array instead of FancyArray
    161:       @argv.flatten!   # NOTE: << creates @argv[[]]
    162:       @stdin = stdin
    163:       
    164:       self.init         if self.respond_to? :init     # Must be called first!
    165:       
    166:     end
    show_commands ()

    Print the list of available commands to STDOUT. This is used as the “default” command unless another default commands is supplied. You can also write your own Drydock::Command#show_commands to override this default behaviour.

    The output was worked on here: etherpad.com/SXjqQGRr8M

    [show source]
         # File lib/drydock.rb, line 257
    257:     def show_commands
    258:       project = " for #{Drydock.project}" if Drydock.project?
    259:       cmds = {}
    260:       Drydock.commands.keys.each do |cmd|
    261:         next if cmd == :show_commands
    262:         pretty = Drydock.decanonize(cmd)
    263:         # Out to sea
    264:         cmds[Drydock.commands[cmd].cmd] ||= {}
    265:         unless cmd === Drydock.commands[cmd].cmd
    266:           (cmds[Drydock.commands[cmd].cmd][:aliases] ||= []) << pretty
    267:           next
    268:         end
    269:         cmds[cmd][:desc] = Drydock.commands[cmd].desc
    270:         cmds[cmd][:desc] = nil if cmds[cmd][:desc] && cmds[cmd][:desc].empty?
    271:         cmds[cmd][:pretty] = pretty
    272:       end
    273:     
    274:       cmd_names_sorted = cmds.keys.sort{ |a,b| a.to_s <=> b.to_s }
    275:       
    276:       if @global.quiet
    277:         puts "Commands: "
    278:         line = []
    279:         cmd_names_sorted.each_with_index do |cmd,i|
    280:           line << cmd
    281:           if (line.size % 4 == 0) || i == (cmd_names_sorted.size - 1)
    282:             puts "  %s" % line.join(', ')
    283:             line.clear
    284:           end
    285:         end
    286:         return
    287:       end
    288:       
    289:       puts "%5s: %s" % ["Usage", "#{@executable} [global options] COMMAND [command options]"]
    290:       puts "%5s: %s" % ["Try", "#{@executable} -h"] 
    291:       puts "%5s  %s" % ["", "#{@executable} COMMAND -h"]
    292:       puts
    293:       
    294:       puts "Commands: "
    295:       if @global.verbose > 0
    296:         puts # empty line
    297:         cmd_names_sorted.each do |cmd|
    298:           puts "$ %s" % [@executable] if Drydock.default?(cmd)
    299:           puts "$ %s %s" % [@executable, cmds[cmd][:pretty]]
    300:           puts "%10s: %s" % ["About", cmds[cmd][:desc]] if cmds[cmd][:desc]
    301:           if cmds[cmd][:aliases]
    302:             cmds[cmd][:aliases].sort!{ |a,b| a.size <=> b.size }
    303:             puts "%10s: %s" % ["Aliases", cmds[cmd][:aliases].join(', ')]
    304:           end
    305:           puts
    306:         end
    307: 
    308:       else
    309:         cmd_names_sorted.each do |cmd|
    310:           aliases = cmds[cmd][:aliases] || []
    311:           aliases.sort!{ |a,b| a.size <=> b.size }
    312:           aliases = aliases.empty? ? '' : "(aliases: #{aliases.join(', ')})"
    313:           pattern = Drydock.default?(cmd) ? "* %-16s %s" : "  %-16s %s"
    314:           puts pattern % [cmds[cmd][:pretty], aliases]
    315:         end
    316:       end
    317:     end
    to_s ()

    The name of the command

    [show source]
         # File lib/drydock.rb, line 320
    320:     def to_s
    321:       @cmd.to_s
    322:     end