yes and no in YAML
April 09, 2009  comments

I recently needed to display 'yes' and 'no' "internationally" depending on whether the value of a certain attribute is true or false. So I came up with this simple helper method:

  def to_yes_no(expr)
    expr ? I18n.t('yes') : I18n.t('no')
  end

and the corresponding translations in the yaml file:

  yes: sí
  no: no

It was so obviously correct and yet it did not work. It kept displaying "true" or "false". After about an hour spent scratching my head and juggling with yaml files I finally realized that YAML recognizes the strings Yes and No (or their lowercase versions) and handles them as true and false.

Strictly speaking, one should always put quotes around the strings in the locale yaml files to make sure they are recognized as strings, but it's so much uglier that way. Anyhow, the solution was precisely that:

  "yes": "sí"
  "no": "no"

Now I wonder if this is a case where the grammar designers (or whatever we call YAML) want to be smarter than the programmer. In any case, they were this time :)

finding missing I18n translations with missing_t
March 25, 2009  comments

A recurring problem in an internationalized Rails project is to see which translations are missing. You could go through all the pages looking for "translation missing: en, user, new" texts. That, however is very tedious and error prone. There may be some texts you don't even see that are missing translation. (like a title of an image).

A better solution is to write a program that finds these. So that's what I did. I gave it a very imaginative name: missing_t. It's darn simple. You first have to install the gem:

gem install balinterdi-missing_t  

and then from the root of your Rails app you type:

missing_t

You will see all the I18n strings that do not have translations along with the file they were found in. If you want to restrict your search for a specific language, you provide its language code as the first parameter, like so:

missing_t fr

For a bit more detailed description, see the README.

Go ahead, give it a try, your app has the right to speak all those beautiful languages out there!

Thrifty - track your expenses easily
March 17, 2009  comments

Thrifty is a simple application I have written (and am still writing) in Sinatra that tracks your expenses. You can quickly record each spending you make and assign tags to them so you can group your expenditures easily. You can then see how much you spend in different categories (by tags) possibly narrowed down to a given date interval.

Anyway, a web app is all about interaction so give it a try on the test site or download it from its github repo and run it locally. You'll also find a somewhat detailed README there.

This is a very early release so I'd appreciate any kind of feedback, be it a bug report, a comment on bad UI or anything you might find worthwhile sharing.

plans for 2009 - contribute (more) to open source projects
March 12, 2009  comments

At the start of 2009 my friend Jaime resumed his previous year and proposed me to do the same. It seemed a really good idea but somehow it still died down.

I know it's March now but I reckon it's still ok to do this until December :) I'll attempt to write a mini-series of posts about not so much what I did in 2008 but rather what I would like to achieve in 2009.

When I started to work full-time with Ruby I also realized the vast possibilities and magnetism of open source projects. I could -and still can- spend hours browsing among different projects on github, peeping into their code, reading related articles, etc.

So when I set out for this journey one of my tasks naturally became to regularly contribute to a "serious" open source project. When I got acquainted with Merb I also got to know DataMapper, its default ORM. I admired its elegance and coherence and the more I knew of it the more I liked it. So when the maintainer position of a dm-more gem, dm-constraints* seemed to be up for grabs I took the opportunity.

That was in December and since then I sent in a few patches and merged changes implemented by others. (which I realized could sometimes be a lot more difficult than writing code :) ). I like to do this and have learned -and probably will learn- a lot so one of my plans for 2009 is to continue with dm-constraints and maybe find other open source projects I could contribute to on a regular basis.

So, if you happen to use DataMapper, which I strongly encourage you to do, and find a bug related to foreign-key constraints, file a ticket and assign it directly to me (Balint Erdi). And/or start contributing!

Notes

* Dm-more is the meta package that contains everything outside the core functions of DataMapper. Dm-constraints deals with foreign key constraints. If you are familiar with ActiveRecord, it is basically the options you specify with :dependent on an association.

easily quote passage with Mail in a reply
March 12, 2009  comments

That was too long to twitter, so here it goes.

If you use Mail (OS-X) when replying to a message you can select some text in the email you want to reply to and then hit reply. The new email will only include the text you selected so you don't have to delete all the lines you don't need. I hope someone finds this useful, I really do.

Why I love Datamapper
February 12, 2009  comments

I wanted to find the last user in alphabetic order of their names in a Merb project that uses Datamapper (the default ORM in Merb). So I did [*]:

irb(main):020:0> User.all(:order => [:name]).first.name
 ~ (0.032946) SELECT  FROM `users` ORDER BY `name` LIMIT 1
=> "Admin User"

Ok, so the default sorting order is ascending but I need the last one. There are two ways to do this. Write an SQL snippet and sneak in "DESC" somewhere or reverse the collection before taking the first element. Since I was not sure how to sneak in "DESC" plus I prefer writing Ruby to writing SQL hands down, I went with the second approach:

irb(main):021:0> User.all(:order => [:name]).reverse.first.name
 ~ (1.033271) SELECT  FROM `users` ORDER BY `name` DESC LIMIT 1
=> "XX XX"

See what happened? Instead of reverting the collection (which is extra time even if it is done very fast) Datamapper sneaked in that DESC for me! Isn't this just brilliant? Datamapper takes the burden to write SQL off of your shoulders. You can keep writing Ruby statements you presumably love and let Datamapper take care of the SQL reaping both the comfort and the performance gain. [**]. Also, likewise your app stays database type agnostic. Note how it is not supposed there is a RDBMS under the ORM layer. It could work with CouchDB, for example (I think there is actually work in progress for a CouchDB adapter). This is not the only reason I like Datamapper so much, so if you are still not convinced, go check out some other reasons to use it.


Notes

* I could have written this one in a simpler way:

irb(main):018:0> User.first(:order => [:name]).name
 ~ (0.032345) SELECT  FROM `users` ORDER BY `name` LIMIT 1
=> "Admin User"
But you -or at least I- could not do it for the last element (there is no User.last)

** I am not suggesting not to learn SQL at all. I am all for a know-thy-tools approach (especially it it means not cluttering your markup with javascript :) ). However, having the ORM do obviously good things for you is worth it most of the time.

deep_test to become TDD more easily
February 11, 2009  comments

I am all for TDD, really. I did not even waver when recently I have been working on a medium-sized Rails project and running the tests after each change took about 60-80 seconds. 60 seconds is still a lot, though, especially if you go through these cycles ~50 times a day (a wild guess). I also believe in very short test-implementation cycles to stay focused so I was starting to think about ways to keep that time down.

Autotest, part of the Zentest toolbox is a very good choice. It basically runs all the tests automatically after something has changed in the code and more importantly it only runs the tests it deems affected by the latest change. This helped to reduce the amount of time by reducing the number of tests that were run in each loop.

Another I think less well-known option is deep_test which helps to reduce testing time by increasing computational power. More precisely, it runs the tests through worker threads so you can either benefit from using deep_test if you set it up for a computer network (individual computers take from a pool of tests and then send in the results) or if you have a multi-core computer. Since many of us do nowadays, that stepped up as a viable option.

It was quite easy to set up and the results it brought were quite remarkable. It reduced the running time of my tests by ~40% (based on a completely unscientific benchmark). One thing I experienced is that it did not really play out well with sqlite although I have not spent a lot of time trying to make it work there. I just switched to mysql and it worked seamlessly. So yeah, the next logical step was to get the better of both worlds: run only the tests that need to be run and run them on as many cores as possible. I will talk about that in a later post.

I would very much like to hear your experiences and solutions to make TDD a breeze or just plain bearable. I cannot imagine doing real TDD if running tests takes more than a certain time limit, around maybe 90 seconds. Not only you lose a lot of time waiting for the tests to finish, more importantly you fall out of the falling test-implementation cycle, you lose focus, your mind drifts away and then the whole thing probably just does not work.