Tuesday, October 28, 2008

CodeWeaver CrossOver giveaway

I downloaded my free copy of CodeWeaver's CrossOver that is free for today only. You have just a few more hours to download yours. I'm waiting for my free license key. The website got slammed today, so they say it may take a few days to fulfill. I'm curious to see how running Windows applications on a Mac works. I had heard of Wine, but I was not interested enough in setting it up. But it appears CodeWeaver makes it easier for you. Here is the original story.

Monday, October 27, 2008

Book Review: Ruby Cookbook



This is the first book review that I've done where I haven't read the complete book. But to be fair, this book is actually a reference, and, coming in at almost 900 pages, Ruby Cookbook, by Lucas Carlson and Leonard Richardson, is a fine reference that I'll be sure to keep near.

Like any good cookbook, this book is composed of recipes. And the recipe collection is very comprehensive, starting from simple examples involving strings, arrays, hashes, etc. to higher level concepts like classes, objects and meta-programming. The authors touch upon such useful topics as testing and packaging your Ruby code for distribution. All recipes start out with a problem, a solution, and then a discussion that expands a bit on the topic. And each chapter has a little introduction to that area as well, so it's worth to read the beginning of a chapter before diving into a recipe.

I've actually used quite a few of these, and read some others just for interest and learning. For anyone serious about learning Ruby or perfecting their skills, I highly recommend keeping this book close at hand. I give this book a 10 out of 10.

Friday, October 24, 2008

Converting a space delimited file to a CSV file

Here is a little quick conversion script I wrote today. I needed to import data from another utility into OpenOffice's Calc. But the output from this other utility was not tab separated like I thought it was. It had a variable number of spaces between each field. So, here is my handy conversion:



You invoke the script like this:

ruby convert_to_csv.rb infile > outfile

So, we take the command line argument infile, open it, and then iterate through each line. In each line, we use the gsub command to substitute a comma for any whitespace (tab, space, newline, etc.). The chop method is used because after running the line through the gsub command, the newline is converted to a comma. We want to change that back to a newline, so, therefore, we chop it off, and then append our newline.

Friday, October 17, 2008

Curious end-of-line conversion behavior between DOS and Cygwin

I'm working on a Ruby script that generates shell scripts and batch files. This is similar to the work using ERB like I posted about earlier. Since my desktop is Windows, and the shell script will be run on Linux, I need to worry about end of line characters. Specifically, I need to convert \r\n to \n. I thought this would be straightforward enough to write in Ruby: just use the gsub command, right?



Well, after running my script, I ran od -c to check my results. Unfortunately, it doesn't work when you run the script in DOS. So, since I have Cygwin installed, I changed my script to:



Checking my results, I see that this worked correctly when running in DOS. Then, I checked my results when running the first script in a Cygwin shell, and that worked correctly too.

So, this behavior all seems a little strange to me, but now I know.

Thursday, October 9, 2008

Some thoughts on designing a test framework with Ruby

Here are some of my thoughts after actively working on a test framework in Ruby and scripting and running test scripts for the last couple of months.

Start writing tests first, and then grow your framework. I tried to design a framework before I had a solid idea of what the testing needs were. I had just joined the company, and didn't really understand the use cases and test procedures very well. So, I just made assumptions of what I thought would be good common code and what should be in a "good" test framework. These assumptions came from other test frameworks I had used or designed in the past. I felt like my experience would make up for my lack of product knowledge. In a lot of cases that was true, but I could have delved more into the testing side, instead of just the framework. Sometimes to test something, you just need a very simple script, and a sophisticated framework can just get in the way.

Don't overdesign features before you really need them. For example, I'm thinking of ripping out the logging stuff I implemented, because now it is annoying me. I had designed the test framework so that when you include the test harness class in the test class, a log will be made for any test run. Well, I found out I wasn't really reading the logs too much, I was just relying on the output from Ruby's Test::Unit class. And I hadn't implemented a cleanup mechanism to clear the logs after a certain age was reached. So, I'm constantly typing "rm -f *.log". I think it is wiser to not force the logging in a test class, and have the test developer decide what logging is necessary and the mechanism to do that.

The DRY (Don't Repeat Yourself) concept is great, but don't get too fancy, though, with code reuse and that magical metaprogramming (if you are using a dynamic language like Ruby, as I am). It probably doesn't matter much when you need to quickly crank out tests, since this is just testware, not shippable code. In most cases, I think repeating yourself a couple of times is okay, especially when you are trying to automate as much of your tests by the end of a sprint. But once you get to the magical number of 3, then you should think about your modularity and move your repeated code to a common library.

Don't get hung up about trying to implement tests in only one language. This is probably a good reason to not spend too much time working on a framework, because, you might need a different language or tool to perform a subset of your tests. For example, there are some things that Java is better at than Ruby and vice versa. When it comes to manipulating large amounts of XML, performance-wise, Java would be my choice over Ruby.

Tuesday, October 7, 2008

Using Ruby and ERB to dynamically create XML files from templates

Here is a simple way to dynamically create XML files from templates. Actually, it could be any type of file. I chose XML format, because I work with plenty of XML at work. And I use this technique in a test setup.

For our example template, here is a very basic XML file, called ERB_example.xml.

<email>
<to><%= $name %></to>
<from><%= $me %></from>
<date><%= Time.now %></date>
<subject><%= $hello %></subject>
On your way home, please pick up the following from the store:
% $list.each do |thing|
* <%= thing %>
% end
<%= $signoff %>
</email>


As you can see, it has the basic elements of an email message, I have tags surrounded by <%= and %>. Anything inside these tags are treated like a Ruby expression and are evaluated. I also have two occurrences of just %. These are treated as the other tags if they are at the start of the line. (Note that I did not indent those lines!) This is useful for us because we cannot nest the <%= and %> tags. (Try it!)

Just to make things easier for this example, I am using global variables for most of these tokens. I also have an expression Time.now which will substitute the date and time. Now to our Ruby script, ERB_example.rb.

require 'rubygems'
require 'erb'

# set up some variables that we want to replace in the template
$hello = "Hola"
$me = "Tu mama"
$name = "Mi'jito"
$list = [ "milk", "eggs", "bread"]
$signoff = "Te quiero mucho."

# method update_tokens takes template_file, expecting globals
# to be set, and will return an updated string with tokens replaced.
# you can either save to a new file, or output to the user some
# other way.
def update_tokens(template_file)
template = ""
open(template_file) {|f|
template = f.to_a.join
}
updated = ERB.new(template, 0, "%<>").result

return updated
end

new_xml=update_tokens(Dir.getwd+"/ERB_example.xml")
puts new_xml


Note that in our third argument to ERB.new, we are telling ERB two things. First, the % says to process any % at the beginning of a line. Second, the <> says to omit any newline for lines beginning with <% and ending with %>.

So, our final output when we run this little script is as follows:

<email>
<to>Mi'jito</to>
<from>Tu mama</from>
<date>Tue Oct 07 14:22:10 -0500 2008</date>
<subject>Hola</subject>
On your way home, please pick up the following from the store:
* milk
* eggs
* bread
Te quiero mucho.
</email>


You can find out more about ERB at the Ruby Standard Library Documentation.

Monday, October 6, 2008

How to compile and install Ruby on RHEL 4

This is one of those posts where I'm mostly writing this so I can remember how to do it in the future. But maybe it will help someone else, too. I'm not a Unix sysadmin, by any means, but here is what I did to get, compile, and install Ruby on a RHEL 4 system at work. I realized later that I could have found and installed an RPM, but after I started down this path, I wanted to finish it.

First of all, this may seem backwards, but I set these environment variables first. This is because I messed up the first time I tried to install Ruby, so these were left hanging around.

export RUBYLIB=/opt/ruby/lib:/usr/lib/site_ruby
export PATH=$PATH:/opt/ruby:/opt/ruby/bin

Next I downloaded the Ruby source code:

wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.6.tar.gz

I unarchived it:

tar -zxvf ruby-1.8.6.tar.gz

I made a symbolic link which will match the paths in the RUBYLIB and PATH environment variables I set up previously. Also, it's just a lot easier to type /opt/ruby instead of /opt/ruby-1.8.6-p287:

ln -s ruby-1.8.6-p287 ruby

Now, we build and install:

cd ruby
./configure
make
make install

I next installed RubyGems. First we download the archive and unpack:

wget http://rubyforge.org/frs/download.php/43985/rubygems-1.3.0.tgz
tar -zxvf rubygems-1.3.0.tgz

Then we run the setup:

cd rubygems-1.3.0
ruby setup.rb

And that is it!

Wednesday, October 1, 2008

How to print to PDF on Windows for free


One of the nice things that Mac OS X has out of the box is support for PDF. You can easily print to PDF without any other software. Unfortunately, with Windows, that is not the case. There are commercial products available that allow you to print to PDF. But there is another way, a free way to do it. I set this up on my computer at work using the following tutorial: Creating a free PDFWriter using Ghostscript. The only thing that I did differently was to download and use HP's Universal Print Driver.