# Main-2.0.0

**URL:** <https://www.ruby-forum.com/t/main-2-0-0/117672>\
**Category:** Ruby\
**Created:** [October 19, 2007, 4:38am UTC](https://www.ruby-forum.com/t/main-2-0-0/117672 "2007-10-19T04:38:28Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 19, 2007, 4:38am UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/1 "2007-10-19T04:38:28Z")

</div>

NAME  
main.rb

SYNOPSIS  
a class factory and dsl for generating command line 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  
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

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 you 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

```

~ \> 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]
 nil
 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
- vim -o lib/main.rb lib/main/\*
- API section below

HISTORY  
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

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 'removed_email_address@domain.invalid'

```

# 

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

########################################################################

### 

# 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

}

enjoy.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 19, 2007, 6:46am UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/2 "2007-10-19T06:46:30Z")

</div>

From: ara.t.howard [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]

# Subject: [ANN] main-2.0.0

quick qs:

1. how to invoke -h inside program.  
currently i use something like [exec “ruby #{ **FILE** } -h”]

2. required args that fail just gives/raise errors which is not so user  
friendly. How can i capture error cleanly? so i can display a user  
friendly error (and i also want to invoke help thereafter). Maybe  
require may need a block for the error to display, like,

Right now, i set required args back to optional and then i have to ask  
if args was given?

1. how can i access all the args and options i set? I’d like to change  
my synopsis automatically and beautifully 🙂

sorry for the many questions, ara.  
Thank you for main. It’s very cool.

kind regards -botp

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 19, 2007, 4:49pm UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/3 "2007-10-19T16:49:44Z")

</div>

Great, I’m looking forward to using this

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 19, 2007, 4:54pm UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/4 "2007-10-19T16:54:29Z")

</div>

Fantastic! I always thought there should be a more Ruby-ish way of  
handling things like this.

This probably won’t make it into any of my current projects, but I’ll  
definitely be using it in the future.

Thanks!  
Jeremy

On 10/18/07, ara.t.howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> [http://codeforpeople.com/lib/ruby/](http://codeforpeople.com/lib/ruby/)  
> - auto generation of usage and help messages  
> in short main.rb aims to drastically lower the barrier to writing
> 
> which is always  
> Main {
> 
> really streamline  
> keyword(‘bar’){  
> synopsis ‘export barfoo=value’  
> when run with a command line of  
> while a command line of
> 
> ```
> * export barfoo=value
> 'one argument will get processed via int(argument_name)'
> 2 : two arguments
> * --help, -h
> 
> validate{|foo| foo == 42} # raises error in failure case
> 
> ```
> 
> failure case
> 
> ```
> keyword('bar'){
> 
> c.rb
> 
> required # by default options are not required, we could
> cast :bool
> 
> d.rb
> 
> ```
> 
> - test/main.rb
> - softened error messages for parameter parsing errors: certain
> 
> # 
> 
> # 
> 
> # used in usage
> 
> # 
> 
> # 
> 
> # syntax to append sections onto the already pre-built usage
> 
> they can
> 
> ```
> mode 'docs' do
> description 'remove even if dependancies exist'
> end
> 
> ```
> 
> API #
> 
> # parameter(‘foo’){ type :option }
> 
> ```
> #
> # cast - should be either a lambda taking one argument, or a symbol
> #
> 
> ```
> 
> appears in the  
> arity 2  
> ########################################################################  
> def run  
> given on  
> p foo.values  
> #  
> #  
> enjoy.

–  
[http://www.jeremymcanally.com/](http://www.jeremymcanally.com/)

My books:  
Ruby in Practice

> **[Ruby in Practice](https://www.manning.com/books/ruby-in-practice)**
>
> Like Ruby itself, Ruby in Practice will make you more productive. The book shows you practical techniques and strategies for small projects and large-scale environments. A cookbook-style reference, it gives you concrete examples of systems...

My free Ruby e-book

> **[Site not found · DreamHost](http://www.humblelittlerubybook.com/)**
>
> The owner of this domain has not yet uploaded their website.

My blogs:

> **[Site not found · DreamHost](http://www.mrneighborly.com/)**
>
> The owner of this domain has not yet uploaded their website.

[http://www.rubyinpractice.com/](http://www.rubyinpractice.com/)

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 19, 2007, 5:36pm UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/5 "2007-10-19T17:36:44Z")

</div>

On Oct 18, 2007, at 10:46 PM, Peña, Botp wrote:

> From: ara.t.howard [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]
> 
> # Subject: [ANN] main-2.0.0
> 
> quick qs:
> 
> 1. how to invoke -h inside program.  
> currently i use something like [exec “ruby #{ **FILE** } -h”]

cfp:~/src/ruby/main/main-2.0.0 \> cat a.rb  
require ‘main’

Main {  
option ‘foobar’

```
 def run
   print usage.to_s
   exit
 end

```

}

cfp:~/src/ruby/main/main-2.0.0 \> ruby a.rb  
NAME  
a.rb

SYNOPSIS  
a.rb [options]+

PARAMETERS  
–foobar  
–help, -h

the reason that the ‘to\_s’ is required is that the usage returns and  
object that inherits from array and ruby treats ‘puts an\_array’  
specially. i should changed that in the next version… regardless  
‘usage.to\_s’ will continue to work.

> 1. required args that fail just gives/raise errors which is not so  
> user friendly.

i think 2.0.0 addresses this (common) complaint:

cfp:~/src/ruby/main/main-2.0.0 \> cat a.rb  
require ‘main’

Main {  
argument(‘foobar’){ required }

run(){ puts Main.version }  
}

cfp:~/src/ruby/main/main-2.0.0 \> ruby a.rb foobar  
2.0.0

cfp:~/src/ruby/main/main-2.0.0 \> ruby a.rb  
argument(foobar) not given

is that ok?

> How can i capture error cleanly? so i can display a user friendly  
> error (and i also want to invoke help thereafter). Maybe require  
> may need a block for the error to display, like,

hmmmm. right now you, in 2.0.0, you can define ‘handle\_exception’ on  
your class but you will need to handle all exceptions in that  
method… that’s not great i realize. in 2.0.0 i’ve added the  
concept of ‘Softspoken’ errors. these are errors that, rather than  
dumping a stacktrace in the log/stderr - simple print their message.  
that’s how the ‘argument(foobar) not given’ above is printed - it’s a  
‘Softspoken’ error and this is it’s message. now, as to the question  
of how to further handle errors but printing usage, etc… that’s  
harder. i’d personally NOT print usage after the error and instead  
suggest to the user to run the program with ‘-h’ because a long usage  
message printed after and error will cause the error to scroll off a  
small terminal… still it’s a real need…

> required {|error| code\_here}
> 
> or
> 
> def err err\_obj  
> end
> 
> # ie, main calls err if it exists
> 
> # but i still would not know what to put on err

ok i like this idea. the general concept is that parameter can have  
their own error handlers - let me chew on this a little bit and try  
to get a sample impl online for you to play with…

> Right now, i set required args back to optional and then i have to  
> ask if args was given?

oh that’s hacking we don’t want to doing that! 😉

> 1. how can i access all the args and options i set? I’d like to  
> change my synopsis automatically and beautifully 🙂

cfp:~/src/ruby/main/main-2.0.0 \> cat a.rb  
require ‘main’

Main {  
argument ‘foobar’  
argument ‘barfoo’  
option ‘a’  
option ‘b’

run(){ params.each{|pm| p pm} }  
}

cfp:~/src/ruby/main/main-2.0.0 \> ruby a.rb foobar barfoo --a --b  
#\<Main::Parameter::Argument:0x6c034 @given=true, @type=:argument,  
@arity=1, @values=[“foobar”], @names=[“foobar”], @defaults=[],  
@cast=nil, @required=true, @validate=nil\>  
#\<Main::Parameter::Argument:0x6b558 @given=true, @type=:argument,  
@arity=1, @values=[“barfoo”], @names=[“barfoo”], @defaults=[],  
@cast=nil, @required=true, @validate=nil\>  
#\<Main::Parameter::Option:0x6aa7c @given=true, @type=:option,  
@arity=1, @values=[true], @names=[“a”], @defaults=[], @cast=nil,  
@required=false, @argument=nil, @validate=nil\>  
#\<Main::Parameter::Option:0x69e24 @given=true, @type=:option,  
@arity=1, @values=[true], @names=[“b”], @defaults=[], @cast=nil,  
@required=false, @argument=nil, @validate=nil\>  
#\<Main::Parameter::Option:0x67a0c @given=nil, @type=:option,  
@arity=1, @names=[“help”, “h”], @defaults=[], @required=false,  
@argument=nil\>

i’d be interested to see what you come up with for an auto usage  
message - that part was very hard for me and i’m not sure mine is the  
best.

> sorry for the many questions, ara.  
> Thank you for main. It’s very cool.

glad you are using it, and the feedback is really welcome - it’s  
surprisingly difficult to get this working smoothly for even a modest  
sample of command line apps - there are a lot of variables! 😉

look for main-2.0.1 later today…

cheers.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 20, 2007, 6:51pm UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/6 "2007-10-20T18:51:29Z")

</div>

On Oct 19, 2007, at 9:41 PM, Peña, Botp wrote:

> # object that inherits from array and ruby treats ‘puts an\_array’
> 
> # specially. i should changed that in the next version… regardless
> 
> # ‘usage.to\_s’ will continue to work.
> 
> no problem, ara. The usage.to\_s is good enough.

great. in 2.1.0 (on rubyforge now) you can just use ‘help!’ which  
calls ‘print usage.to\_s; exit’ for you. i’ll rework the Usage class  
to be and Array delegate rather than an Array subclass soon. it  
annoys me that ‘puts usage’ does not work…

> where to add more 🙂
> 
> eg, i want to add sections like “other info”, “gotchas”,  
> “copyright”, “reporting bugs”, and “see also”.

oh. the Usage class is already setup to do that. simply do

usage[‘gotchas’] = huge\_block\_of\_text

and it will automatically be included in a nicely formatted way.

> it’s working great. really. my suggestions were purely cosmetics.  
> and btw, the new mode option is cool.  
> many thanks again.
> 
> kind regards -botp

glad to hear it - 2.1.0 also addresses your error handling issue:

cfp:~/src/ruby/main/main-2.1.0 \> cat a.rb  
require ‘main’

puts Main.version

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

cfp:~/src/ruby/main/main-2.1.0 \> ruby -I lib a.rb  
2.1.0  
this fires _before_ normal error handling using #instance\_eval…  
this fires _instead of_ normal error handling using #instance\_eval…  
this fires _after_ normal error handling using #instance\_eval…

in fact, 2.1.0 allows _any_ exception to specify it’s own error  
handlers - check out lib/main/base.rb and grep for ‘handler’.

kind regards.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![ara.t.howard](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a8b319/32.png) [@ara.t.howard](https://www.ruby-forum.com/u/ara.t.howard)\
**Post date:** [October 20, 2007, 5:42am UTC](https://www.ruby-forum.com/t/main-2-0-0/117672/7 "2007-10-20T05:42:33Z")

</div>

From: ara.t.howard [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]

# def run

# print usage.to\_s

arggh, i did not try the to\_s 🙂  
thanks

# exit

# end

# the reason that the ‘to\_s’ is required is that the usage returns and

# object that inherits from array and ruby treats ‘puts an\_array’

# specially. i should changed that in the next version… regardless

# ‘usage.to\_s’ will continue to work.

no problem, ara. The usage.to\_s is good enough.

# i’d be interested to see what you come up with for an auto usage

# message - that part was very hard for me and i’m not sure

# mine is the

# best.

# 

no, the automessage part is fine.  
my plan really is to add more info on --help and i was looking where to  
add more 🙂

eg, i want to add sections like “other info”, “gotchas”, “copyright”,  
“reporting bugs”, and “see also”.

# glad you are using it, and the feedback is really welcome - it’s

# surprisingly difficult to get this working smoothly for even

# a modest

# sample of command line apps - there are a lot of variables! 😉

# 

# look for main-2.0.1 later today…

it’s working great. really. my suggestions were purely cosmetics. and  
btw, the new mode option is cool.  
many thanks again.

kind regards -botp
