to_yaml_properties

•February 20, 2008 • 2 Comments

There are just so many little secrets in Ruby. Today we found one. We have a class and we want to be able to serialize it using to_yaml, but we just want to store some, not all, instance variables. After 10 minutes digging out, we found all we need is overwrite to_yaml_properties method, made it return an array of instance variables we want. Like this:


def to_yaml_properties
["@attr1", "@attr2"]
end

Returning Gracefully

•February 14, 2008 • Leave a Comment

I just learned from Marcel Molina a graceful way to return an object from a method. In old days, I often have to write a method like this:

   def born(params={})
     person = Person.new params
     person.do_something
     person.save!
     person
  end

The last line bothered me a lot, it looks ugly.

But just as usual, Rails addresses it, that is method returning. With this method, now I can modify my previous example to the following:

   def born(params={})
     returning Person.new(params) do |person|
       person.do_something
       person.save!
     end
  end

Basically what this method does is return the argument you give to the returning method, AFTER processing it further in the block. Simply beautiful.

For your convenience, here’s a link to the documentation. By the way it’s also very interesting to see what else rails offers in that class. They could come in handy sometimes. Here’s a link to an explanation of K Combinator. You can find tons of related links through our old dear friend google.

The best validation ever

•January 7, 2008 • Leave a Comment

My first name is Yi and I tried to register to a website the other night, and here is what I got:

There were problems with the following fields:

    * First name is too short (minimum is 3 characters)

Riding Rails on IntelliJ

•January 1, 2008 • 1 Comment

Textmate seems the “official” IDE for rails projects. But we have to develop under Windows, so no Textmate.

We used eclipse with radrails (Aptana) for a while, believe me, it’s not fun. Then we start to try IntelliJ now.

Ctrl+Shift+Alt+Space in IntelliJ gives you “word completion”, just like “Esc” in Textmate. And Ctrl+Space works for local variables nicely. And it even works for instance variables, but it needs long time to think. Ctrl+Space works partially in Eclipse, but not in a RSpec file where no explicit class declarations.

Global search on Textmate is a pain, especially if you forget to delete huge development.log and test.log. So I just grep extensively when on Macs. In IntelliJ, you can specify which directory to search with, this helps a lot. Even better, when you have to search the whole project, it will ask you if you want to skip development.log/test.log, very intelligent.

The amazing thing is that renaming classes name and methods name work perfectly in IntelliJ. This feature alone will save me countless time and energy.

Subversion support in Texmate is not so nice, I would just use terminal for subversion operations. In both Eclipse and IntelliJ, the supports are just awesome.

When you have conflicting files, the diff support in Textmate is primitive. And there is no good files/directories comparison tool under MacOS. Meld diff viewer is awesome, but it may take some effort to install it on Macs.

The biggest problem with IntelliJ is that it’s not very responsive, compared to Textmate. But it’s definitely faster than Eclipse.

We use Watir as our scenario test tool, so moving away from Windows doesn’t seem quite possible. This being said, it seems IntelliJ is our best bet.

Simple Format Plugin

•December 12, 2007 • 1 Comment

It’s so amazing that so many rails plugins out there, waiting for your discovery. Such as Simple Format plugin is exactly the stuff we are looking for in our project.

A Study in Array#Collect

•December 4, 2007 • Leave a Comment

Stephen Chu talked about how to beautify statements like
customers.collect { |customer| customer.name } in one of his posts. Dr. Nic also has a post talking about the same thing. It’s very interesting to see so many people want to get away the cumbersome collect syntax and I am one of these people.

To beautify the collect syntax when we need just one field such as customer.name. There are several ways:
to use Stephen’s syntax:
customers.collect_name

Dr. Nic’s:
customers.names

And guess what, if you are using Rails, it comes with a Symbol extension method called to_proc. What the method does is to turn a symbol into a simple Proc object. so we can say:

customers.collect &:name which does the job.

In practice, I always just use this built-in to_proc because it’s free as long as you are on a Rails project. And there is no reason for me to justify I should spend time to make it even more magical.

Stephen also came up with syntax like:
customers.collect_name_and_id

The method always returns an array of arrays ([['Yi', 1], ['Du', 2]]). The syntax looks very nice, but I think it has limited value because I may not want an array of arrays, I may want an array of hashes ([{1 => 'Yi'}, {2 => 'Du']), or an array of strings, then the method has no use or we have to do more magic. Most importantly, when we want multiple fields from a model object to form some kind of data structure, we probably should ask ourselves first: what’s the business meaning for this action? If we can find one, we can just add one method, returning whatever we want, to the model class we are dealing with and use that method for collect.

For example, if I want to send an email to several people and their email address should look like:
people.collect{|person| "person.name <person.email>"}, then I probably will just add a method to the Person class, such as Person#full_email_address and return the string I need. the the syntax for collect can be simplified to people.collect &:full_email_address.

It’s cool to see how powerful method_missing can be with Stephen’s extension, and how lovely Ruby is.

Why I hate test coverage tools

•November 19, 2007 • Leave a Comment

Because they could lie if we abuse them. I have been in one project where people count acceptance tests (written in FIT) so the test coverage always looks pretty high when the unit tests coverage are actually poor. But the figure gave people there false confidence that their code is in good shape.

In another project, a test had only two lines of code, but it actually ran about 5 seconds and touched a lot of code underneath. So by this test alone, it improved the test coverage a lot, looks pretty good eh? Then wait until it failed sometimes. People had absolutely no clue on why it failed and where it caused the failure. and then we could spent one hour to just pinpoint where the problem is. For me, this test is simply just not a test and should be replaced by a bunch of more fine-grained unit tests.

The test coverage number is just a number. It helps when the number is low so that you know you have serious problems in your project. But when the number is high, it doesn’t mean anything. We could still do something with it, such as browsing through the nice colored reports to see where we failed to test and if we should fix that. But we should never trust we are in good shape just because the number is high.

To make our test coverage more meaningful, we should remember that TDD is a tool to help us designing our code, to improve the code quality. If we feel awkward in writing a test, then we know there is something wrong in our code and we should refactor that piece, instead of just writing a bad test or just be off.

When RSpec meets Validatable

•November 12, 2007 • Leave a Comment

Jay Fields writes an excellent module called Validatable to provide a class who include the module the ActiveRecord like behavior. For example, you can say validates_presence_of :attribute etc. This page has the RDoc of the module.When I write RSpec for a Validatable class, I ended up writing a stattement like this:

  @email.validate_only("presence_of/body")
  @email.errors.on(:body).should_not be_nil

Which is basically testing body is a required field. It works, but it looks complicated and hard to understand.The RSpec on Rails plugin provides a method error_on so that I can say something like this:

 model.should have(2).errors_on(:attribute)

This is much more readable than the previous one.I came up with a small extension on Validatable so that I can have a better syntax for testing Validatable.Here’s the spec:

require File.dirname(__FILE__) + '/../../../spec_helper'

module RspecValidatableSpec
  class Thing
    include Validatable
    attr_accessor :age
    attr_accessor :name
    validates_presence_of :age
    validates_numericality_of :age
  end
end

describe RSpecValidatable, 'a validatable object' do
  before :each do
    @thing = RspecValidatableSpec::Thing.new
  end

  it "should tell you it has at least one error on a field" do
    @thing.should have_at_least(1).error_on(:age)
  end

  it "should tell you it has one error on a required field" do
    @thing.should have(1).error_on_presence_of(:age)
  end

  it "should tell you it has one error on a numerical field" do
    @thing.should have(1).error_on_numericality_of(:age)
  end
end

describe RSpecValidatable, 'a validatable object' do
  before :each do
    @thing = RspecValidatableSpec::Thing.new
  end

  it "should tell you it has no error on a field" do
    @thing.should have(:no).errors_on(:name)
  end
end

You may need a different path to your spec_helper.rb to make it work.I got the “traditional” errors_on just like how RSpec works on ActiveRecords. What’s more, Validatable has a validates_only method which allows us validating only one type of error on one attribute. so I can have even better control than RSpec on Rails giving me over ActiveRecords. For example, I can specify what type of errors I expect to have.The only problem is that validates_only raises an error if you check an attribute on a validation that is not specified. So a nice spec like email.should have(:no).errors_on_presence_of(:attachment)is not quite possible. For those of you who are interested in this, here is the actually code:

module RSpecValidatable
  def errors_on(attribute)
    self.valid?
    [self.errors.on(attribute)].flatten.compact
  end

  def respond_to? method_name
    super(method_name) || method_name.to_s.index('error_on') == 0
  end

  def method_missing(error_on_method, attribute)
    reason = error_on_method.to_s.sub(/error_on_/, '')
    self.validate_only("#{reason.to_s}/#{attribute.to_s}")
    [self.errors.on(attribute)].flatten.compact
  end

  alias :error_on :errors_on

end

Validatable.send :include, RSpecValidatable

Law of Demeter and Forwardable

•November 2, 2007 • Leave a Comment

Dan Manges has an excellent post explaining Law of Demeter and when it makes sense to use Forwardable to comply the principle, or I should say when it doesn’t make sense to use the module.

The point is, use it when it makes sense. Take his example, customer_name is just not a sensible method for an order. Asking an order for its customer name is a wrong question because all the order should care is who is its customer. The name is irrelevant to the order.

In fact, I think by putting cusomer_name method in an order. the encapsulation is actually broken because now an order knows the inside details of a customer, thus tightly coupled these two classes.

Simple Captcha and Validatable

•September 10, 2007 • 2 Comments

I need a captcha in a form, whose associated model is a Validatable. After googling, I decided to go with Simple Captcha. The Simple captcha is extremely easy to use, see its documentation, you’ll know. But it works fine with a ActiveRecord::Base, not a Validatable. There has to be some hack to make it work. I could use “Controller mode” of it. But it will be nice to put it into model, make it part of validation process. and here’s my code:

First, include SimpleCaptcha into your Validatable model:

YourValidatable.module_eval do
    class << self; include SimpleCaptcha::ModelHelpers; end
end
&#91;/sourcecode&#93;

<br /><br />And overwrite <i>apply_simple_captcha</i><br /><br />


  def self.apply_simple_captcha(options = {})
    module_eval do
      require 'pstore'
      include SimpleCaptcha::ConfigTasks
      attr_accessor :captcha, :captcha_code,
      :authenticate_with_captcha
      alias_method :valid_without_captcha?, :valid?
    end
    @captcha_invalid_message =
 (options[:message].nil? || options[:message].empty?) ?
  " image did not match with text" : options[:message]
    module_eval(turing_valid_method)
    module_eval(turing_save_method)
  end

Finally, call apply_simple_captcha

That’s it.

In the controller, instead of calling valid? to decide if the object is valid, you call valid_with_captcha?

BTW: Follow this link to see how to install RMagick on Ubuntu