Monday, October 12, 2009

TechMixer University 2009



October 13th, 2009: TechMixer University is a one-day conference in Birmingham AL. This year it had ~500 people attending. I gave the "Getting Started with Ruby" presentation to ~40 people. Almost everyone in the meeting had never seen Ruby before, so this presentation was perfect for them.

This presentation is an update from last year's presentation. The differences are: 1) shortened the Ruby language syntax details 2) Changed the Bonus Slides to "Ruby in Action" and added Cucumber, Sinatra, Rake to this section.

Thanks to all that attended. If anyone needs help getting started, please post questions to the Rubyham message board.

Wednesday, August 19, 2009

Free E-Book: O'Reilly C# 3 Pocket Reference

RedGate is running a marketing campaign where they are giving away O’Reilly’s C# 3 Pocket Reference. You can get it by following this link. The book is available by a download link at the bottom of the page. Kudos to RedGate, especially since you dont have to fill out any forms to get the book.

Thursday, July 16, 2009

IronRuby 0.6 and TofuHash

I took a quick look at IronRuby 0.6 which was release earlier this month. My first test of it was to run the TofuHash gem's unit tests.

Running in MRI (Matt's Ruby Interpreter) the result was:


Loaded suite test-tofuhash
Started
............................................................
Finished in 0.031 seconds.

60 tests, 220 assertions, 0 failures, 0 errors

.

Running in Iron Ruby the result was:


Loaded suite test-tofuhash
Started
...........................F.................F..............
Finished in 2.031315 seconds.

{stack traces for the failed cases removed to keep the output short}

60 tests, 220 assertions, 2 failures, 0 errors

.

The first thing to notice is the execution time difference 0.03 sec vs 2.03; which shows IronRuby still needs work on it's performance. These times are a good improvement over prior versions. Not show here is the start-up time. MRI was practically unnoticable, while IronRuby was noticable at ~5 seconds. The startup time is now fast enough to not be annoying.

The second noticable difference is that two tests failed under IronRuby.

The first was the #invert method. TofuHash doesn't have a custom implementation of #invert because in MRI's Hash #invert makes use of other methods in Hash. In IronRuby, it appears #invert has it's own implementation, so I'll have to give TofuHash a custom #invert to get that test to pass in IronRuby.

The second failed test was with YAML serialization and deserialization. I'll have to dig to find the root cause. Making a roundtrip from TofuHash to YAML and back, IronRuby resulted in a Hash object instead of a TofuHash. Just like the prior error, TofuHash doesn't have a custom implementation for #to_yaml, it just inherits it from Hash. I'm guessing there are differences between the implementations of Hash#to_yaml in MRI and IronRuby that work for Hash but dont work for the subclass TofuHash.

I'll probably wait until IronRuby 1.0 is released before updating TofuHash to correct these two errors. Until then, it appears TofuHash 1.0 will work in IronRuby 0.6 except for #invert and #to_yaml.

Wednesday, June 03, 2009

White - UI Testing Library (.Net)

White is an open source .Net library designed to support Unit Testing of Windows GUIs. I used it for the first time this week. The results were good enough to recommend using it again. The performance was a little slow, so I wouldn't want to have lots of tests. I prefer to avoid UI Unit Tests by separating the presentation from the logic. However, sometimes you need to unit test an interaction. For those cases, White can be useful.

I'm not going to blog an example here. The documentation for White has some examples. See Getting Started.

Wednesday, April 29, 2009

Using Cucumber Testing Framework without Rails

Most of the articles for Cucumber are given as Rails examples. While Cucumber was born for Rails testing, it isn't limited to that environment. A few simple steps will allow you to use Cucumber with any Ruby project.

This example will use Rake to run cucumber because the Cucumber::Rake::Task does a lot of work for you. It will automatically load (require) the features and steps for you.

First, you should follow Cucumber's pattern for directories:




{project home}/featuresstores all the .feature files
{project home}/features/step_definitionsstores the .rb files containing steps
{project home}/features/supportcontains the env.rb file


First create a rakefile for your project and add a Cucumber::Rake::Task as follows...



Next create the features file(s). The rake task will automatically require all the .feature files in the features directory. This example reproduces the additions.feature shown on Cucumber's homepage.



At this time, you may run "rake features" to see Cucumber runs. The results will show that 4 steps are undefined. To define the steps create features\step_definitions\addition_steps.rb. The rake task will automatically require all the step_definitions files.



This example uses a class Calculator from my project. So lets define that class under lib\calculator.rb.



This calculator isn't very exciting. It just uses a stack to remember values. The first item in the stack is the "screen". The add method will add the top two values. This is the bare minimum needed to meet the defined feature. (Normally you would define the class and fill in the details in a test-first fashion. But to keep this article short, I've posted the completed class.)

The rake features task doesn't automatically require the calculator.rb file. Also, if you noticed the addition_steps.rb makes use of rspec expectations, which isn't available by default. To require these files, create the features/support/env.rb file. The rake features task will automatically require any file under features/support



Now when you run "rake features" everything will work together. Your steps should all run and pass with green color!

Saturday, April 04, 2009

TofuHash is done!

I've released TofuHash v1.0 which supports the entire Hash interface for both Ruby 1.8.x and Ruby 1.9.1.

On Monday April 6, I'll be presenting a lightning talk on TofuHash to Rubyham. The talk will mostly cover the ruby 1.9.1 issues encountered.

Thursday, March 12, 2009

TofuHash is now a ruby gem.

I've released v0.1.0 as a ruby gem. The documentation is online at http://tofuhash.rubyforge.org/

To install it, simply use:

gem install tofuhash

Tuesday, February 03, 2009

wordle.net



I found wordle.net which can generate word clouds from text, blogs, etc. Just for fun, I created one from my blog.

Monday, December 08, 2008

tufuhash 0.0.1 available

TufuHash is posted on github. TofuHash is a case-insensitive hash plus string/symbol indifferent access version of Ruby's Hash. It is implemented as a subclass of Hash. The behavior is easily modifiable by creating a different TofuKey. So you could have it perform key lookups anyway you want!

The current release 0.0.1 hasn't been used in many places. So if you find defects, send them to me. I'll get it fixed asap. So far I've create a bunch of unit tests to verify TofuHash behavior. These unit tests include modified versions of Ruby's Hash unit tests, sourcecode examples from the ri documentation of Hash, plus some of my own tests.

So far I've avoided monkey patching Hash. So there is a known issue where Hash doesn't always know how to handle TofuHash. For example, you can't compare Hash to TofuHash(myHash == myTofuHash), but the reverse is possible (myTofuHash == myHash).

The easiest way to create and populate a TofuHash is to use Hash's [ ] syntax as shown here:

require 'tofuhash'
h = TofuHash[ :aSymbol => "symbol", "MixedCaseString" => "string", 11 => "number" ]
puts h["asymbol"] #=> "symbol"
puts h[:mixedCaseString] #=> "string"
puts h[11] #=> "number"

Labels: ,

color-block 0.2.0 released

Several weeks ago I made color-block available on github. This is a small library to colorize ruby output. Specifically I wanted to colorize my rake output. In some rake tasks, I didn't have access to the details of the task. So I couldn't add color to each string. Instead color-block allows me to colorize an entire block of code.

Several friends have tested color-block on Windows, Linux and Apple Mac.

require 'color-block'
include ColorBlock

color( :blue ) { "everything in this block is blue!" }

color( :white, :blue ) do
puts "now everything is white on blue!"
color( :green, :black ) { "nesting is supported" }
end

color( :white, :black, :bold ) { "third parameter to specify :bold or :dim" }

Labels: ,

Monday, August 18, 2008

TechMixer University 2008

Here is the presentation from TechMixer University 2008. The topic is "Getting Started With Ruby" which is designed to teach an introduction of Ruby. Along the way, we will see some interesting Ruby features: dynamic programming, mixins, dependency injection (e.g. how Ruby doesn't require a DI framework). The slide set contains a couple of bonus slides covering Databases, Builder, Hpricot, RSS::Maker.



or view it here on Google Docs

Labels:

Wednesday, July 23, 2008

Rake Quick Reference

I've created a Rake Quick Reference available on pastie.org.

Update : 7/28/2008 paste #242691 - reworked task generation section; added command-line tip
Update : 7/24/2008 paste #240284 - added details on namespace.
Release: 7/23/2008 paste #239387 - original release.

Wednesday, July 16, 2008

Hudson (build and continuous integration tool)

If you haven't seen Hudson (https://hudson.dev.java.net/), you should give it a look. I was introduced to it by Clay McCoy at Rubyham. After playing with it, I decided to switch from CruiseControl.Net to Hudson. The switch didn't take long. In all, I spent < 3 hours total to make the swtich (most was learning time). The setup was fast (~10min). Conversion from CC.Net wasn't hard. I'm very happy with the features of Hudson and it's plugins.

Monday, June 16, 2008

How to call Rake from CruiseControl.Net

CruiseControl.Net is a great Continuous Integration tool. It is easier to setup than CruiseControl (java). Plus it makes more sense to use CC.Net if you work at a .Net shop.

To script the Continuous Integration process, I first investigated using MSBuild. At this time, I found MSBuild to work well for building Visual Studio projects. But MSBuild wasn't mature enough to accomplish much else. NAnt is a more mature alternative to MSBuild, which I've used on some projects. NAnt is fairly powerful (even better in my opinion than the original Ant). However, there is one problem with both these tools: XML is not a programming language.

Rake is a programming language. Rake is actually Ruby, with some additional stuff to give it the powers of Make. Rake also makes sense in a .Net shop because 1) Ruby can call .Net objects using the Ruby/.Net Bridge. 2) John Lam is currently porting Ruby to run directly on the .Net DLR.

So how do you get CruiseControl.Net to call Rake? The best solution would be to create a CC.Net plugin to call Rake. But if your like me, time is limited. So an easy kludge will suffice. The kludge is this: 1) CC.Net calls either MSBuild or NAnt, which is already built in. 2) MSBuild or NAnt executes Rake via an Exec task.

(You may be wondering why not use CC.Net exec task. The short answer, I couldn't get CC.Net exec task to call Rake. I'm not sure why. It just didn't work well.)

First - CC.Net calls MSBuild or NAnt. This is very simple. In the CC.Net config file you add a task...

   <tasks>
<nant buildFile="nant.xml" />
</tasks>



or

   <tasks>
<msbuild projectFile="msbuild.xml" />
</tasks>


Then you have NAnt or MSBuild call Rake. Here are the nant.xml and msbuild.xml files:

<?xml version="1.0"?>
<project name="Rake Runner" default="RakeBuild" basedir=".">
<target name="RakeBuild">
<exec program="c:\ruby\bin\rake.bat" />
</target>
</project>



<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="RakeBuild">
<Target Name="RakeBuild">
<Exec Command="rake" />
</Target>
</Project>



Notice that each just calls the RakeBuild target, which is the default target.

Rake will then run the default target (you could specify a Rake task in the scripts above). Here is an example Rake script which displays all the environment variables:


task :default => [:test]

task :test do
ENV.each {|k,v| puts "#{k}=#{v}" }
end



CC.Net captures the output a little different for MSBuild vs NAnt. MSBuild's output is append to the end of the build log. Which results in a long build log. NAnt's output is captured to a different page "NAnt Output". However, NAnt prepends each line with "[exec]".

Sunday, May 11, 2008

Twitter fun

Last Friday I attend the IPSA meeting on Social Media. That got me interested in two products: Twitter and ooVoo.

I've now got a Twitter account using the nickname neversleep360. For which I got curious about the reach of Twitter. So I wrote a quick ruby script to search out Friends and Friends of Friends, then score everything they were following based on the number of Friends/FriendsX2 following. This should point out nicks of common interest. Also, I found several interesting nicks sitting out in the wings.

I've posted everything on my wiki at Twitter Friends of Friends. One interesting result is the number of links to BarackObama. Personally I'm not a fan of BarackObama; but it is interesting to see him score highly among this circle of friends on Twitter.

Labels: ,

Wednesday, April 23, 2008

Ten Free Must-Have Security Tools

eWeek published this list of useful security tools. have fun!

Tuesday, February 19, 2008

Unexpected Hash Behavior With String Keys

I was looking for a way to create a case-insensitive Hash class. One suggestion was to use NormalizedHash (http://pastie.caboo.se/154304), and override methods on the String keys. This doesn't work as expected.

I found that Hash makes a duplicate of the String key. This unfortunately removes any methods added in the singleton class. (surprise!)

Here is the code to demonstrate this behavior: http://pastie.caboo.se/154595

----

Shortly after writing the above post, I came across a little footnote in Hash#[]= which says... "(a String passed as a key will be duplicated and frozen)"

I learn something new every day. (I wish this information was given in the class description instead of the method description where it is easly missed.)

Wednesday, December 12, 2007

How to redefine or mock a class method in Ruby

Monday, November 26, 2007

link: Introduction to Abject-Oriented Programming

Monday, September 17, 2007

My SQL Server 2005 is Slow

Testing code that queries SQL Server 2005, I kept observing long delays. Sometimes my tests would execute in less than one second, which was expected. Frequently, they would take 30 to 120 seconds!

A little digging into the SQL Server, I found the two top waits were SQLTRACE_BUFFER_FLUSH and RESOURCE_SEMAPHORE, both of which would grow in correlation to delays I observed when running my unit tests.

A little reading found: this forum topic and this kb article. The former being the most useful. It turns out SQL 2005 will run a trace by default; to assist in fixing problems later. (read "default trace enabled" in SQL Books Online) Unfortunately on my development box, it appears the trace is the source of my delays. So my solution is to turn off the default trace using:

exec sp_configure 'show advanced options',1
reconfigure
exec sp_configure 'default trace enabled',0
reconfigure


After this, my tests always ran in less than one second!

Wednesday, August 08, 2007

fun with ruby meta-programming

Wednesday, August 01, 2007

IronRuby alpha

John Lam has posted a nice article about the current work on IronRuby. My development team has already started using Ruby to write unit tests. We are currently using CRuby but plan to port to IronRuby once it is released. Our product is written on .Net so IronRuby will fit our project very well.

Diff tools

SourceGear just released an update to their free DiffMerge program. This product caught my eye because it has a 3-way merge. My current favorit Diff tool is Beyond Compare 2 from Scooter Software ($30). It has more features than DiffMerge, but doesn't include the 3-way merge which I sometimes need. The best merge tool I've ever used is Araxis Merge, but it costs $269 for the pro edition, I can't justify the extra cost vs the $30 Beyond Compare 2. Araxis Merge's price tag was worth it when I was working with an offshore team. I had to 3-way merge code from the US and India across many files and directories. It would have been too expensive in time if I didn't use Araxis Merge for that task.

Thursday, July 05, 2007

IIS Authentication and Access Diagnostics Tool

I just got through configuring SQL Server 2005 for a Scale-Out Deployment. One problem I ran into was the NTML "Dual Hop" issue. Fortunately I found the IIS Authentication and Access Diagnostics Tool which helped quickly identify the issue. This tool hasn't been mentioned much, so I am recommending it.

Now I've got a happy system with Report Server running separately from Reporting Services Database. Everything is working great: Reports and Report Builder. I've seen other sites which said this configuration would not work. I managed to get it working using Integrated Authentication and Kerberos.

Enjoy!

Monday, May 21, 2007

Ruby Require Idiom

Ruby's "require" command can accidentally load the same file twice.

The following example shows this problem (2 files)...

#----------
# file: problem.rb
puts "#{__FILE__} loaded"

#----------
# file: run_me.rb
require '././problem' #=> .\problem.rb loaded
require 'problem' #=> ./problem.rb loaded



When run_me requires problem.rb using slightly different paths, Kernel#require loads it twice. This happens because Kernel#require tracks the files it has loaded in the $" array. It only does a String compare, so if the file names differ it doesn't find the match.

There are several ways to avoid loading the same file twice. The first technique is to call require using the absolute path of the file. Since every file only has one absolute path, Kernal#require will not get confused. To get the absolute path, we can use File.expand_path as shown in the following example.
#----------
# file: ok.rb
puts "#{__FILE__} loaded"

#----------
# file: run_me.rb
require File.expand_path('././ok') #=> C:/ruby/require/expand_path/ok.rb loaded
require File.expand_path('ok') #=>



Another effective technique is using indirection. That is, require a file that requires other files. This technique works really well for loading libraries and gems. The first file may get loaded multiple times because of arguments to Kernel#require. But once inside this file, all calls to Kernel#require are the same. So the sub-files are not loaded multiple times. The following example illustrates this solution.

#----------
# file: run_me.rb
require 'base' #=> ./required_by_base.rb loaded
require '././base'

#----------
# file: base.rb
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

require 'required_by_base'

#----------
# file: required_by_base.rb
puts "#{__FILE__} loaded"



See how "base.rb" is required twice using different file paths. Kernel#require actually loaded "base.rb" twice. But "base.rb" didn't do anything except call Kernel#require to load other files. Since the parameter 'required_by_base' was the same in both calls, "required_by_base.rb" was only loaded once.

The first two lines of "base.rb" add the current directory to the search path. This wasn't really necessary for this example since the "required_by_base.rb" file is in the same directory. However, if the require used a relative path to another directory, it would have failed. By adding the current directory to the front of the search path this ensures the correct files are loaded.

If you look closely, you will see that the File.expand_path is used to put the absolute path into the search path. This avoids adding the same path twice.

Wednesday, May 02, 2007

DLR is here! Ruby soon to follow!

IronPython (2.0 Alpha) is now available with the Dynamic Language Runtime (DLR).

Microsoft also announced support for JScript on the DLR. They say releases of Ruby and VB will soon follow. (source: Jim Hugunin's Thinking Dynamic: A Dynamic Language Runtime)

This is great news to me.

Wednesday, April 25, 2007

Microsoft to support dynamic languages?

ZDNet published news that Microsoft will publish a "Dynammic Language Runtime" (DLR) to provide support for dynamic languages like Ruby to run on the .Net CLR.&nbsp; This is great news to me.&nbsp; I've tried many dynamic languages for .Net, but haven't found anything I could use in production.&nbsp; IronPython is the best I've found.&nbsp; But you can't fully integrate it into existing C# projects.&nbsp; IronPython can use C# classes, but C# can't use IronPython classes.&nbsp; I cant wait until the day I can run Ruby on .Net, with full integration to non-dynamic language projects.

Wednesday, April 18, 2007

RSpec

I been using RSpec for about 1 week now. I must say I really love it. Anyone who has worked with me knows I'm a test-first style developer. Now I switched to a spec-first developer!

RSpec is a ruby library for Behavior Driven Development (BDD). It accomplishes the same purpose as Unit Testing, automated tests for development. The big difference is BDD changes the way you think about tests.

With BDD, you begin by defining a "context" which is a situation or state of the system under test. For example, for a Stack object one context would be an "empty stack".

Next, you define the "specifications" for the "context". BDD uses language such as "should be", "should not" to describe the specification. In the "empty stack" context, the specification might include "should be empty", and "pop should throw exception". Within the specification we add the test code to check that the specification is followed. Here is the ruby code for this example:

context "A new stack" do

setup do
@stack = Stack.new
end

specify "should be empty" do
@stack.should be_empty
end

specify "pop must throw exception" do
lambda { @stack.pop }.should raise_error
end
end


Notice how easy it is to read the code above. This is what I like about RSpec verses xUnit. The contexts and specifications provide guidance about how to orginize your tests.

RSpec does not stop there. RSpec also includes RCov so you can easily see a report of test coverage. This is very handy to find holes in your specifications and tests. RSpec includes a mock object framework to help isolate the system under test. You can also use the mock objects to test the object interation of the system under test. RSpec does support Rails development.

Anyone interested in learning Behavior Driven Development or RSpec, I highly recommend working through the RSpec tutorial. The tutorial really provides a great exercise in BDD. I had read about BDD, but it wasn't until I completed the tutorial that I internalized it. (If you need Ruby, you can download it from ruby-lang.org, I use the Windows One-Click Install. Then type "gem install rspec" on the command-line to get rspec. Very quick and easy!)

Wednesday, February 07, 2007

Rubyham

Our local user group holds it's First Code Day!

Sunday, January 07, 2007

XBox 360

I joined the ranks of XBox 360 players this holiday season. My gamer profile link is NeverSleep360. I've also put my gamer card on the side bar. Game On!

Friday, January 05, 2007

I'm on Google EngEDU!

Jack Herrington in his presentation Code Generation With Ruby (Google Video), a comment references Dave Thomas's Blog post Rails and the Legacy World which talks about my post Let ActiveRecord support Enterprise Databases! The reference is part of the after presentation discussion at about 35 min in the video. One of the developers talks about the technique I used to modify ActiveRecord to support Sql Server, and references my blog post. Wow! I only thought a couple of my friends read this blog.

Mr. Herrington's presentation provides a good overview of Code Generation, different options, and notes about when it is appropriate or not. He then shows some implementations of Code Generation using Ruby and ERb. The discussion after the presentation is very interesting. They talk about different experiences with Code Generation and Active Record.

A couple of months ago I did some SQL code generation in Ruby. I should create a post about it soon.

Friday, December 22, 2006

Wii Browser

Nintendo released a demo of their browser for the Wii. It seems to work pretty well for checking the weather, email, google. I tried a few of the kids sites like NickJr, but it only played some of the flash content. The videos didn't work since they were windows media. Since I can now check Weather.com using the browser, I doubt I would use their Forcast Channel.

If you have a Wii, try WiiCade which has some good games optimized for the Wii. There are also some wii flash games at Albino Black Sheep Wii Games; but I havent tried them so I cant comment on the quality of the games at Albino. WiiCade had certainly done a good job making a Wii optimized page, and providing good games.


Enjoy!

Friday, September 29, 2006

RSS feeds from Ruby

A friend asked me if I knew a good way to create RSS feeds. He want RSS feeds created for some web sites that didn't already have them. My favorit answer: Ruby.

So I created a demo script in Ruby that parses Fatwallet.com and creates an RSS feed for topics that are rated "Better" or higher. The hardest part of this problem was parsing the HTML, but Ruby made that pretty easy. Creating the RSS information was very simple.

The code below has plenty of comments because my friend doesn't know Ruby. His background is more .Net, Java, and Perl.

#  This is a simple example.  It reads the Hot Topics forum
# on Fatwallet.com finding all topics rated "Better" or higher.
# It will print these topics and their URL as it finds them.
# Finally, it prints the RSS feed for this information.
# See: http://www.fatwallet.com/c/18/
#
# Three steps to run this script...
#
# You can get Ruby from http://www.ruby-lang.org/en/downloads/
# I highly recommend the One-click Installer for Windows
#
# This program uses an extra library, Hpricot, to parse HTML.
# To get Hpricot installed, use Ruby's package manager "Gems"
# Just run the follow at your DOS cmd prompt
# gem install hpricot
#
# To run the program from the DOS cmd prompt...
# ruby RubyBot-forRich.rb
#
# RSS feed creation using the RSS library for Ruby
# see: http://www.ruby-doc.org/stdlib/libdoc/rss/rdoc/index.html
# tutorial: http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en

# "require" is not like "using" in C# nor "#include" in C++.
# require searches the library for the correct ruby file and executes it.
require 'rubygems'
require 'open-uri'
require 'rss/maker'
begin
require 'hpricot'
rescue LoadError # this is like a Try Catch, but there are nifty differences
puts 'Please run "gem install hpricot" before running this program.'
exit
end

BETTER = 4 # a constant

doc = Hpricot(open('http://www.fatwallet.com/c/18/'))

rss = RSS::Maker.make("1.0") { |maker|
#
# Let me explain what is happening...
# The ".make" method created a Maker object, passed it into
# the block (i.e. everything between { and }) as the variable 'maker'.
# Executed the block. Then ".make" returns the RSS object that
# was built while executing the block.
#
maker.channel.about = 'http://www.fatwallet.com/c/18/'
maker.channel.title = 'Fatwallet.com Hot Deals Forum'
maker.channel.description = 'Hot deals rated "Better" or higher.'
maker.channel.link = 'http://www.fatwallet.com/c/18/'

puts 'Searching...' # puts is similar to WriteLine in .Net

(doc/'tr').each { | tr |
#
# (doc/'tr') => performed an XPath search on doc and got a collection of <tr> nodes
# .each => iterates over the collection passing elements one at a time to the "{ |tr| ... }" block
# { | tr | ... } => this is a Closure, the variable 'tr' gets set to the element passed in
#
# similar to C#...
# foreach( Node tr in doc.FindAllNodes( 'tr' ) ) { ... }
# but not really since it is using a closure.
#
# I had to loop on <TR> html tags because I will need to reference this tag later.
#
(tr/'td/img[@title]').each { |img|
if img['title'] =~ /rating: (\d+)/
# $1 is the first group from the match, the rating number
if $1.to_i >= BETTER
(tr/'a[@href]').each { | a |
if a['href'] =~ /^\/t\/18/
puts "http://fatwallet.com#{a['href']} #{a.inner_html}"

item = maker.items.new_item
item.link = "http://fatwallet.com#{a['href']}"
item.title = a.inner_html

end
} # each a
end # if rating >= better
end # if title is rating
} # each img
} # each tr
} # RSS maker

puts "\nRSS..."
puts rss

Long time no post... why?

Two months and nothing posted. The reason is my wife is pregnant with our third child. Just like the first two, the pregnancy is very difficult. So I haven't done much blogging nor extra coding.