# Main-0.0.1 - command line apps for the truly lazy

**URL:** <https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474>\
**Category:** Ruby\
**Created:** [March 20, 2007, 7:31pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474 "2007-03-20T19:31:25Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 20, 2007, 7:31pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474/1 "2007-03-20T19:31:25Z")

</div>

NAME  
main.rb

SYNOPSIS  
a class factory and dsl for generating real main programs real quick

URI

[http://rubyforge.org/projects/codeforpeople/](http://rubyforge.org/projects/codeforpeople/)  
[http://codeforpeople.com/lib/ruby/](http://codeforpeople.com/lib/ruby/)

INSTALL

$sudo gem install main

DESCRIPTION  
main.rb is a library which simplifies and unifies the details of  
creating  
command line programs. 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 which  
is always  
accepted and handled appropriately: ‘–help’, ‘-h’.

for simple programs this 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

```

~ \> ruby samples/a.rb --help

```
 NAME
   a.rb

 SYNOPSIS
   a.rb foo [options]+

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

   * --help, -h

```

\<========\< 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]

```

~ \> ruby samples/b.rb --help

```
 NAME
   b.rb

 SYNOPSIS
   b.rb foo [options]+

 PARAMETERS
   * foo [3 -> int(foo)]
       the foo param

   * --help, -h

```

\<========\< 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

```

~ \> ruby samples/c.rb --help

```
 NAME
   c.rb

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

 PARAMETERS
   * foo=foo [2 -> float(foo)]

   * bar=bar [1 ~> bool(bar)]

   * --help, -h

```

\<========\< 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]
 true
 false

```

~ \> ruby samples/d.rb --help

```
 NAME
   d.rb

 SYNOPSIS
   d.rb --foo=foo [options]+

 PARAMETERS
   * --foo=foo, -f [2 -> float(foo)]

   * --bar=[bar], -b [1 ~> bool(bar=false)]

   * --help, -h

```

DOCS  
test/main.rb  
find lib|xargs -n1 vi -R

HISTORY  
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

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 20, 2007, 8:38pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474/2 "2007-03-20T20:38:34Z")

</div>

On 3/20/07, Ara.T.Howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> NAME  
> main.rb
> 
> SYNOPSIS  
> a class factory and dsl for generating real main programs real quick

Excellent looking library. I have some fascination with writing CLI  
apps,  
and have used the commandline gem extensively. My one complaint with  
that  
library was the obscure syntax used for parsing command line options.

Can the options parsed be used outside the Main { } declaration? For  
small  
scripts, the “run” method is fine, but for larger apps it becomes  
necessary  
to break things up. Specifically, I am thinking of some highline driven  
apps  
I have which would benefit from the option parsing provided here.

Justin

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 20, 2007, 8:57pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474/3 "2007-03-20T20:57:36Z")

</div>

On Wed, 21 Mar 2007, Justin B. wrote:

> Excellent looking library. I have some fascination with writing CLI apps,  
> and have used the commandline gem extensively. My one complaint with that  
> library was the obscure syntax used for parsing command line options.
> 
> Can the options parsed be used outside the Main { } declaration? For small  
> scripts, the “run” method is fine, but for larger apps it becomes necessary  
> to break things up. Specifically, I am thinking of some highline driven apps  
> I have which would benefit from the option parsing provided here.

harp:~ \> cat a.rb  
require ‘rubygems’  
require ‘main’

ARGV.replace %w( --foo=42 42.0 )

main = Main.new{  
option(‘foo=’){ cast :int }  
option(‘bar=’){ cast :float }  
}

p main.param[‘foo’]  
p main.param[‘bar’]

harp:~ \> ruby a.rb  
#\<Main::Parameter::Option:0xb74ce1b4 @given=true, @validate=nil,  
@cast=:int, @names=[“foo”], @arity=1, @argument=:required,  
@required=false, @values=[42], @type=:option, @defaults=[]\>  
#\<Main::Parameter::Option:0xb74cdd18 @given=nil, @cast=:float,  
@names=[“bar”], @argument=:required, @required=false, @type=:option,  
@defaults=[]\>

i realize, as i post this, that i’d meant for one to be able to say

argv = %w( --foo=42 42.0 )

env = {‘PATH’ =\> ‘/usr/loca/bin’}

main = Main.new(argv, env){  
option(‘foo=’){ cast :int }  
option(‘bar=’){ cast :float }  
}

but neglected to pass some information through. i’ll think about it and  
ensure  
that’s possible v.s directly manipulating ARGV

this is quite a re-work of what’s in alib, so i’m all ears for  
comments/feature-requests. btw. the usage can be overridden simply  
with

Main{  
usage ‘my usage string’  
}

regards.

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 21, 2007, 8:21pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474/4 "2007-03-21T20:21:26Z")

</div>

On Thu, 22 Mar 2007, Jason R. wrote:

> Could you make the main gem dependent on other gems? I had to manually  
> install attributes and arrayfields to get main to run. Otherwise, this is a  
> cool little library, thanks!

will do. it was an oversight. i’m making a few mods today and should  
release  
later in the aftertoon.

cheers.

-a

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 21, 2007, 7:43pm UTC](https://www.ruby-forum.com/t/main-0-0-1-command-line-apps-for-the-truly-lazy/89474/5 "2007-03-21T19:43:13Z")

</div>

Could you make the main gem dependent on other gems? I had to manually  
install attributes and arrayfields to get main to run. Otherwise, this  
is a  
cool little library, thanks!

Jason
