Module: Executable
- Defined in:
- lib/executable.rb
Overview
Executable Mixin
The Executable mixin is a very quick and and easy way to make almost any class usable via a command line interface. It simply uses writer methods as option setters, and the first command line argument as the method to call, with the subsequent arguments passed to the method.
The only limitation of this approach (besides the weak control of the process) is that required options must be specified with the key=value notation.
class X
include Executable
attr_accessor :quiet
def bread(*args)
["BREAD", quiet, *args]
end
def butter(*args)
["BUTTER", quiet, *args]
end
end
x = X.new
x.execute_command("butter yum")
=> ["BUTTER", nil, "yum"]
x.execute_command("bread --quiet")
=> ["BUTTER", true]
Executable also defines #command_missing and #option_missing, which you can override to provide suitable results.
TODO: Maybe command_missing is redundant, and method_missing would suffice?
Defined Under Namespace
Classes: NoCommandError, NoOptionError
Class Method Summary collapse
- .parse(obj, argv) ⇒ Object
- .parse_equal(obj, opt, argv) ⇒ Object
- .parse_flags(obj, opt, args) ⇒ Object
- .parse_option(obj, opt, argv) ⇒ Object
- .run(obj, argv = ARGV) ⇒ Object
Instance Method Summary collapse
-
#command_missing ⇒ Object
This is the fallback subcommand.
-
#execute_command(argv = ARGV) ⇒ Object
Used to invoke the command.
-
#option_missing(opt, *argv) ⇒ Object
Override option_missing if needed.
Class Method Details
.parse(obj, argv) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/executable.rb', line 88 def parse(obj, argv) case argv when String require 'shellwords' argv = Shellwords.shellwords(argv) else argv = argv.dup end argv = argv.dup args, opts, i = [], {}, 0 while argv.size > 0 case opt = argv.shift when /=/ parse_equal(obj, opt, argv) when /^--/ parse_option(obj, opt, argv) when /^-/ parse_flags(obj, opt, argv) else args << opt end end return args end |
.parse_equal(obj, opt, argv) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/executable.rb', line 115 def parse_equal(obj, opt, argv) if md = /^[-]*(.*?)=(.*?)$/.match(opt) x, v = md[1], md[2] else raise ArgumentError, "#{x}" end if obj.respond_to?("#{x}=") # TODO: to_b if 'true' or 'false' ? obj.send("#{x}=",v) else obj.option_missing(x, v) # argv? end end |
.parse_flags(obj, opt, args) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/executable.rb', line 140 def parse_flags(obj, opt, args) x = opt[1..-1] c = 0 x.split(//).each do |k| if obj.respond_to?("#{k}=") obj.send("#{k}=",true) else obj.option_missing(x, argv) end end end |
.parse_option(obj, opt, argv) ⇒ Object
130 131 132 133 134 135 136 137 |
# File 'lib/executable.rb', line 130 def parse_option(obj, opt, argv) x = opt[2..-1] if obj.respond_to?("#{x}=") obj.send("#{x}=",true) else obj.option_missing(x, argv) end end |
.run(obj, argv = ARGV) ⇒ Object
71 72 73 74 75 76 77 78 79 |
# File 'lib/executable.rb', line 71 def run(obj, argv=ARGV) args = parse(obj, argv) subcmd = args.shift if subcmd && !obj.respond_to?("#{subcmd}=") obj.send(subcmd, *args) else obj.command_missing end end |
Instance Method Details
#command_missing ⇒ Object
This is the fallback subcommand. Override this to provide a fallback when no command is given on the commandline.
56 57 58 |
# File 'lib/executable.rb', line 56 def command_missing raise NoCommandError end |
#execute_command(argv = ARGV) ⇒ Object
Used to invoke the command.
50 51 52 |
# File 'lib/executable.rb', line 50 def execute_command(argv=ARGV) Executable.run(self, argv) end |
#option_missing(opt, *argv) ⇒ Object
Override option_missing if needed. This receives the name of the option and the remaining arguments list. It must consume any argument it uses from the (begining of) the list.
65 66 67 |
# File 'lib/executable.rb', line 65 def option_missing(opt, *argv) raise NoOptionError, opt end |