• Stars
    star
    266
  • Rank 154,103 (Top 4 %)
  • Language
    Ruby
  • Created over 15 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

a class factory and dsl for generating command line programs real quick
NAME
  main.rb

SYNOPSIS
  a class factory and dsl for generating command line programs real quick

URI
  http://codeforpeople.com/lib/ruby/
  http://rubyforge.org/projects/codeforpeople/
  http://github.com/ahoward/main

INSTALL
  gem install main

DESCRIPTION
  main.rb features the following:

    - unification of option, argument, keyword, and environment parameter
      parsing
    - auto generation of usage and help messages
    - support for mode/sub-commands
    - io redirection support
    - logging hooks using ruby's built-in logging mechanism
    - intelligent error handling and exit codes 
    - use as dsl or library for building Main objects
    - parsing user defined ARGV and ENV
    - zero requirements for understanding the obtuse apis of *any* command
      line option parsers
    - leather pants

  in short main.rb aims to drastically lower the barrier to writing uniform
  command line applications.

  for instance, this program

    require 'main'

    Main {
      argument 'foo'
      option 'bar'

      def run
        p params['foo']
        p params['bar']
        exit_success!
      end
    }

  sets up a program which requires one argument, 'bar', and which may accept one
  command line switch, '--foo' in addition to the single option/mode which is always
  accepted and handled appropriately: 'help', '--help', '-h'.  for the most
  part main.rb stays out of your command line namespace but insists that your
  application has at least a help mode/option.

  main.rb supports sub-commands in a very simple way

    require 'main'

    Main {
      mode 'install' do
        def run() puts 'installing...' end
      end

      mode 'uninstall' do
        def run() puts 'uninstalling...' end
      end
    }

  which allows a program, called 'a.rb', to be invoked as

    ruby a.rb install

  and

    ruby a.rb uninstall

  for simple programs main.rb is a real time saver but it's for more complex
  applications where main.rb's unification of parameter parsing, class
  configuration dsl, and auto-generation of usage messages can really streamline
  command line application development.  for example the following 'a.rb'
  program:

    require 'main'

    Main {
      argument('foo'){
        cast :int
      }
      keyword('bar'){
        arity 2
        cast :float
        defaults 0.0, 1.0
      }
      option('foobar'){
        argument :optional
        description 'the foobar option is very handy'
      }
      environment('BARFOO'){
        cast :list_of_bool
        synopsis 'export barfoo=value'
      }

      def run
        p params['foo'].value
        p params['bar'].values
        p params['foobar'].value
        p params['BARFOO'].value
      end
    }

  when run with a command line of

    BARFOO=true,false,false ruby a.rb 42 bar=40 bar=2 --foobar=a

  will produce

    42
    [40.0, 2.0]
    "a"
    [true, false, false]

  while a command line of

    ruby a.rb --help

  will produce

    NAME
      a.rb

    SYNOPSIS
      a.rb foo [bar=bar] [options]+

    PARAMETERS
      * foo [ 1 -> int(foo) ]

      * bar=bar [ 2 ~> float(bar=0.0,1.0) ]

      * --foobar=[foobar] [ 1 ~> foobar ]
          the foobar option is very handy

      * --help, -h

      * export barfoo=value

  and this shows how all of argument, keyword, option, and environment parsing
  can be declartively dealt with in a unified fashion - the dsl for all
  parameter types is the same - and how auto synopsis and usage generation saves
  keystrokes.  the parameter synopsis is compact and can be read as

      * foo [ 1 -> int(foo) ]

        'one argument will get processed via int(argument_name)'

          1        : one argument
          ->       : will get processed (the argument is required)
          int(foo) : the cast is int, the arg name is foo

      * bar=bar [ 2 ~> float(bar=0.0,1.0) ]

        'two keyword arguments might be processed via float(bar=0.0,1.0)'

          2                  : two arguments
          ~>                 : might be processed (the argument is optional)
          float(bar=0.0,1.0) : the cast will be float, the default values are
                               0.0 and 1.0

      * --foobar=[foobar] [ 1 ~> foobar ]

        'one option with optional argument may be given directly'

      * --help, -h

        no synopsis, simple switch takes no args and is not required

      * export barfoo=value

        a user defined synopsis

SAMPLES

  <========< samples/a.rb >========>

  ~ > cat samples/a.rb

    require 'main'
    
    ARGV.replace %w( 42 ) if ARGV.empty?
    
    Main {
      argument('foo'){
        required                    # this is the default
        cast :int                   # value cast to Fixnum
        validate{|foo| foo == 42}   # raises error in failure case 
        description 'the foo param' # shown in --help
      }
    
      def run
        p params['foo'].given?
        p params['foo'].value
      end
    }

  ~ > ruby samples/a.rb

    true
    42


  <========< samples/b.rb >========>

  ~ > cat samples/b.rb

    require 'main'
    
    ARGV.replace %w( 40 1 1 ) if ARGV.empty?
    
    Main {
      argument('foo'){
        arity 3                             # foo will given three times
        cast :int                           # value cast to Fixnum
        validate{|foo| [40,1].include? foo} # raises error in failure case 
        description 'the foo param'         # shown in --help
      }
    
      def run
        p params['foo'].given?
        p params['foo'].values
      end
    }

  ~ > ruby samples/b.rb

    true
    [40, 1, 1]


  <========< samples/c.rb >========>

  ~ > cat samples/c.rb

    require 'main'
    
    ARGV.replace %w( foo=40 foo=2 bar=false ) if ARGV.empty?
    
    Main {
      keyword('foo'){
        required  # by default keywords are not required
        arity 2
        cast :float
      }
      keyword('bar'){
        cast :bool
      }
    
      def run
        p params['foo'].given?
        p params['foo'].values
        p params['bar'].given?
        p params['bar'].value
      end
    }

  ~ > ruby samples/c.rb

    true
    [40.0, 2.0]
    true
    false


  <========< samples/d.rb >========>

  ~ > cat samples/d.rb

    require 'main'
    
    ARGV.replace %w( --foo=40 -f2 ) if ARGV.empty?
    
    Main {
      option('foo', 'f'){
        required  # by default options are not required, we could use 'foo=foo'
                  # above as a shortcut
        argument_required
        arity 2
        cast :float
      }
    
      option('bar=[bar]', 'b'){  # note shortcut syntax for optional args
        # argument_optional      # we could also use this method
        cast :bool
        default false
      }
    
      def run
        p params['foo'].given?
        p params['foo'].values
        p params['bar'].given?
        p params['bar'].value
      end
    }

  ~ > ruby samples/d.rb

    true
    [40.0, 2.0]
    nil
    false


  <========< samples/e.rb >========>

  ~ > cat samples/e.rb

    require 'main'
    
    ARGV.replace %w( x y argument )
    
    Main {
      argument 'argument'
      option 'option'
    
      def run() puts 'run' end
    
      mode 'a' do
        option 'a-option'
        def run() puts 'a-run' end
      end
    
      mode 'x' do
        option 'x-option'
    
        def run() puts 'x-run' end
    
          mode 'y' do
            option 'y-option'
    
            def run() puts 'y-run' end
          end
      end
    }

  ~ > ruby samples/e.rb

    y-run


  <========< samples/f.rb >========>

  ~ > cat samples/f.rb

    require 'main'
    
    ARGV.replace %W( compress /data )
    
    Main {
      argument('directory'){ description 'the directory to operate on' }
    
      option('force'){ description 'use a bigger hammer' }
    
      def run
        puts 'this is how we run when no mode is specified'
      end
    
      mode 'compress' do
        option('bzip'){ description 'use bzip compression' }
    
        def run
          puts 'this is how we run in compress mode' 
        end
      end
    
      mode 'uncompress' do
        option('delete-after'){ description 'delete orginal file after uncompressing' }
    
        def run
          puts 'this is how we run in un-compress mode' 
        end
      end
    }

  ~ > ruby samples/f.rb

    this is how we run in compress mode


  <========< samples/g.rb >========>

  ~ > cat samples/g.rb

    require 'main'
    
    ARGV.replace %w( 42 ) if ARGV.empty?
    
    Main {
      argument( 'foo' )
      option( 'bar' )
    
      run { puts "This is what to_options produces: #{params.to_options.inspect}" }
    }

  ~ > ruby samples/g.rb

    This is what to_options produces: {"help"=>nil, "foo"=>"42", "bar"=>nil}


  <========< samples/h.rb >========>

  ~ > cat samples/h.rb

    require 'main'
    
    # block-defaults are instance_eval'd in the main instance and be combined with
    # mixins
    #
    # ./h.rb   #=> forty-two
    # ./h.rb a #=> 42 
    # ./h.rb b #=> 42.0 
    #
    
    Main {
      fattr :default_for_foobar => 'forty-two' 
    
      option(:foobar) do
        default{ default_for_foobar }
      end
    
      mixin :foo do
        fattr :default_for_foobar => 42
      end
    
      mixin :bar do
        fattr :default_for_foobar => 42.0
      end
    
    
      run{ p params[:foobar].value }
    
      mode :a do
        mixin :foo
      end
    
      mode :b do
        mixin :bar
      end
    }

  ~ > ruby samples/h.rb

    "forty-two"


  <========< samples/j.rb >========>

  ~ > cat samples/j.rb

    #!/usr/bin/env ruby
    
    require 'open-uri'
    
    require 'main'
    require 'digest/sha2'
    
    # you have access to a sequel/amalgalite/sqlite db for free
    #
    
    Main {
      name :i_can_haz_db
    
      db {
        create_table(:mp3s) do
          primary_key :id
          String :url
          String :sha
        end unless table_exists?(:mp3s)
      }
    
      def run
        url = 'http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3'
        mp3 = open(url){|fd| fd.read}
        sha = Digest::SHA2.hexdigest(mp3)
    
        db[:mp3s].insert(:url => url, :sha => sha)
        p db[:mp3s].all
        p db
      end
    }

  ~ > ruby samples/j.rb

    [{:url=>"http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3", :sha=>"54c99ac7588dcfce1e70540b734805e9c69ff98dcca001e6f2bdec140fb0f9dc", :id=>1}, {:url=>"http://s3.amazonaws.com/drawohara.com.mp3/ween-voodoo_lady.mp3", :sha=>"54c99ac7588dcfce1e70540b734805e9c69ff98dcca001e6f2bdec140fb0f9dc", :id=>2}]
    #<Sequel::Amalgalite::Database: "amalgalite://Users/ahoward/.i_can_haz_db/db.sqlite">



DOCS
  test/main.rb
  vim -p lib/main.rb lib/main/*rb
  API section below

HISTORY
  5.1.0
    - support for STATE_DIRNAME and STATE_BASENAME environment variables
  5.0.0
    ?
  4.4.0
    - support for automatic sequel/sqlite/amalgalite dbs for persistent state
      across invocations

        Main {
          db {
            create_table :foo do
              String key
              String val
            end unless table_exists? :foo
          }

          def run
            db[:foo].create(:key => 'using', :val => 'amalgalite')
          end
        }

      - support for automatic config files with auto populated template data

          Main {
            config :email => '[email protected]', :password => 'pa$$word'

            def run
              email = config[:email]
            end
          }

      - new paramter types :pathname, :path, :slug, :input, and :output 

      - input/output parameters.  can be filenames or '-' to supply
        stdin/stdout respectively

          Main {
            input :i
            output :o

            def run
              i = params[:i].value
              o = params[:o].value

              line = i.gets
              o.puts line
            end
          }

       - clean up warnings running with 'ruby -w'

       - fix a failing test

       - ability to ignore parameters in sub modes

          Main {
            argument :foo
            argument :bar

            def run
              p param[:bar].value
            end

            mode :ignoring do
              params[:foo].ignore!
            end
          }
  4.0.0
    - avoid duping ios.  new methods Main.push_ios! and Main.pop_ios! are
    utilized for testing.  this was done to make it simple to wrap
    daemon/servolux programs around main, althought not strictly required.
    not the version bump - there is not reason to expect existing main
    programs to break, but it *is* and interface change which requires a major
    version bump.

  3.0.0
    - major refactor to support modes via module/extend vs. subclassing.
    MIGHT NOT be backward compatible, though no known issues thus far.

  2.9.0
    - support ruby 1.9

  2.8.3
    - support for block defaults


  2.8.2
    - fixes and tests for negative arity/attr arguments, options, eg

        argument(:foo){
          arity -1  
        }

        def run  # ARGV == %w( a b c )
          p foo  #=> %w( a b c )
        end

      thanks nathan

  2.8.1
    - move from attributes.rb to fattr.rb

  2.8.0 
    - added 'to_options' method for Parameter::Table.  this allows you to convert
      all the parameters to a simple hash.  
      for example

        Main {
          option 'foo'
          argument 'baz'

          run { puts params.to_options.inspect } 

        }

  2.7.0
    - removed bundled arrayfields and attributes.  these are now dependancies
      mananged by rubygems.  a.k.a. you must have rubygems installed for main
      to work.

  2.6.0
    - added 'mixin' feaature for storing, and later evaluating a block of
      code.  the purpose of this is for use with modes where you want to keep
      your code dry, but may not want to define something in the base class
      for all to inherit.  'mixin' allows you to define the code to inherit
      once and the selectively drop it in child classes (modes) on demand.
      for example

        Main {
          mixin :foobar do
            option 'foo'
            option 'bar'
          end

          mode :install do
            mixin :foobar
          end

          mode :uninstall do
            mixin :foobar
          end

          mode :clean do
          end
        }

    - mode definitions are now deferred to the end of the Main block, so you
      can do this

        Main {
          mode 'a' do
            mixin :foo
          end

          mode 'b' do
            mixin :foo
          end

          def inherited_method
            42
          end

          mixin 'foo' do
            def another_inherited_method
              'forty-two'
            end
          end
        }

    - added sanity check at end of paramter contruction

    - improved auto usage generation when arity is used with arguments

    - removed 'p' shortcut in paramerter dsl because it collided with
      Kernel.p.  it's now called 'param'.  this method is availble *inside* a
      parameter definition

        option('foo', 'f'){
          synopsis "arity = #{ param.arity }"
        }
      
    - fixed bug where '--' did not signal the end of parameter parsing in a
      getoptlong compliant way

    - added (before/after)_parse_parameters, (before/after)_initialize, and
      (before/after)_run hooks

    - fixed bug where adding to usage via

        usage['my_section'] = 'custom message'

      totally horked the default auto generated usage message

    - updated dependancies in gemspec.rb for attributes (~> 5.0.0) and
      arrayfields (~> 4.3.0)

    - check that client code defined run, iff not wrap_run! is called.  this is
      so mains with a mode, but no run defined, still function correctly when 
      passed a mode

    - added new shortcut for creating accessors for parameters.  for example

        option('foo'){
          argument :required
          cast :int
          attr
        }

        def run
          p foo ### this attr will return the parameter's *value*
        end

      a block can be passed to specify how to extract the value from the
      parameter

        argument('foo'){
          optional
          default 21 
          cast :int
          attr{|param| param.value * 2}
        }

        def run
          p foo #=> 42 
        end

    - fixed bug where 'abort("message")' would print "message" twice on exit
      if running under a nested mode (yes again - the fix in 2.4.0 wasn't
      complete)

    - added a time cast, which uses Time.parse

        argument('login_time'){ cast :time }

    - added a date cast, which uses Date.parse

        argument('login_date'){ cast :date }
    

  2.5.0
    - added 'examples', 'samples', and 'api' kewords to main dsl.  each
      keyword takes a list of strings which will be included in the help
      message
        
        Main {
          examples "foobar example", "barfoo example"

          samples <<-txt
            do this

            don't do that
          txt

          api %(
            foobar string, hash

            barfoo hash, string
          ) 
        }

      results in a usage message with sections like

      ...

      EXAMPLES
        foobar example
        barfoo example

      SAMPLES
        do this

        don't do that

      API
        foobar string, hash

        barfoo hash, string

      ...

  2.4.0
    - fixed bug where 'abort("message")' would print "message" twice on exit
      if running under a nested mode.

    - allowed parameters to be overridden completely in subclasses (modes)

  2.3.0
    - re-worked Main.new such that client code may define an #initialize
      methods and the class will continue to work.  that is to say it's fine
      to do this

        Main {
          def initialize
            @a = 42
          end

          def run
            p @a
          end

          mode 'foo' do
            def run
              p @a
            end
          end
        }

      the client #initialize will be called *after* main has done it's normal
      initialization so things like @argv, @env, and @stdin will all be there
      in initialize.  of course you could have done this before but you'd have
      to both call super and call it with the correct arguments - now you can
      simply ignore it.

  2.2.0
    - added ability for parameter dsl error handlers to accept an argument,
      this will be passed the current error.  for example

        argument(:x) do
          arity 42
        
          error do |e|
            case e
              when Parameter::Arity
            ...
          end
        end  

    - refined the mode parsing a bit: modes can now be abbreviated to uniqness
      and, when the mode is ambiuous, a nice error message is printed, for
      example:

        ambiguous mode: in = (inflate or install)?

  2.1.0
    - added custom error handling dsl for parameters, this includes the ability
      to prepend, append, or replace the standard error handlers:

        require 'main'

        Main {
          argument 'x' do
            error :before do
              puts 'this fires *before* normal error handling using #instance_eval...'
            end

            error do
              puts 'this fires *instead of* normal error handling using #instance_eval...'
            end

            error :after do
              puts 'this fires *after* normal error handling using #instance_eval...'
            end
          end
          
          run(){ p param['x'].given? }
        }

    - added ability to exit at any time bypassing *all* error handling using
      'throw :exit, 42' where 42 is the desired exit status.  throw without a
      status simply exits with 0.

    - added 'help!' method which simply dumps out usage and exits

  2.0.0
    - removed need for proxy.rb via Main::Base.wrap_run!
    - added error handling hooks for parameter parsing
    - bundled arrayfields, attributes, and pervasives although gems are tried
      first
    - softened error messages for parameter parsing errors: certain classes of
      errors are now 'softspoken' and print only the message, not the entire
      stacktrace, to stderr.  much nicer for users.  this is configurable.
    - added subcommand/mode support
    - added support for user defined exception handling on top level
      exceptions/exits
    - added support for negative arity.  this users ruby's own arity
      semantics, for example:
      
        lambda{|*a|}.arity     == -1
        lambda{|a,*b|}.arity   == -2
        lambda{|a,b,*c|}.arity == -3
        ...

      in otherwords parameters now support 'zero or more', 'one or more' ...
      'n or more' argument semantics

  1.0.0
    - some improved usage messages from jeremy hinegardner

  0.0.2
    - removed dependancy on attributes/arrayfields.  main now has zero gem
      dependancies.

    - added support for io redirection.  redirection of stdin, stdout, and
      stderr can be done to any io like object or object that can be
      inerpreted as a pathname (object.to_s)

    - main objects can now easily be created and run on demand, which makes
      testing a breeze

        def test_unit_goodness!
          main = 
            Main.new{
              stdout StringIO.new 
              stderr '/dev/null'

              def run
                puts 42
              end
            }

          main.run
          main.stdout.rewind

          assert main.stdout.read == "42\n"
        end

    - added API section to readme and called it 'docs'

    - wrote a bunch more tests.  there are now 42 of them.

  0.0.1

    initial version.  this version extracts much of the functionality of alib's
    (gen install alib) Alib.script main program generator and also some of jim's
    freeze's excellent CommandLine::Aplication into what i hope is a simpler and
    more unified interface 

API

  Main {

  ###########################################################################
  #                       CLASS LEVEL API                                   #
  ###########################################################################
  #
  # the name of the program, auto-set and used in usage 
  #
    program 'foo.rb'
  #
  # a short description of program functionality, auto-set and used in usage
  #
    synopsis "foo.rb arg [options]+"
  #
  # long description of program functionality, used in usage iff set
  #
    description <<-hdoc
      this text will automatically be indented to the right level.

      it should describe how the program works in detail
    hdoc
  #
  # used in usage iff set
  #
    author '[email protected]'
  #
  # used in usage
  #
    version '0.0.42'
  #
  # stdin/out/err can be anthing which responds to read/write or a string
  # which will be opened as in the appropriate mode 
  #
    stdin '/dev/null'
    stdout '/dev/null'
    stderr open('/dev/null', 'w')
  #
  # the logger should be a Logger object, something 'write'-able, or a string
  # which will be used to open the logger.  the logger_level specifies the
  # initalize verbosity setting, the default is Logger::INFO
  #
    logger(( program + '.log' ))
    logger_level Logger::DEBUG
  #
  # you can configure exit codes.  the defaults are shown
  #
    exit_success # 0
    exit_failure # 1
    exit_warn    # 42
  #
  # the usage object is rather complex.  by default it's an object which can
  # be built up in sections using the 
  #
  #   usage["BUGS"] = "something about bugs'
  #
  # syntax to append sections onto the already pre-built usage message which
  # contains program, synopsis, parameter descriptions and the like
  #
  # however, you always replace the usage object wholesale with one of your
  # chosing like so
  #
    usage <<-txt
      my own usage message
    txt

  ###########################################################################
  #                         MODE API                                        #
  ###########################################################################
  #
  # modes are class factories that inherit from their parent class.  they can
  # be nested *arbitrarily* deep.  usage messages are tailored for each mode.
  # modes are, for the most part, independant classes but parameters are
  # always a superset of the parent class - a mode accepts all of it's parents
  # paramters *plus* and additional ones
  # 
    option 'inherited-option'
    argument 'inherited-argument'

    mode 'install' do
      option 'force' do
        description 'clobber existing installation'
      end

      def run
        inherited_method()
        puts 'installing...'
      end

      mode 'docs' do
        description 'installs the docs'

        def run
          puts 'installing docs...'
        end
      end
    end

    mode 'un-install' do
      option 'force' do
        description 'remove even if dependancies exist'
      end

      def run
        inherited_method()
        puts 'un-installing...'
      end
    end

    def run
      puts 'no mode yo?'
    end

    def inherited_method
      puts 'superclass_method...'
    end


  ###########################################################################
  #                         PARAMETER API                                   #
  ###########################################################################
  #
  # all the parameter types of argument|keyword|option|environment share this
  # api.  you must specify the type when the parameter method is used.
  # alternatively used one of the shortcut methods
  # argument|keyword|option|environment.  in otherwords
  #
  #   parameter('foo'){ type :option } 
  #
  # is synonymous with
  #
  #   option('foo'){ } 
  #
    option 'foo' {
    #
    # required - whether this paramter must by supplied on the command line.
    # note that you can create 'required' options with this keyword
    #
      required # or required true
    #
    # argument_required - applies only to options.
    #
      argument_required # argument :required
    #
    # argument_optional - applies only to options.
    #
      argument_optional # argument :optional
    #
    # cast - should be either a lambda taking one argument, or a symbol
    # designation one of the built in casts defined in Main::Cast.  supported
    # types are :boolean|:integer|:float|:numeric|:string|:uri.  built-in
    # casts can be abbreviated
    #
      cast :int
    #
    # validate - should be a lambda taking one argument and returning
    # true|false
    #
      validate{|int| int == 42}
    #
    # synopsis - should be a concise characterization of the paramter.  a
    # default synopsis is built automatically from the parameter.  this
    # information is displayed in the usage message
    #
      synopsis '--foo'
    #
    # description - a longer description of the paramter.  it appears in the
    # usage also.
    #
      description 'a long description of foo'
    #
    # arity - indicates how many times the parameter should appear on the
    # command line.  the default is one.  negative arities are supported and
    # follow the same rules as ruby methods/procs.
    #
      arity 2
    #
    # default - you can provide a default value in case none is given.  the
    # alias 'defaults' reads a bit nicer when you are giving a list of
    # defaults for paramters of > 1 arity
    #
      defaults 40, 2
    #
    # you can add custom per-parameter error handlers using the following
    #
      error :before do
        puts 'this fires *before* normal error handling using #instance_eval...'
      end

      error do
        puts 'this fires *instead of* normal error handling using #instance_eval...'
      end

      error :after do
        puts 'this fires *after* normal error handling using #instance_eval...'
      end
    }

  ###########################################################################
  #                       INSTANCE LEVEL API                                #
  ###########################################################################
  #
  # you must define a run method.  it is the only method you must define.
  #
    def run
      #
      # all parameters are available in the 'params' hash and via the alias
      # 'param'.  it can be indexed via string or symbol.  the values are all
      # Main::Parameter objects
      #
        foo = params['foo']
      #
      # the given? method indicates whether or not the parameter was given on
      # the commandline/environment, etc.  in particular this will not be true
      # when a default value was specified but no parameter was given 
      #
        foo.given?
      #
      # the list of all values can be retrieved via 'values'.  note that this
      # is always an array.
      #
        p foo.values
      #
      # the __first__ value can be retrieved via 'value'.  note that this
      # never an array.
      #
        p foo.value
      #
      # the methods debug|info|warn|error|fatal are delegated to the logger
      # object
      #
        info{ "this goes to the log" }
      #
      # you can set the exit_status at anytime.  this status is used when
      # exiting the program.  exceptions cause this to be ext_failure if, and
      # only if, the current value was exit_success.  in otherwords an
      # un-caught exception always results in a failing exit_status
      #
        exit_status exit_failure
      #
      # a few shortcuts both set the exit_status and exit the program.
      #
        exit_success!
        exit_failure!
        exit_warn!
    end

  }

More Repositories

1

sekrets

sekrets is a command line tool and library used to securely manage encrypted files and settings in your rails' applications and git repositories.
Ruby
268
star
2

open4

open child process with handles on pid, stdin, stdout, and stderr: manage child processes and their io handles easily.
Ruby
194
star
3

map

the ruby container you've always wanted: an ordered string/symbol indifferent hash
Ruby
167
star
4

systemu

univeral capture of stdout and stderr and handling of child process pid for windows, *nix, etc.
Ruby
126
star
5

testy

a BDD testing framework for ruby that's mad at the world and plans to kick it's ass in 78 freakin lines of code
Ruby
98
star
6

configuration

pure ruby scoped configuration files.
Ruby
80
star
7

forkoff

brain-dead simple parallel processing for ruby
Ruby
73
star
8

fattr

fattr.rb is a "fatter attr" for ruby and borrows heavily from the metakoans.rb ruby quiz
Ruby
73
star
9

session

session offers a persistent way to drive the shell (/bin/sh) via ruby
Ruby
63
star
10

dao

sa-weet data access object library for rails. top secret.
Ruby
61
star
11

lockfile

a ruby library for creating NFS safe lockfiles
Ruby
54
star
12

macaddr

cross platform mac address determination for ruby
Ruby
47
star
13

middleman-gibberish

password protect middleman pages - even on s3
JavaScript
47
star
14

threadify

threadify.rb makes it stupid easy to process a bunch of data using 'n' worker threads
Ruby
39
star
15

shared

shared.rb provides a super easy way to share code between classes or modules in a simple way.
Ruby
33
star
16

bj

Backgroundjob (Bj) is a brain dead simple, zero admin, background priority queue for Rails.
Ruby
31
star
17

tagz

tagz.rb generates html, xml, or any sgml variant like a small ninja running across the backs of a herd of giraffes swatting of heads like a mark-up weedwacker.
Ruby
31
star
18

demon

demon.rb - the ruby daemon library you've been waiting for
Ruby
29
star
19

slave

easy management of child process works over pipes and drb
Ruby
27
star
20

rails_build

A very small, very simple, very fast, and bullet proof static site generator built as a Rails 5 engine.
Ruby
25
star
21

objectpool

a simple, robust, generic thread-safe object pool for ruby
Ruby
20
star
22

rq

ruby queue is a zero-admin zero-configuration tool used to create instant unix clusters
Ruby
20
star
23

raptcha

low drain bamage, storage-less, session-less, plugin-less, zero admin, single-source-file secure captcha system for ruby and/or rails.
Ruby
19
star
24

arrayfields

allow keyword access to array instances.
Ruby
18
star
25

tumblr

a command line utility and library for the excellent tumblr blogging platform
Ruby
18
star
26

helene

helene is a plugin for writing rails applications on top of amazon's aws platform including sdb, s3, and sqs
Ruby
17
star
27

rego

run arbitrary commands easily when files change
Ruby
16
star
28

fbomb

fbomb is the dangerous flowdock bot
Ruby
16
star
29

fucking_favicons

fucking favicons fucking suck
Ruby
15
star
30

mongoid-haystack

a mongoid 3 zero-config, zero-integration, POLS pure mongo fulltext solution
Ruby
14
star
31

coxswain

encapsulate pre-forking master / worker pattern for ruby
Ruby
12
star
32

jquery.bires

bandwidth limited progressive image enhancement
JavaScript
12
star
33

hashish

awesome data access layer for rails/ruby projects
Ruby
12
star
34

rails_current

track current_STUFF mo betta
Ruby
9
star
35

assassin

no zombies ever, not even on `exit!` or `kill -9`
Ruby
9
star
36

default_url_options

all relative urls in rails all the time. even in mailers.
Ruby
8
star
37

forkhandle

a teeny library / design pattern for managing connections in a process and thread safe fashion
Ruby
7
star
38

rememberthemilk

simple (162 loc), json only, interface to the excellent RememberTheMilk API
Ruby
7
star
39

wrap

non-sucky :before and :after callbacks for any ruby class
Ruby
7
star
40

conducer

a model+view component for rails that combines the conductor and presenter pattern
Ruby
7
star
41

ro

ro is library for managing your site's content in git, as god intended.
Ruby
7
star
42

rails_default_url_options

you really can have default_url_options everywhere. even in mailers.
Ruby
7
star
43

options

options.rb handles keyword options in ruby in a simple and robust way
Ruby
6
star
44

irbcp

irbcp gives access to your system's clipboard (copy and paste) from irb
Ruby
6
star
45

rails_errors2html

simple and sane active_model error html rendering
Ruby
6
star
46

fukung

perhaps the most important ruby code EVAAARRR! gets random images from http://fukung.net.
Ruby
6
star
47

rails_nav

objectified navigation for rails
Ruby
5
star
48

cssjs

a zero learning curve zero contraints dsl for writing css stylesheets in javascript
JavaScript
5
star
49

pork

pork supports parallel programming in ruby using forked actors and durable sqlite message queues
Ruby
5
star
50

isolation

a small rails app to demonstrate what *you* don't understand about RDBMS transactions
Ruby
5
star
51

mongoid-fts

enable mongodb's new fulltext simply and quickly on your mongoid models, including pagination.
Ruby
4
star
52

lru_cache

a simple but efficient implementation of a size limited least recently used cache in ruby
Ruby
4
star
53

terminator

an external timeout mechanism based on processes and signals
Ruby
4
star
54

cdc

uber simple cross domain communication for javascript/iframes
JavaScript
4
star
55

coerce

a ruby library full of common cast/coercion operations
Ruby
4
star
56

rails_view

render views from anywhere. even without a controller context
Ruby
4
star
57

rails_helper

helper = Helper.new and helper.link_to(:foo)
Ruby
4
star
58

ggeocode

simple wrapper on google's new geocoding api
Ruby
4
star
59

suck

gem to show issues with gem/minigem load ordering
Shell
3
star
60

alpo

a library and design pattern for building sane web applications on top of the rails' stack
Ruby
3
star
61

backup.rake

rails' rake task for backup up and loading data+assets as yaml+files
Ruby
3
star
62

id3rename

id3rename is a program to do simple renaming of mp3 files
3
star
63

nfsutils

Ruby FileUtils for NFS
3
star
64

bookify

development moved to https://github.com/everlater/bookify
Ruby
3
star
65

senv

the 12-factor environment tool your mother told you to use
Ruby
3
star
66

codeforpeople

billions and billions of libs
3
star
67

ledis

a K.I.S.S auto-rotating redis logger for ruby/rails
Ruby
3
star
68

kgb

ultra lightweight javascript decision tree builder
JavaScript
3
star
69

image_cache

a small utility library to facility caching image uploads between form validation failures.
2
star
70

gnip-ruby

Ruby library for utilizing Gnip services.
Ruby
2
star
71

linked_list

a simple linked list implementation for ruby
Ruby
2
star
72

bucket

bucket is a command-line interface for amazon's s3 service
2
star
73

tmpdir_block

extends ruby's built-in Dir.tmpdir to accept a block.
Ruby
2
star
74

bestofyoutube

simple ruby library to grab some good video urls from http://bestofyoutube.com
Ruby
2
star
75

superhash

A general mechanism for defining attribute inheritance structures among objects of any type, not just classes
Ruby
2
star
76

testing.rb

adds the minimal features required in order to make test/unit not suck
Ruby
2
star
77

openobject

a simple property based container that's much more capable than a blankslate but far less polluted than ruby's built-in OpenStruct
Ruby
2
star
78

candy_store

hybrid session store that combines rails' built-in cookie based session store with its database backed one
Ruby
2
star
79

slug

a simple slug library. unicode prepared.
Ruby
2
star
80

markdown

my markdown script
Ruby
2
star
81

mongoid-bolt

mongoid-bolt is a concrete lock implementation and mixin.
Ruby
2
star
82

growltdf

growltdf is the greatest program evar. it let's you scrape http://cyclingnews.com for TDF updates and dump them into growl to you can keep up with the race while working.
2
star
83

nmap

narray + mmap = wicked fast persistent numerical arrays for ruby
Ruby
2
star
84

mob

background jobs for mongoid
Ruby
1
star
85

foobar

1
star
86

ydb

mo-betta the yaml/store.
Ruby
1
star
87

hrs

tracking teh hours from the cli
Ruby
1
star
88

mp3scrape

download shit-loads of mp3s from web pages
Ruby
1
star
89

wapp

golden.image
Ruby
1
star
90

upload_cache

a small utility library to facility caching http file uploads between form validation failures. designed for rails, but usable anywhere.
Ruby
1
star
91

forkify

forkify.rb makes it easy to process a bunch of data using 'n' worker processes
Ruby
1
star
92

ansible

magic unicorns for your deployz
Ruby
1
star
93

campfire

a command line script for using 37signal's campfire chat room
1
star
94

cast

a collection of casting methods for ruby
1
star
95

fifo

a very simple javascript fifo queue / cache
JavaScript
1
star
96

ey-cloud-recipes

A starter repo for custom chef recipes on EY's cloud platform
Ruby
1
star
97

test

1
star
98

one-click-hugo-cms

CSS
1
star
99

attributes

the implementation of attributes.rb borrows many of the best ideas from the metakoans.rb ruby quiz (ps. fattr >= attributes)
Ruby
1
star
100

gnip-expander

relay a gnip publisher stream to another, expanding shortened uris in the process
Ruby
1
star