-
I put all of these files in
~/bin, you can put them
where you want. But, if you don't there could be a hiccup
caused from relying that they are in ~/bin.
-
If I want to do some task, that task will probably be done
repeatedly, but don't want to invest tons of time into
actually writing the overhead that makes
maintainable/understandable scripts (e.g. argument parsing, help
printing, convenient methods abstracted out to base classes, etc)
I would first
invoke newapp with the name of the app(s) as argument(s)
and some other options, and it will create the file, make it
executable, and try to add it to SVN. Here are the full set of
options you'd see if you type pass the one of the two help
arguments,
-h or -help, or simply invoke
it with no arguments.
% newapp
Produces starter code for commandline apps using the 'app' gem
Usage: newapp <options> <arguments>
where options include:
-h | -help Print this message
-v | -verbose Print debugging messages
-d | -describe Print a desription of this program
-e | -explainargs Print a desription of the argument types
-b | -bindir Use ~/bin for you destintion directory.
-n | -motions Just go through the motions
-f | -force Force override of existing files
-t | -text <s> New description of the app, 's'
and where arguments are 'app names'
After that a new file will be created for every name you pass as an argument. For example:
% newapp a_sample_app -t "A sample app for this blog post"
% cat a_sample_app
#!/usr/bin/env ruby
#
# A sample app for this blog post
#
require 'rubygems'
require 'app'
class ASampleApp < App
def initialize
super
end
def description
"A sample app for this blog post"
end
def default_arguments
[]
end
def argument_explanations
[]
end
def get_options
end
def process_arg(arg)
throw 'Implementation missing for method ' +
q(self.class.name + '.process_arg')
# OK
0
end
end
ASampleApp.new.main ARGV
-
First, something about the arguments...all apps that are
subclasses of App support the following arguments:
-h | -help Print this message
-v | -verbose Print debugging messages
-d | -describe Print a desription of this program
-e | -explainargs Print a desription of the argument types
-b | -bindir Use /users/jeff/bin for you destintion directory.
-n | -motions Just go through the motions
To add more arguments implement the method get_options to return a list of Options, for example:
def get_options
[new_force_opt,
new_text_opt,
new_opt('-j','-jeff',"Print jeff's name"),
new_long_opt('-s','-string',"Use the passed in",true)]
end
Here, the two methods that create Options
are new_opt(short_opt,long_opt,description)
and new_long_opt(short_opt,long_opt,text,required),
the other true are shortcuts for commonly-used options.
-
Within your code, member variables are set by reflection, so for
the third options from above, you could refer to the jeff
option with
@opt_j or @opt_jeff.
-
There is a special method for side-effecting code -- like file
creation or deletion -- called
block(msg) that takes
as arguments a string msg and a thunk. If the user
passes in -n or -motions, as
in make, this method simply prints out the message.
These options control whether any actually 'happens'. In normal
mode, the thunk is run and msg is printed if the user
has passed verbose options. I really like this one, probably the
most, and here's an example of how you would use this to delete a
file, f:
f = ...
block 'Deleting file ' + f do
File.delete f
end
This way it's easier to write code that you can just see what it
will do first, before doing things that could change your machine.
I kinda rambled there, but the idea is that the migration from little
scripts to real programs shouldn't be painful. In fact, it should be
fun, and these are fun to write (OK, I may have lost a lot of readers
there). So, you should never have to parse arguments, or write help
screens, or comment out nasty stuff that could screw things up. You
just really implement one method -- parse_arg -- and do
your stuff in there.
Posted by jeff at December 1, 2009 07:53 PM