NAME
main.rb
SYNOPSIS
a class factory and dsl for generating real main programs real quick
URI
http://rubyforge.org/projects/codeforpeople/
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