Module: Boson::Scientist
Overview
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:
: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}]
Defined Under Namespace
Classes: Error
Instance Attribute Summary collapse
-
#global_options ⇒ Object
Returns the value of attribute global_options.
-
#render ⇒ Object
Returns the value of attribute render.
-
#rendered ⇒ Object
Returns the value of attribute rendered.
Instance Method Summary collapse
- #call_original_command(args, &block) ⇒ Object
- #can_render? ⇒ Boolean
- #command_renders? ⇒ Boolean
-
#commandify(obj, hash) ⇒ Object
A wrapper around redefine_command that doesn’t depend on a Command object.
-
#object_methods(obj) ⇒ Object
:stopdoc:.
- #option_command(cmd = @command) ⇒ Object
-
#redefine_command(obj, command) ⇒ Object
Redefines an object’s method with a Command of the same name.
-
#redefine_command_block(obj, command) ⇒ Object
The actual method which redefines a command’s original method.
- #render_or_raw(result) ⇒ Object
- #run_help_option ⇒ Object
- #run_pretend_option(args) ⇒ Object
- #run_verbose_help(option_command, original_args) ⇒ Object
- #translate_and_render(obj, command, args, &block) ⇒ Object
- #translate_args(obj, args) ⇒ Object
Instance Attribute Details
#global_options ⇒ Object
Returns the value of attribute global_options.
37 38 39 |
# File 'lib/boson/scientist.rb', line 37 def @global_options end |
#render ⇒ Object
Returns the value of attribute render.
37 38 39 |
# File 'lib/boson/scientist.rb', line 37 def render @render end |
#rendered ⇒ Object
Returns the value of attribute rendered.
37 38 39 |
# File 'lib/boson/scientist.rb', line 37 def rendered @rendered end |
Instance Method Details
#call_original_command(args, &block) ⇒ Object
99 100 101 |
# File 'lib/boson/scientist.rb', line 99 def call_original_command(args, &block) block.call(args) end |
#can_render? ⇒ Boolean
173 174 175 |
# File 'lib/boson/scientist.rb', line 173 def can_render? render.nil? ? command_renders? : render end |
#command_renders? ⇒ Boolean
177 178 179 |
# File 'lib/boson/scientist.rb', line 177 def command_renders? (!!@command. ^ @global_options[:render]) && !Pipe.any_no_render_pipes?(@global_options) end |
#commandify(obj, hash) ⇒ Object
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}]
67 68 69 70 71 72 73 74 |
# 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. || {}) redefine_command(obj, fake_cmd) end |
#object_methods(obj) ⇒ Object
:stopdoc:
91 92 93 |
# File 'lib/boson/scientist.rb', line 91 def object_methods(obj) @object_methods[obj] ||= {} end |
#option_command(cmd = @command) ⇒ Object
95 96 97 |
# File 'lib/boson/scientist.rb', line 95 def option_command(cmd=@command) @option_commands[cmd] ||= OptionCommand.new(cmd) end |
#redefine_command(obj, command) ⇒ Object
Redefines an object’s method with a Command of the same name.
43 44 45 46 47 48 49 50 51 |
# 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..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: #{$!.}" end |
#redefine_command_block(obj, command) ⇒ Object
The actual method which redefines a command’s original method
77 78 79 80 81 82 83 84 85 86 87 88 |
# 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 |
#render_or_raw(result) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/boson/scientist.rb', line 160 def render_or_raw(result) if (@rendered = can_render?) if @global_options.key?(:class) || @global_options.key?(:method) result = Pipe.scientist_process(result, @global_options, :config=>@command.config, :args=>@args, :options=>@current_options) end View.render(result, OptionCommand.(@global_options.dup), false) else Pipe.scientist_process(result, @global_options, :config=>@command.config, :args=>@args, :options=>@current_options) end rescue StandardError raise Error, $!., $!.backtrace end |
#run_help_option ⇒ Object
147 148 149 150 151 |
# File 'lib/boson/scientist.rb', line 147 def run_help_option opts = @global_options[:verbose] ? ['--verbose'] : [] opts << "--render_options=#{@global_options[:usage_options]}" if @global_options[:usage_options] Boson.invoke :usage, @command.full_name + " " + opts.join(' ') end |
#run_pretend_option(args) ⇒ Object
153 154 155 156 157 158 |
# File 'lib/boson/scientist.rb', line 153 def run_pretend_option(args) if @global_options[:verbose] || @global_options[:pretend] puts "Arguments: #{args.inspect}", "Global options: #{@global_options.inspect}" end @rendered = true if @global_options[:pretend] end |
#run_verbose_help(option_command, original_args) ⇒ Object
137 138 139 140 141 142 143 144 145 |
# File 'lib/boson/scientist.rb', line 137 def run_verbose_help(option_command, original_args) global_opts = option_command.(original_args) if global_opts[:help] && global_opts[:verbose] @global_options = global_opts run_help_option return true end false end |
#translate_and_render(obj, command, args, &block) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/boson/scientist.rb', line 103 def translate_and_render(obj, command, args, &block) @global_options, @command, original_args = {}, command, args.dup @args = translate_args(obj, args) return run_help_option if @global_options[:help] run_pretend_option(@args) render_or_raw call_original_command(@args, &block) unless @global_options[:pretend] rescue OptionCommand::CommandArgumentError run_pretend_option(@args ||= []) return if !@global_options[:pretend] && run_verbose_help(option_command, original_args) raise unless @global_options[:pretend] rescue OptionParser::Error, Error raise if Runner.in_shell? = @global_options[:verbose] ? "#{$!}\n#{$!.backtrace.inspect}" : $!. $stderr.puts "Error: " + end |
#translate_args(obj, args) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/boson/scientist.rb', line 119 def translate_args(obj, args) option_command.modify_args(args) @global_options, @current_options, args = option_command.parse(args) return if @global_options[:help] (@global_options[:delete_options] || []).map {|e| @global_options.keys.map {|k| k.to_s }.grep(/^#{e}/) }.flatten.each {|e| @global_options.delete(e.to_sym) } if @current_options option_command.add_default_args(args, obj) return args if @no_option_commands.include?(@command) args << @current_options option_command.check_argument_size(args) end args end |