Scientist wraps around and redefines an object’s method to give it the following features:
- Methods can take shell command input with options or receive its normal arguments. See the Commandification section.
- Methods have a slew of global options available. See OptionCommand for an explanation of basic global options.
- Before a method returns its value, it pipes its return value through pipe commands if pipe options are specified. See Pipe.
- Methods can have any number of optional views associated with them via global render options (see View). Views can be toggled on/off with the global option —render (see OptionCommand).
The main methods Scientist provides are redefine_command() for redefining an object’s method with a Command object and commandify() for redefining with a hash of method attributes. Note that for an object’s method to be redefined correctly, its last argument must expect a hash.
Commandification
Take for example this basic method/command with an options definition:
options :level=>:numeric, :verbose=>:boolean def foo(*args) args end
When Scientist wraps around foo(), it can take arguments normally or as a shell command:
foo 'one', 'two', :verbose=>true # normal call foo 'one two -v' # commandline call Both calls return: ['one', 'two', {:verbose=>true}]
Non-string arguments can be passed as well:
foo Object, 'two', :level=>1 foo Object, 'two -l1' Both calls return: [Object, 'two', {:level=>1}]
Attributes
global_options | [RW] | |
render | [RW] | |
rendered | [RW] |
Public instance methods
A wrapper around redefine_command that doesn’t depend on a Command object. Rather you simply pass a hash of command attributes (see Command.new) or command methods and let OpenStruct mock a command. The only required attribute is :name, though to get any real use you should define :options and :arg_size (default is ’*’). Example:
>> def checkit(*args); args; end => nil >> Boson::Scientist.commandify(self, :name=>'checkit', :options=>{:verbose=>:boolean, :num=>:numeric}) => ['checkit'] # regular ruby method >> checkit 'one', 'two', :num=>13, :verbose=>true => ["one", "two", {:num=>13, :verbose=>true}] # commandline ruby method >> checkit 'one two -v -n=13' => ["one", "two", {:num=>13, :verbose=>true}]
# File lib/boson/scientist.rb, line 67 def commandify(obj, hash) raise ArgumentError, ":name required" unless hash[:name] hash[:arg_size] ||= '*' hash[:has_splat_args?] = true if hash[:arg_size] == '*' fake_cmd = OpenStruct.new(hash) fake_cmd.option_parser ||= OptionParser.new(fake_cmd.options || {}) redefine_command(obj, fake_cmd) end
Redefines an object’s method with a Command of the same name.
# File lib/boson/scientist.rb, line 43 def redefine_command(obj, command) cmd_block = redefine_command_block(obj, command) @no_option_commands << command if command.options.nil? [command.name, command.alias].compact.each {|e| obj.instance_eval("class<<self;self;end").send(:define_method, e, cmd_block) } rescue Error $stderr.puts "Error: #{$!.message}" end
The actual method which redefines a command’s original method
# File lib/boson/scientist.rb, line 77 def redefine_command_block(obj, command) object_methods(obj)[command.name] ||= begin obj.method(command.name) rescue NameError raise Error, "No method exists to redefine command '#{command.name}'." end lambda {|*args| Scientist.translate_and_render(obj, command, args) {|args| Scientist.object_methods(obj)[command.name].call(*args) } } end