AppleScript for my Rails terminal tabs

Posted by caike on December 10, 2009

While working on a Rails project I always have at least 4 different Terminal tabs that I use for

  1. spork server
  2. autospec
  3. ./script/server
  4. command line stuff (generators and general shell commands)

Setting up the tabs all the time is kind of a boring and repetitive task. This truly deserved some automation and it was the perfect excuse for writing my first AppleScript.

After some googling around I came up with this bash/AppleScript to do these tasks for me (and also open up TextMate):

#!/bin/bash

if [ $# -ne 1 ]; then
    PATHDIR=`pwd`
else
    PATHDIR=$1
fi

/usr/bin/osascript <<EOF
on new_terminal_tab()
	tell application "System Events" to tell process "Terminal" \
        to keystroke "t" using command down
end new_terminal_tab

set actions to {"spork rspec", "autospec", "./script/server"}

tell application "Terminal"
	do script with command "cd $PATHDIR && mate . && clear" \
	in selected tab of the front window
	repeat with action in actions
		my new_terminal_tab()
		do script with command "cd $PATHDIR && " & action \
		in selected tab of the front window
		if action contains "spork" then
			delay 7
		end if
	end repeat
end tell
EOF

If only I had used the right search words I would have found Nick Rutherfor had been through the same situation.

Using Authlogic for general email validation 1

Posted by caike on November 05, 2009

In case you are using Authlogic for authentication in your Rails apps, then you are probably using its email format validation in the user registration step. You get this validation for free just by specifying your model to acts_as_authentic:

class User < ActiveRecord::Base

  acts_as_authentic

end

That’s it for the user model and its registration field validations (login, email and password).

But what if you have some other model in your application with an email field that you also want to validate ? You could just get your favorite email format regexp and use it with the validates_format_of method:

class Band < ActiveRecord::Base

  validates_presence_of :manager, :description
  validates_format_of :email, :with => /SomeRegexpYouGotFromGoogle/

end

But that would be decentralizing the email validation concern - totally anti-DRY and error-prone.

A better solution would be to use the email regexp that’s in Authlogic, which is the same that’s already validating your user model email field.

class Band < ActiveRecord::Base

  validates_presence_of :manager, :description
  validates_format_of :email, :with => Authlogic::Regex.email

end

That’s it. Hope it helps someone keep their code clean.

DHH’s secret to high productivity

Posted by caike on May 09, 2009

I have had a great impression watching DHH’s keynote from this years’ RailsConf. According to him, although many changes have been made to the Rails codebase since he started the project 6 years ago, on the overall not that much has changed.

From the few times I’ve watched him speak, he always made it clear that out-of-the-box Rails is all he really uses or knows about. No surprise, since he has written the thing for himself exactly the way he needed it to be. Then a core team came along and extended it. Nice. Now we have people digging in for performance enhancement which will be seen in Rails 3. Great!

Its convention over configuration was never meant to be fit for everyone and every occasion. It will probably never be in the long run and I really hope it stays that way. If someone thinks they need to tweak a few things in Rails in order to accomplish something, then they should go ahead and do it and it’s awsome how most times it is as simple as writing a plugin or gem.

All the framework hype that we see happening today is way more than we will ever come to actually need.  His secret to high productivity is not really technology related. It’s all about renegotiating requirements.

If you are developing professional solutions for the enterprise (and by that I don’t mean enterprisey) and you’re still doing it the hacker way, then no platform will look good enough for you. If there is no communication involved in your development process, then you will either fail or spend a lot more effort on trying to develop something.

Five years have passed since Rails was released. All it offers, plus all the other gazillion testing frameworks and gems, will be completely useless unless you take your time to understand what really needs to be done.

You client doesn’t always know what he wants, but he sure knows what he does not want.

He may come up to you and ask you for something that will take you two weeks to develop. As a professional software developer, it is up to you to start from what he wants and get to what he needs. Maybe you can solve his problem with a completely different solution, and one that will take you one day to develop.

As DHH said it, in case you want chocolate, maybe a Twix that is in your pocket is all you need, rather than driving all the way downtown and getting a 15 dollar belgian chocolate.

DHH e o segredo para a alta produtividade

Posted by caike on May 09, 2009

A keynote do DHH na RailsConf deste ano me causou uma boa impressão. Segundo ele, mesmo havendo muitas mudanças incorporadas ao código do Rails desde que o projeto foi iniciado há 6 anos, no geral não mudou muito.

Das vezes que pude assiti-lo falar, ele sempre deixou bem claro que o Rails “básico” é tudo o que ele realmente usa ou sabe a respeito. Nada supreendente, uma vez que ele escreveu o framework para seu próprio uso e exatamente da maneira como ele precisava que fosse.

Então veio um “core team” e estendeu a ferramenta. Legal. Agora temos pessoas cavando nas profundezas para melhorar sua performance, que será visto na versão 3 do Rails. Excelente!

Sua convenção sobre configuração nunca pretendeu agradar a todos ou servir a todas as situações. O Rails nunca será a bala de prata e eu realmente espero que permaneça desta maneira. Caso você precise mudar alguma coisa no comportamento do Rails, na maioria das vezes esta mudança é tão simples quanto escrever um plugin ou gem. 

Toda a hype em torno de frameworks (do próprio Rails e outros ‘auxiliares’) que vemos hoje é muito mais do que vamos realmente precisar algum dia. O segredo que DHH fala sobre a alta produtividade não é nada relacionado a tecnologia. Mesmo tendo desenvolvido o Rails para aumentar sua produtividade, o seu real segredo é saber renegociar requisitos.

Se você está desenvolvendo software profissionalmente para a indústria e ainda utiliza a maneira hacker, nenhuma plataforma será produtiva o suficiente para você. Caso não haja comunicação envolvida no seu processo de desenvolvimento, você irá certamente falhar ou então gastar muito mais tempo para desenvolver algo que - a princípio - resolva o problema do seu cliente.

Cinco anos se passaram desde que o Rails foi lançado. Tudo o que ele oferece e mais todos os outros zilhões de frameworks de teste e gems são totalmente inúteis, a não ser que você preocupe-se com o que essencialmente precisa ser feito.

Seu cliente pode não saber o que ele quer, mas certamente sabe o que não quer. 

Ele pode chegar para você e pedir algo que levará duas semanas para ser desenvolvido. Como um desenvolvedor profissional, cabe a você começar da onde ele quer e chegar aonde ele precisa. Talvez o resultado seja resolver problema do seu cliente com uma solução completamente diferente da que foi sugerida por ele, mas uma muito mais simples e que levará você muito menos tempo para desenvolver.

Como DHH falou, quando você quiser um chocolate, talvez um Twix que esteja no seu bolso seja tudo o que precise, ao invés de dirigir até o centro da cidade e gastar muito mais dinheiro com uma caixa de chocolates belgas.

Test Driven Development in Rails - Part I (Models)

Posted by caike on March 04, 2009

The following is part one of a series of examples of a simple feature developed using Ruby on Rails. The intent of this post is to show how the test code can (and should, as much as possible) be written before the actual implementation code, which is an agile practice known as Test Driven Development.

I expect this series of examples to show how writing tests is actually a design activity rather than simply code verification. Each new test runs along with all the previous tests. This automation helps developers by giving them constant feedback.

The Steps

According to Kent Beck, the rythm of Test Driven Development can be summed up as follows:

1. Quickly add a test.

2. Run all tests and see the new one fail.

3. Make a little change.

4. Run all tests and see them all succeed.

5. Refactor to remove duplication.

The Tools

There are many testing framework options to choose from in the Ruby world (RSpec, Cucumber, Shoulda, etc.) but in this example I’m going to keep it plain and simple using just Test::Unit for unit testing the models and ActionController for testing controllers as well as testing routes.

After writing each test and ensuring that it fails, we will write the simplest thing that could possibly work. At first it may look ugly and not “the Rails way” of doing things, but we will later enhance its quality using another agile technique known as refactoring.

Rails out-of-the-box expects you to have a database setup and creates default fixtures for each of your models. Although there is a way to get around that, I’ll leave it alone for now.

The problem

Our client wants us to develop an e-commerce app for his musical instrument shop. From our meetings, we agreed that users should be able to buy instruments online. He said that for an instrument to be considered valid it must belong to a category, have a description and have a price. If either of those conditions is not true, then the instrument is not valid.

Making it work

Notice how the meeting revealed a few keywords and concepts to be used in the construction of our domain model and its relationships (instrument, description, category, price, belongs to).

We start off creating our application:

$ rails music_shop
$ cd music_shop

and creating our first model:

$ ./script/generate model instrument

The output shows that a bunch of files were created. At this moment, only three files are important for us: instrument migration file, model and unit test.

Our client told us he wants an instrument with description, price and category, therefore they will be the initial attributes for instrument.

Add the following snippet to some_number_create_instruments.rb located in db/migration.

create_table :instruments do |t|
     t.string       :description
     t.decimal      :price, :precision => 8, :scale => 2
     t.references   :category

     t.timestamps
end

This migration file is going to build the instruments database table using the adapter defined in database.yml, located in the config folder. Unless defined otherwise, Rails uses SQLite as dbms and I suggest that you keep it that way until deployment (or even until SQLite becomes a bottleneck for you app).

Run your migration:

$ rake db:migrate

The database table has been created for you and you don’t need to worry about it anymore.

Now we should focus on the business requirements. Open test/unit/instrument_test.rb and add the following snippet that relates to what the client said about a valid instrument.

  def setup
    @valid_params = {:description => "gibson sg",
                     :price => 100.00, 
                     :category => Category.new}
   end

  test "not valid without description" do
    guitar = Instrument.new(@valid_params.merge(:description => nil))
    assert !guitar.valid?
    assert guitar.errors.on(:description)
  end

 

Let’s run our first test

$ rake test:units

and watch it fail!

1 tests, 0 assertions, 0 failures, 1 errors

It was expected to fail since we have not implemented any validation yet. Actually it has not failed, but spit an error instead:

1) Error:
test_not_valid_without_description(InstrumentTest):
NameError: uninitialized constant InstrumentTest::Category

The error says there is no Category class defined. So lets generate our missing model, run the created migration and then run the test again.

$ ./script/generate model category
$ rake db:migrate
$ rake test:units

No complaining about missing class, but it says there is no category attribute for our Instrument model.

1) Error:
test_not_valid_without_description(InstrumentTest):
ActiveRecord::UnknownAttributeError: unknown attribute: category

Indeed, we haven’t coded anything that says that an instrument belongs to a category. So let’s do that in our Instrument model:

class Instrument < ActiveRecord::Base
  belongs_to :category
end

Run the tests again and notice how the errors are gone. Now there is just a failing test that needs to get out of our way.

2 tests, 2 assertions, 1 failures, 0 errors

Notice how the test code is guiding us through design and it’s telling us what needs to be done, like in a two-way conversation.

The process of starting a feature with failing tests and coding towards making the tests pass is known as “red green refactor”, resembling the red and green bars present in previous unit test framework outputs (JUnit being the most famous). Taking baby steps is a safe way to measure the impact of you actions in the code.

Only one line is needed to make the failure go away. In the app/models/instrument.rb add the following:

class Instrument < ActiveRecord::Base
  belongs_to :category
  validates_presence_of :description
end

Run the test again and watch the failure go away.

1 tests, 1 assertions, 0 failures, 0 errors

I believe that as you gain proficiency with test driving your code, you can go ahead and write a couple of failing tests before going into implementation code - as long as they are related to the same context of the unit under test.

Moving on with our tests, let’s add two more:

 test "not valid without price" do
    guitar = Instrument.new(@valid_params.merge(:price => nil))
    assert !guitar.valid?
    assert guitar.errors.on(:price)
  end

  test "not valid without category" do
    guitar = Instrument.new(@valid_params.merge(:category => nil))
    assert !guitar.valid?
    assert guitar.errors.on(:category_id)
  end

Run it again with rake and watch it fail:

3 tests, 3 assertions, 2 failures, 0 errors

Now only the barely essential to make the above tests pass is added, and the complete instrument model looks like the following:

class Instrument < ActiveRecord::Base
  belongs_to :category                      

  validates_presence_of :description, :price
  validate :has_a_category

  def has_a_category
    if category.nil? && category_id.nil?
      errors.add(:category_id, "must have a category")
    end 
  end
end

Run the tests again and they should all pass

5 tests, 5 assertions, 0 failures, 0 errors

Conclusion

I hope the previous steps showed some of the benefits of test driven development, which is, in my humble opinion, one of the most important agile practices.

It should be taken as a design practice rather than pure verification. Running automated tests keeps the developers in control of the application and makes code easier to maintain and evolve.