Friday, November 04, 2011

Ruby, OptionParser, and Switches with Optional Arguments

Ruby's OptionParser supports switches with optional arguments. Both the official documentation and the pickaxe book give examples of various syntax choices like these:

"--switch [OPTIONAL]"
"--switch [=OPTIONAL]"
"--switch" "=[OPTIONAL]"

Somewhere along the way the first time I needed a switch with an optional argument I copied the third syntax, where the argument is specified as a separate string.

Later I noticed odd behavior. While my switches with required arguments could be used with or without an equals sign, my switches with optional arguments required an equals sign. I.e. "--switch foo" did not work for the switches with optional arguments, while "--switch=foo" did work.

I've lived with this oddity for several years. But then recently I picked up a copy of the new "Build Awesome Command-Line Applications in Ruby" book and was giving it a read. In their section about OptionParser they only listed the first syntax (all one string, no equals sign). That got me wondering if the
equals sign made a difference.

I went back and re-read the OptionParser section of the pickaxe book and noticed an interesting statement differentiating "--switch=ARG" from "--switch ARG". Specifically they say the later syntax "specifies the argument follows the switch."

Hmm, that sounds promising. Write a quick test. Yes! "--switch [ARG]" makes the argument optional, and with or without the equals sign. I should have stopped there, but now I was curious. So I tried "--switch=[ARG]", and oddly it works the same way. Optional argument, optional equals sign. Hmm, that's odd. Try the "--switch" "=[ARG]" syntax again just to make sure I'm not going crazy. Nope, not crazy. Argument is optional, but equals sign is not.

So, a bit more pondering and I come up with 9 possible syntaxes and set about to try them all:

"--switch [OPTIONAL]"
"--switch [=OPTIONAL]"
"--switch =[OPTIONAL]"
"--switch" "=[OPTIONAL]"
"--switch" "[=OPTIONAL]"
"--switch" "[OPTIONAL]"
"--switch[OPTIONAL]"
"--switch[=OPTIONAL]"
"--switch=[OPTIONAL]"

Interesting, all 9 are valid syntax for OptionParser. 8 work in terms of the argument being optional, "--switch =[OPTIONAL]" being the odd one where the argument is required despite the square brackets (tested with both ruby 1.8.7 and 1.9.2).

And finally, drumroll please, the distinction that actually makes the equals sign required is when you specify the argument as a separate string. The presence or position of the equals sign when specifying the switch to OptionParser makes no difference, except as noted with the "--switch =[OPTIONAL]" syntax. "--switch [=OPTIONAL]"? No equals sign required. "--switch" "[OPTIONAL]"? Equals sign required.  Wacky.

+1 to the Pickaxe book for prompting me to ponder the different syntaxes, but -1 for being somewhere between misleading and wrong in actually documenting the difference.

Monday, October 10, 2011

FIOS Router CLI and DHCP


I recently got Verizon FIOS service.  The router Verizon provides is an Actiontec MI424WR.  Verizon goes to some trouble to hide the Actiontec branding; but, for example, the Model Name field in the System Monitoring tab on mine says "MI424WR-GEN2".

Anyway, I wanted to get the DHCP lease database out of the router in order to populate that information into my own DNS server.  I initially looked at scraping the web interface, but the router does some weird Javascript hashing of the password before submitting it to the server.  I figured there had to be a better way.

In the advanced options you can turn on telnet access to the router.  That gets you into a command line administration utility, which in turn will let you access a shell (via "system shell").  However I was unable to find a DHCP lease database in the filesystem.  There was a /var/state/dhcp directory, but it was empty.

Some searching on the web turned up the fact that the Actiontec MI424WR runs a commercial Linux distro called OpenRG.  More searching turned up an OpenRG Configuration Entries Guide.  A bit more poking and I found that this command will dump out the DHCP lease database:

conf print dev/br0/dhcps/lease

Friday, October 07, 2011

Python Packages

I'm new to the Python and Django world, having primarily worked with Ruby and Ruby on Rails for the last few years.  In reading about how to manage dependencies several folks referred to pip and distribute as the new hotness (literally).  Ok, fine, they're probably something like ruby gems, but what's the difference?

Looking over their respective pages (http://pypi.python.org/pypi/pip and http://pypi.python.org/pypi/distribute) it is confusing to see that there appears to be some sort of circular dependency.  The pip page says "In order to use pip, you must first install setuptools or distribute."  The distribute page gives instructions for installing distribute via pip.  Wha?!

The heading at the top of the pip page says "pip installs packages. Python packages."  The heading of the distribute page says "Easily download, build, install, upgrade, and uninstall Python packages".  Argh, still confused.

Pip is more clearly documented, and serves in the roll of package downloader, dependency resolver and installer.  This would be analogous to yum or apt.  I.e. pip does not create packages.  Pip apparently replaces something called easy_install.

So if you're just using existing packages you'll just use pip, possibly in combination with virtualenv for isolation (similar to bundler in the Ruby world).

So what about distribute?  The distribute documentation is terribly confusing.  It says it replaces setuptools, but then seems to imply that it is setuptools.  It looks like distribute is a fork of setuptools because the setuptools maintainer stopped maintenance.  And I guess in parallel there's another tool called distutils.  These all are used to make packages.  As is usual for package making there's a metadata file (setup.py in this case) and setuptools/distribute/distutils take that and a directory full of files and makes a package.

And apparently because setuptools, distribute and distutils all have problems there's work underway on distutils2 to replace them all.

On a side note, you'll also find references to eggs.  This is apparently a packaging format introduced by setuptools.  It seems to have lost favor.  The PyPI repository distributes packages as generic tarballs.

So, in summary if you're making a package use distribute or distutils, and if you're installing a package use pip.  I think.  :)

Other references:
http://guide.python-distribute.org/
http://packages.python.org/distribute/

Tuesday, August 23, 2011

Upgraded to Mac OS 10.7 (Lion)?  Tried to update Macports with sudo port selfupdate and get:

Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: shell command failed (see log for details)


You probably still have the Snow Leopard version of Xcode installed.  Try to run Xcode, it will probably tell you that you need to upgrade.  Go delete the Install Xcode app from your Applications folder, fire up the App Store app and get Xcode again.  That will get you the installer for Lion, which you can then run to upgrade Xcode to the Lion compatible version.  Then the Macport update should work.

Tuesday, April 12, 2011

I'm working on a MacRuby project in Xcode.  I upgraded Xcode from 4.0 to 4.0.1 and Interface Builder stopped working right for my project.  New outlets weren't showing up so I couldn't connect them to UI elements.  I eventually realized that in the Xcode upgrade the MacRuby templates got wiped out.  A reinstall of MacRuby got things working again.

Wednesday, April 06, 2011

Filesystem Hierarchy Standard for Mac OS X

I frequently refer to the Filesystem Hierarchy Standard when trying to figure out where to put files on Linux systems.

I recently started doing some Mac development and was looking for an equivalent document. Apple's File System Overview seems to cover similar ground.