I have been working on my new project, using Eclipse as an IDE and ruby as a scripting language. Eclipse itself has it's quirks (such as having to create workspaces and projects before you can do anything) but once these are set up it is quite nice to use. I have discovered that the "Bitstream Vera Sans Mono" font is a very nice programming font to use in it, very crisp and clean and it doesn't have weird problems so I can use bold in syntax highlighting. I am also now, for the first time ever, sold on editors that display line numbers on each line, saves a lot of time when going through build/run errors. Then again, I am using a 22" Widescreen monitor with horizontal screen real-estate aplenty. UPDATE: on my 24" monitor at home in 1920x1200 mode Bitstream Vera Sans Mono looked very fuzzy until I enabled cleartype. That PC is running XP, maybe cleartype is on by default in Vista?
I have installed the RDT (Ruby Development Tools) eclipse plugin and I have found some very nice features:
- "Run as Ruby" or "Run as Test::Unit Test" options. I am creating Unit Tests in my new project and it is very easy to run the tests from inside eclipse. Eclipse includes a browser than displays the test results.
- RI documentation browser. A bit like fxri but it works a lot faster, although it raises an nasty looking error if it cannot find any search matches.
Since my Eclipse has both C development tools and Ruby development tools I am able to work nicely on both, which is useful since I had to write a ruby extension to handle serial communications. The extension is written in C++ but Eclipse is able to run a makefile to build it and then I can run Ruby Unit Tests to test the extension.
Eclipse has a wizard that is supposed to allow me to create new unit test files but it is totally confusing to use, always puts the file in the wrong directory and doesn't seem to give any huge advantages over simple 'New File' and 'Save As': it stills gives me the 'Run as Ruby' option.
SWIG and Ruby
I had tried using the ruby-serialport extension module for my serial comms but it was very painful to try building, requiring installation of Visual C++ version 6 (cygwin gpp wouldn't do) and Microsoft nmake rather than gnu make which in it's latest version doesn't work with extconf.rb: the makefiles it generates give syntax errors. Once I did get it to build it gave obscure gem errors when I tried to use it. It seems that it doesn't support the latest ruby libraries or something.
I decided to write my own simple ruby extension to handle rs232 so I went back to swig and this did it's usual great job of generating ugly boilerplate interface code for me. The biggest problem I found here was getting my module to generate ruby exceptions on errors but I solved that thusly. In my cpp code I put this:
1 void RaiseError( const char *strFormat, ...) 2 { 3 static char strErrorBuffer[255]; 4 va_list args; 5 6 va_start( args, strFormat); 7 vsprintf( strErrorBuffer, strFormat, args); 8 va_end( args); 9 10 throw strErrorBuffer; 11 }
This formats up an error message and throws a C++ exception. It doesn't support __FILE__ and __LINE__ information but my extension is very simple and doesn't need it. This function is called wherever in the extension I want to raise errors, e.g.
1 * 2 * Read a byte from a serial port. Returns either the integer value of the byte received or -1 3 * if no bytes are available. 4 */ 5 int ReadByte( int nPort) 6 { 7 int nData = 0; 8 ULONG nRxLength; 9 10 HANDLE hPort = (HANDLE)nPort; 11 12 if( ReadFile(hPort, // handle of file to read 13 &nData, // handle of file to read 14 1, // number of bytes to read 15 &nRxLength, // pointer to number of bytes read 16 NULL) == 0) // pointer to structure for data 17 { 18 RaiseError("Read Serial port failed: 0x%08x", GetLastError()); 19 } 20 21 if( nRxLength > 1) { 22 RaiseError("Read too many bytes?"); 23 } 24 25 if( nRxLength > 0) { 26 return nData; 27 } else { 28 return -1; 29 } 30 }
In the swig interface definition file I put this which wraps each interface function with an exception handler that will catch the C++ expection and raise a ruby exception from it:
1 %include exception.i 2 3 %exception { 4 try { 5 $action 6 } 7 catch (char *strErr) { 8 SWIG_exception( SWIG_RuntimeError, strErr); 9 } 10 }
These exceptions can be caught just beautifully in Ruby Unit Tests so I know my error handling is working:
# # Make sure an error is generated when attempting to read from a port that is not open. # def test_read_port_not_open oException = assert_raise RuntimeError do Rs232.ReadByte( 123) end assert_match( oException.message, 'Read Serial port failed: 0x00000006') end
Documentation Woes
In an ideal world I would be using either Doxygen or ruby's own RDoc to document my code. Both are designed to scan my source code and generate copious documentation for me. However, while Doxygen would do a great job with my C/C++ source it does yet handle Ruby. Conversely, RDoc does a great job on ruby source but it's support for C only extends as far as the C source for extension modules and this isn't working for my SWIG generated project. It seems as if the Rdoc C support has been written ONLY for C ruby extensions with little thought given to making it general purpose C documentation tool.
The ruby stuff I am writing will ultimately provide a programming API and the kind of documentation either of these tools would generate would be lovely. I don't really want to have to use two tools with different capabilities and output formats but it is looking like I will have to. Fortunately the C stuff should be pretty much embedded, the Ruby stuff is what other people must be able to use.

