Something new

Posted by teem on April 13, 2008

I’ve created a new blog using Django. I originally started implementing that blog app with Merb but changed my mind with the release of Google App Engine.

I wouldn’t use this blog much after I finish the features I want to implement in that new the blog app. Total control at last. He he!

Google App Engine Preview Release

Posted by teem on April 08, 2008

This is so cool! Google app engine “allows you to build an application that runs reliably, even under heavy load and with large amounts of data.” And the apps are all in Python! Yipee!!

Unfortunately, I wasn’t able to get an account as the preview release is limited to 10,000 users. Can’t wait to try this out.

Checking Out DataMapper

Posted by teem on March 27, 2008

I’ve been itching to learn Merb and DataMapper for so long since this two kinda rocked the Ruby world but I just didn’t have enough motivation to really dive in. But with Merb nearing the v1.0 release (v0.9.2 at the time of this writing), I guess it’s about time.

To start-off my journey in the world of Merb, I decided to try DataMapper. Merb is ORM agnostic so I can use ActiveRecord, but DataMapper is also worth learning and using, primarily because I love learning and because its faster than AR, allows lesser SQL coding, and it’s familiar. It also reminds me of the Django ORM.

Since it’s the first time that I’ll be doing DataMapper stuff, I was not sure where or how to start. I headed to the DataMapper site and after a little bit of reading and coding, I thought of creating a very simple Ruby program that uses DataMapper.

I decided to model a family tree. A family tree is a collection of persons with relationships ordered like a tree. Parents have children, persons have siblings or cousins, etc. I chose this because it tackles two basic topics: attributes/properties and associations.

Adding Properties

Being the BDD fan that I am, I start projects with the creation of RSpec examples. The examples themselves are the code that test some features of DataMapper.

The following set of specs describes some attributes of the Person object. It’s kept simple to focus on the two attributes of the Person class: name and date of birth.

teem_attributes = { :name => "Teem",
                    :date_of_birth => Date.civil(1974, 1, 1)}

describe Person do

  before(:each) do
    @person = Person.new(teem_attributes)
  end

  it "should be valid" do
    @person.should be_valid
  end

  it "should have a name" do
    @person.name = nil
    @person.should_not be_valid
  end

  it "should have been born on some date" do
    @person.date_of_birth = nil
    @person.should_not be_valid
  end

end

Now, to the code.

Connecting to the Database

To setup the database for the whole application

DataMapper::Database.setup({
  :adapter => "sqlite3",
  :database => "family.sqlite3"
})
Creating the Person class

And the Person object is simply this:

class Person < DataMapper::Base
  property :name, :string, :nullable => false
  property :date_of_birth, :date, :nullable => false
end
Accessing Properties Within the Person Class

I wanted to know how to access the attributes within the class so I added a method #age.

describe Person, "#age" do

  before(:each) do
    @person = Person.new(teem_attributes)
  end

  it "returns the number of years since the date of birth" do
    @person.age(Date.civil(2008, 3, 1)).should == 34
  end

end

I opened up the class Person and added #age. Attributes of an DataMapper object are simply instance variables.

class Person

  def age(date=Date.today)
    y = ((date.year - @date_of_birth.year)).to_i
    y -= 1 if (date.month < @date_of_birth.month) || (date.month == @date_of_birth.month && date.day < @date_of_birth.day)
    y
  end

end
Finding Persons
describe Person, ".first tries to find a person" do

  describe "who is in the database" do

    before(:all) do
      Person.create(teem_attributes)
    end

    it "should be found using the name condition" do
      teem = Person.first :name => "Teem"
      teem.name.should == "Teem"
    end

    it "can use LIKE in finding" do
      eem = Person.first :name.like => "%eem"
      eem.name.should == "Teem"
    end

  end

  describe "who is not in the database" do

    it "should return nil" do
      Person.first(:name => "Juan").should be_nil
    end

  end

end

The first method finds the first object that satisfies the conditions. What’s cool about finding stuff in DataMapper is it really is possible to not code SQL. :name.like is sweet, pretty much like Django’s field lookups.

This is fun! So I tried gt and lt on date_of_birth attribute.

# Let's try gt and lt on dates!

describe Person, ".all to find all persons born before, after, or on a specific date" do

  # at this point, teem person is already in the database

  before(:all) do
    @teem = Person.first :name => "Teem"
  end

  it "should return an array that does not include teem when looking for persons born before Jan 1, 1972" do
    d = Date.civil(1972, 1, 1)
    Person.all(:date_of_birth.lt => d).should_not include(@teem)
  end

  it "should return an array that includes Teem when finding persons born after Jan 1, 1972" do
    d = Date.civil(1972, 1, 1)
    Person.all(:date_of_birth.gt => d).should include(@teem)
  end

  it "should return an array that includes Teem when finding persons born on Jan 1, 1974" do
    d = Date.civil(1974, 1, 1)
    Person.all(:date_of_birth => d).should include(@teem)
  end

end

Is not this cool?

Okay. This post is long enough. Too long, in fact. I’ll checkout DataMapper associations next time.

Hitting a wall in RSpec User Stories Integration Testing

Posted by teem on March 22, 2008

Hit a wall today.

I had just finished a bunch of RSpec tests and the implementation. All green.

I went back to an RSpec user story to checkout if everything integrated well.

Nope.

A scenario wherein a user tries to access a non-existing resource failed.

The steps involved looked like this:

When "the user requests for the non-existing book" do
  get "/books/1/"
end

Then "the browser should get a 404" do
  status.should == 404
end

The result of the test? I get the status of 500 instead of the expected 404. (The response object seems to be unset when the exception was raised.)

This shouldn’t happen. RecordNotFound exceptions in Rails are handled by default with a 404 by the ActionController::Rescue module.

So I went on to test it using the IntegrationTest.

class BooksAccessTest < ActionController::IntegrationTest
  def test_book_non_existent
    get "/books/1/"
    assert_equal 404, status
  end
end

The test passes.

So, where does this leave me? I’m not sure how RSpec handles exceptions in the integration code, but the test based on the Rails built-in integration test passes.

One thing I realized about the difficulty of writing tests, especially if you’re new, is that when something goes wrong, it’s much harder to spot the source of the bug: it could be your test, or your implementation, or the tool you’re using.

I’ll try to replicate this to see if this behavior is consistent.

Update

I’ve replicated the problem I encountered as described in the previous post.

To keep it simple, I made an index method that does nothing but raise a RecordNotFound exception.

# The controller
class TasksController < ApplicationController
  def index
    raise ActiveRecord::RecordNotFound
  end
end

Okay. Now for the integration tests.

# IntegrationTest
class TaskControllerIntegrationTest < ActionController::IntegrationTest
  def test_index
    get "/tasks/"
    assert_equal 404, status
  end
end

The test passes.

$ rake test:integration
(in /Users/Tim/sandbox/intest)
/opt/local/bin/ruby -Ilib:test "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb" "test/integration/task_controller_integration_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader
Started
.
Finished in 0.168068 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Now, for the RSpec test.

# The plain text story
Story: User views a task

As a user
I want to view the details of a task
So that I can perform it well

  Scenario: I view a non-existent task by typing a random task number as a url
    Given there are no tasks
    When I try to view a task
    Then I should get a 404

# RSpec steps
steps_for(:tasks) do
  Given "there are no tasks" do
  end

  When "I try to view a task" do
    get "/tasks/1"
  end

  Then "I should get a 404" do
    status.should == 404
  end
end

The test fails.

    ...
    When I try to view a task
    Then I should get a 404 (FAILED)

1 scenarios: 0 succeeded, 1 failed, 0 pending

FAILURES:
    1) User views a task (I view a non-existent task by typing a random task number as a url) FAILED
    Spec::Expectations::ExpectationNotMetError: expected: 404,
     got: 500 (using ==)
    stories/tasks_story.rb:12:in `I should get a 404'
stories/tasks_story.rb:16

Getting the list of Ruby Gems clean

Posted by teem on March 18, 2008

Using gem list, you can get the list of gems installed in your box. Each line contains the gem name and the versions installed. But sometimes, I only want the list of gems and not their versions. I find this useful when I want to install a bunch of gems in a box with freshly installed OS. Here’s a command/script that filters out the version numbers.

gem list | ruby -e "puts STDIN.readlines.select {|e| /^\w/ =~ e}.map {|e| e.split(\" \").first}"

It pipes to the gem list result to an inline ruby script.

Another way is to use the Kernel method ` ` instead of getting it from the pipe.

ruby -e "puts (\`gem list\`).split(\"\n\").select {|e| /^\w/ =~ e}.map {|e| e.split(\" \").first}"

Wah! Too much ruby and no shell scripting goodness? I miss ‘em, too.

gem list | awk '/^[^\*\s]/ { print $1; }'

RSpec tmbundle errors 6

Posted by teem on March 18, 2008

Update:
David Chelimsky posted some time ago that RSpec has moved to github. There’s an RSpec TextMate bundle there, though I haven’t updated yet. You might want to try that first.

Update 2:
Here’s the patch.

After reinstalling TextMate and some bundles, I got the following error when I tried to run a spec file using the RSpec tmbundle(rev. 9148):

/Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/text_mate_formatter.rb:5: uninitialized constant Spec::Runner::Formatter::HtmlFormatter (NameError) from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:14 from /tmp/temp_textmate.0e1ExF:3:in `require' from /tmp/temp_textmate.0e1ExF:3

Hmm.. HtmlFormatter cannot be resolved. So I opened up the RSpec tmbundle directory with my favorite editor and found the culprit. html_formatter.rb isn’t loaded so I required it in text_mate_formatter.rb.

Index: Support/lib/text_mate_formatter.rb
===================================================================
--- Support/lib/text_mate_formatter.rb  (revision 9148)
+++ Support/lib/text_mate_formatter.rb  (working copy)
@@ -1,3 +1,5 @@
+require 'spec/runner/formatter/html_formatter'
+
 module Spec
   module Runner
     module Formatter

I reloaded the bundles. Click, click. Opened the spec examples file. Command+R. Error!

/Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:47:in `run': wrong number of arguments (5 for 1) (ArgumentError) from /Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:47:in `run' from /Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:46:in `chdir' from /Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:46:in `run' from /Users/Tim/Library/Application Support/TextMate/Bundles/RSpec.tmbundle/Support/lib/spec_mate.rb:25:in `run_file' from /tmp/temp_textmate.FXAXRH:4

Hmm… Wrong number of arguments in spec_mate.rb. Hmm.. Must be the versions incompatibilites. (The installed rails plugin and gem are version 1.1.3. I don’t know what versions of RSpec the tmbundle support.) I edited the spec_mate.rb to conform with the newer run method.

Index: Support/lib/spec_mate.rb
===================================================================
--- Support/lib/spec_mate.rb    (revision 9148)
+++ Support/lib/spec_mate.rb    (working copy)
@@ -44,7 +44,7 @@
     end
     argv += ENV['TM_RSPEC_OPTS'].split(" ") if ENV['TM_RSPEC_OPTS']
     Dir.chdir(ENV['TM_PROJECT_DIRECTORY']) do
-      ::Spec::Runner::CommandLine.run(argv, STDERR, stdout, false, true)
+      ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(argv, STDERR, stdout))
     end
   end
 end

I reloaded the bundles. I ran a spec file and I finally get the green and red color coded rspec results. Sweet.

Hmm.. Wouldn’t it be nice to have RSpec tmbundle tell the TextMate user that it isn’t compatible with the installed rails plugin or gem?

Using a Different SSH Port in Subversion 1

Posted by teem on November 28, 2007

If the subversion repository in using a different port from the standard port 22, you can create a custom tunnel behavior. This will allow you to use svn+teemssh://user@host/repo/proj/trunk instead of the usual svn+ssh://... and use a different port.To do this, add the line in the [tunnels] section of your subversion config (~/.subversion/config): 

teemssh = $TEEM_SSH ssh -p <port>

 Here’s the link to the documentation.

OS X MySQL Installer: There is nothing to install

Posted by teem on November 18, 2007

I recently got a project involving the installation of Phreebooks, an open source ERP software. I tried installing version 1.2.1beta to see if I can modify it for the client’s needs.

I decided to downgrade my MySQL from version 5 to 4.1 because I am encountering an SQL syntax error during the installation of PhreeBooks. I don’t use MySQL much so I had nothing to back-up. Here’s the link to the MySQL page on downgrading MySQL, including the steps to back up existing databases. I prefer PostgreSQL for my projects.

After downloading the 4.1 binary from the MySQL site, I immediately tried installing the .pkg file only to find that the installation could not proceed as “There is/was nothing to install.” After reading the readme.txt, I deleted the MySQL directories in the /usr/local then tried again. Nope. That didn’t work. After reading the readme.txt again, I found a small hint on how to proceed:

Additionally, you should remove older versions of the Package Receipt directories located in /Library/Receipts/mysql-VERSION.pkg.

So I did just that and it worked. The installation proceeded as expected.”If everything fails, readme.txt. Re-readme.txt if it still fails.” Or use Google. That would be faster most of the time, I guess.

Fisrt Post !

Posted by teem on October 10, 2007

Here’s a list of topics and tools I’ll be looking into in the next few weeks.

  1. Behavior-driven development (BDD)
  2. rSpec
  3. Capistrano and Deployment
  4. Flex
  5. OSX development (Nu?)
  6. Postgresql, OODBMS, and stored procedures
  7. scriptaculous and jQuery


Weekends and Leap Years

Posted by teem on August 14, 2007

I was taking a bath, preparing for work (yes, I still have a job), when I realized that ranges can be used to retrieve all weekends in a year. It turns out that the solution is a one-liner:

(start_date..end_date).select { |p| [0, 6].include? p.wday }
# start_date and end_date are Date objects.

I only figured that out after somebody posted about getting leap years to which I used ranges.

(start_year..end_year).select { |p| Date::leap?(p) }
# start_date and end_date are ints.

We can further choose to create date objects if the year is a leap year and return an array of Date objects.

((start_year..end_year).select { |p| Date::leap?(p) }).collect { |c| Date.new(year=c) }

The PhRUG post is here.