Skip to content

Instantly share code, notes, and snippets.

@johnthethird
Forked from h0rs3r4dish/canine.rb
Created December 17, 2009 05:12
Show Gist options
  • Save johnthethird/258539 to your computer and use it in GitHub Desktop.
Save johnthethird/258539 to your computer and use it in GitHub Desktop.
class Canine
VERSION = '1.3'
def initialize(&block)
@commands = Hash.new
@default = @latest = :commands
@empty = nil
@auto = {
:commands => hash_command("commands","Show a list of commands",Proc.new {
@commands.each { |cmd| c = cmd[1]
name = c[:name].to_s
name += ' [' + c[:args].map { |i| i[0] }.join('] [') + ']' if c[:args].length > 0
puts " %-20s %-30s" % [name,c[:desc]]
}
})
}
if block then
self.instance_exec &block
self.run
end
end
def command(name,desc="",&block)
if block then
@commands[intern(name)] = hash_command name, desc, block
@latest = intern(name)
else
raise ArgumentError, "No such command '%s'" % desc unless @auto.has_key? intern(desc)
@commands[intern(name)] = auto_command(name,desc)
end
end
def no_command desc, &block
if block then
command('<no command>',desc,&block)
@empty = block
else
@empty = @commands[intern(desc)][:block]
command('<no command>',"Same as %s" % desc,&@empty)
end
end
def options(arghash)
arghash.each_pair { |key, value|
@commands[@latest][:args].push [key, value]
}
end
def default_command cmd
@default = intern(cmd)
end
def invoke(sym, *args)
sym = intern(sym)
raise ArgumentError, "No such command '%s'" % sym unless @commands.has_key? sym
raise ArgumentError, "Not enough arguments for command '%s' (%s for %s)" % [sym, args.length,@commands[sym][:args].length] if args.length < @commands[sym][:args].length
self.instance_exec *args, &@commands[sym][:block]
end
def hash_command(name,desc,block,args=[])
return {:name => name, :desc => desc, :block => block, :args => args}
end
def intern(n)
(Symbol === n) ? n : n.intern
end
def auto_command(name,real_name)
@auto[intern(real_name)].merge({:name => name})
end
def run
cmd = @default
args = Array.new
ARGV.each { |arg|
if cmd == @default then
cmd = arg.intern
if [email protected]?(cmd) then
if @empty != nil then
cmd = "<no command>";
args.push(arg)
else
puts "No such command '%s'" % cmd.to_s
Process.exit
end
end
next
else
args.push(arg)
end
}
ARGV.shift while ARGV.length > 0
begin
invoke cmd, *args
rescue Exception => e
puts e.message
end
end
end

Canine

Canine is a library for creating basic Ruby "binaries," a la the rails, monk, and jekyll executables. It's as easy as passing a block: require 'canine' Canine.new do # code here end And it will auto-magically run.

Now, the things you can do are pretty simple:

  • command name, [desc], &block => creates a new command with the given name. The block can take as many arguments as you want, provided you define them with options later in the script
  • command name, autocommand-name => links an auto-command to the given name. At the moment, there's only one, commands. If more are added, they'll be in the @auto hash
  • no_command desc, &block => if you want a command to be run when arguments are simply passed (as in rails <myapp>), pass a description and a block to this method
  • no_command name => should you want the commandless process to be a command you already created, pass the name to the method
  • options hash => set up the options for the latest command that you created, in an 'name' => 'description' format
  • default_command name => set the command you want to run when no arguments are passed the the script. This is required.

The command blocks themselves can do anything. You can import anything you really need, from fileutils to rake, and use them within the commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment