class TheFox::Timr::SimpleOptParser

Simple Option Parser

Because OptParse sucks. Parsing arguments should be easy. :(

Covered Usecases

Usage

optparser = SimpleOptParser.new
optparser.register_option(['-a'])
optparser.register_option(['-b'])
optparser.register_option(['-c'], 1)
opts = optparser.parse('-a -b -c val')

Attributes

options[R]

Parsed Options (+Commands)

unknown_options[R]

Not Recognized Options

Public Class Methods

new() click to toggle source
# File lib/timr/simple_opt_parser.rb, line 38
def initialize
    #  -a   => 0
    # --all => 0
    #  -b   => 1
    @valid_options = Hash.new
    
    # a   => 0
    # all => 0
    # b   => 1
    # @valid_options_without_prefix = Hash.new
    
    # Parsed Options (+Commands)
    @options = Array.new
    
    # Not Recognized Options
    @unknown_options = Array.new
end

Public Instance Methods

parse(args) click to toggle source

args (Array|String)

# File lib/timr/simple_opt_parser.rb, line 82
def parse(args)
    # Reset previous options.
    @options = []
    
    if args.is_a?(Array)
        pre_argv = args
    else
        pre_argv = args.split(' ')
    end
    
    argv = Array.new
    
    # Pre-process Special Argument (Compact)
    # For example '-abcd' is '-a -b -c -d'.
    pre_argv.each do |arg|
        if arg[0] == '-'
            if arg[1] == '-'
                # Normal --arg
                argv << arg
            else
                if arg.length > 2
                    # Special -ab
                    arg = arg[1..-1]
                    
                    # Add each single argument separate.
                    # Array ['-abc'] will become ['-a', '-b', '-c'].
                    arg.length.times do |n|
                        argv << "-#{arg[n]}"
                    end
                else
                    # Normal -a
                    argv << arg
                end
            end
        else
            # Commands, Values, etc
            argv << arg
        end
    end
    
    loop_c = 0 # Limit the loop.
    while argv.length > 0 && loop_c < 1024
        loop_c += 1
        
        arg = argv.shift
        
        if arg[0] == '-'
            if @valid_options[arg]
                # Recognized Argument
                
                number_values = @valid_options[arg]
                
                if number_values == 0
                    # No values. Like Command.
                    @options << [arg]
                elsif number_values == -1
                    # Eat all the arguments. Nom nom nom.
                    arg_values = []
                    sub_loop_c = 0 # Limit the loop.
                    while argv.length > 0 && sub_loop_c < 1024
                        sub_loop_c += 1
                        
                        arg = argv.shift
                        
                        # When reaching the end.
                        unless arg
                            break
                        end
                        
                        arg_values << arg
                    end
                    @options << arg_values
                else
                    # n values.
                    
                    arg_values = []
                    sub_loop_c = 0 # Limit the loop.
                    while argv.length > 0 && sub_loop_c < number_values && sub_loop_c < 1024
                        sub_loop_c += 1
                        
                        val = argv.shift
                        
                        # When reaching the end.
                        unless val
                            raise ArgumentError, "SimpleOptParser: Argument '#{arg}' expects #{number_values} value(s). Found #{sub_loop_c}."
                        end
                        
                        if @valid_options[val]
                            raise ArgumentError, "SimpleOptParser: Argument '#{arg}' expects #{number_values} value(s). Found another Argument '#{val}'."
                        end
                        
                        arg_values << val
                    end
                    
                    if arg_values.length != number_values
                        raise ArgumentError, "SimpleOptParser: Argument '#{arg}' expects #{number_values} value(s), #{arg_values.length} given."
                    end
                    
                    arg_values.unshift(arg)
                    @options << arg_values
                end
            else
                # Unknown Arguments
                # '-ab' arguments will be processed in pre_argv.
                @unknown_options << arg
            end
        else
            # Command
            @options << [arg]
        end
    end
    
    @options
end
register_option(aliases, number_values = 0) click to toggle source

aliases (Array)

number_values

  • 0 = no value, just a switch

  • -1 = unlimited

  • n = n values

# File lib/timr/simple_opt_parser.rb, line 63
def register_option(aliases, number_values = 0)
    aliases.each do |ali|
        @valid_options[ali] = number_values
        
        # if ali[0] == '-'
        #  if ali[1] == '-'
        #      # --arg
        #      # Cut the two first characters.
        #      @valid_options_without_prefix[ali[2..-1]] = number_values
        #  else
        #      # -a
        #      # Cut only the first character.
        #      @valid_options_without_prefix[ali[1..-1]] = number_values
        #  end
        # end
    end
end
verify(opts) click to toggle source

Do not re-parse. Verify an already parsed array.

# File lib/timr/simple_opt_parser.rb, line 198
def verify(opts)
    opts.each do |opt_ar|
        arg = opt_ar.first
        
        number_values = @valid_options[arg]
        if number_values.nil?
            # Unknown Arguments
        else
            # Argument is valid.
            
            # Check length.
            if number_values == 0
                if opt_ar.length > 0
                    raise ArgumentError, "SimpleOptParser: Argument '#{arg}' expects no values, #{opt_ar.length} given."
                end
            elsif number_values == -1
                # Always OK. Keep eating, Pacman.
            else
                if number_values != opt_ar.length
                    raise ArgumentError, "SimpleOptParser: Argument '#{arg}' expects #{number_values} value(s), #{opt_ar.length} given."
                end
            end
        end
    end
    
    true
end