Module Boson::Scientist

  1. lib/boson/scientist.rb

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}]

Classes and Modules

Class Boson::Scientist::Error

Attributes

global_options [RW]
render [RW]
rendered [RW]

Public instance methods

commandify (obj, hash)

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}]
[show source]
# 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
redefine_command (obj, command)

Redefines an object’s method with a Command of the same name.

[show source]
# 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
redefine_command_block (obj, command)

The actual method which redefines a command’s original method

[show source]
# 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