Ruby

Graticule, Google and UTF8 are in a boat

I faced a problem recently using Graticule with Google geocoder api. Whenever I check for locations whose name contains accentuated chars (like “Orléans”), I was rewarded with a nice REXML exception telling me google xml was not correct (some tags ending missing).

After about an hour of fight with Graticule, then Open-URI, then Net::HTTP, then StringIO and finally google I discovered the problem : Google Geocoder API send xml response with iso-8859-1 unless you fake being…say “Mozilla/5.0”. No matter you specify Accept or Accept-Charset headers the only way to have the xml as utf8 is sending “User-Agent: Mozilla/5.0”.

In fact it works with different versions :“Mozilla/5.0”, “Mozilla 5.0”, “Mozilla 5.0 (give me utf8 please)”, etc.

So if you want to use Graticule to geolocalize locations with accentuated chars change in graticule’s “rest.rb” (around line 80) :

url.open do |response|

to

url.open('User-Agent' => 'Mozilla 5.0 (Some utf8 please)') do |response|

UPDATE :
Brandon Keepers tackles on this lightning fast and release Graticule 0.2.3, one bug down !!

Published on Fri, 27 Apr 2007 13:12

Gettext and Rails

I encountered some problems with gettext rails integration recently, so here they are with explanation and resolution (if I found it).

Localization of ActiveRecordHelper error messages :

I choose to change the error message as explained by the gettext tutorial :

in application.rb

ActionView::Helpers::ActiveRecordHelper::L10n.set_error_message_title(Nn_("An error is occured", "%{num} errors are occured"))  
ActionView::Helpers::ActiveRecordHelper::L10n.set_error_message_explanation(Nn_("The error is:", "The errors are:"))

this works great, the error message displayed by the helper is the good one… except it only appears in the base language (English in my case). And the text never appears in my .pot file. After some searches in the gettext files, I found the problem : the textdomain for the helper is ‘rails’, which is great because you got validations and errors localized by gettext team for free. But it means you can’t set your own message without modifying the rails.pot in gettext package, which is not a solution because you need to maintain your own gettext gem or apply modifications to all you servers installs, and no you can’t install gettext as a rails plugin as gettext gem compile a gettext.so|.dylib on install which depends of your system.

The solution ? I didn’t find any satisfying one, if you force the textdomain to your app’s one then you need to duplicate and update all the rails translations strings from gettext package.

Gettext#updatepo and models with observers :

One of gettext nifty feature is its ability to extract your model columns names for translation. But the implementation cause some trouble when you have declared some observers in your environment.rb.

To accomplish its tasks, gettext first load rails environment. Then each files are parsed by Gettext::ActiveRecordParser#parse where you have :

old_constants = Object.constants
begin
  eval(open(file).read, TOPLEVEL_BINDING)
rescue
  $stderr.puts _("Ignored '%{file}'. Solve dependencies first.") % {:file => file}
  $stderr.puts $! 
end
loaded_constants = Object.constants - old_constants

This code try to catch the constants the current file add to Object.constants and then parse them either as ruby or ActiveRecord subclass. But if you declared an observer in your environment.rb, the model and its observer is already in the Object.constants and are just ignored by the gettext active record parser.

Solution ? Comment the config.observers line in your environment.rb each time you need to run gettext:updatepo task, not really sexy but it works.

Published on Fri, 30 Mar 2007 10:49

RSpec On Rails and HAML

As my incursion into RSpec continue, I encountered a strange problem on my CC machine. I switched my default layout (aka application.rhtml) to HAML, so the file became application.haml. No problem on my development machine running specs either with spec command or with rake. But the CC machine start sending me error in my specs, telling me application.rhtml does not exists.

I searched some looooong minutes which stack generates this error, four possibilities : RoR, RSpec, Gettext, HAML plugin.

The last thing I did before the specs breaks was to switch a controller spec from view isolation to view integration. So I looked more closely to RSpec On Rails plugin and found something interesting, to run in isolation mode, RSpec on rails stub those methods :

@template.stub!(:file_exists?).and_return(true)
@template.should_receive(:render_template).any_number_of_times.and_return(true) { |*args|
  @first_render ||= args[2]
}
@template.stub!(:find_template_extension_for).and_return("rhtml")
@template.stub!(:read_template_file).and_return("this is fake content generated by rspec")

So it faint Rails about an existing application.rhtml which in fact does not. Rails in its great willingness cache the different template/template extension lookups even in test mode. Then when mixing view integration and view isolation in specs, if those with view integration run after those in isolation, it breaks… or it should, as I can’t reproduce this in my development machine nor can I reproduce this on my CC machine when launching the specs by hand with the spec command (it does occurs only with rake).

About the Rails choice to cache, I fully understand why it is as it is, there should be no template rename during test as it is possible in development mode. So it’s not Rails fault.

But what can we do about this, the simplest solution I came to was to set the template extension caching to off in config/environments/test.rb :

config.action_view.cache_template_extensions         = false

Hope this helps someone else using RSpecOnRails with a custom template system.

[Update]
The difference between my two machine was revealed to me in just after I post this. The rake task on the CC machine, does not sort the controller spec files as my development machine, the problematic file is called addresses_controller_spec.rb so it was the first one evaluate in my development machine and is drowned between others in my CC machine.

Published on Sat, 24 Feb 2007 13:21

How to use a custom RDoc template from a rake task

I just need to do that, use a custom rdoc template to generate a documentation for a Rails project.

My main concern, regarding the different solutions I found on the web, was I didn’t want to have a template in the ruby installation directory but one that resides in a subdirectory of my rails application.

In fact it’s not a problem … when you find the good command. Here’s my rake task to generate the documentation (I put the Jamis Buck customized template in RAILS_ROOT/doc/rdoc_template/jamis.rb)

namespace :doc do 
  desc "Generate documentation for the application"
  Rake::RDocTask.new("app_jamis") { |rdoc|
    rdoc.rdoc_dir = 'doc/app_jamis'
    rdoc.title    = "My Website Documentation"
    rdoc.template = "doc/rdoc_template/jamis.rb"
    rdoc.options << '--line-numbers' << '--inline-source'
    rdoc.rdoc_files.include('doc/README_FOR_APP')
    rdoc.rdoc_files.include('app/**/*.rb')
    rdoc.rdoc_files.include('lib/**/*.rb')
  }
end

The important part is :

rdoc.template = "doc/rdoc_template/jamis.rb"

I tried to use the —template= and -T options in rdoc.options but it didn’t work… then I found that the RDocTask appends its template variable to the options passed to RDoc bypassing mine.

Published on Thu, 15 Feb 2007 13:35

PostgreSQL, MySQL and Ruby Drivers with MacPorts

If you’re on MacOS X and you’re developing database aware applications you certainly want to have installed locally one or both of those populars RDBMS : PostgreSQL or MySQL.

My prefered way of doing it is through MacPorts (previously known as DarwinPorts), a package manager designed initially for Darwin and now focusing on MacOS X.

I assume you already have installed MacPorts as explain on their website.

So let’s open a console with your favorite application (I tend to prefer iTerm over Terminal.app) and enter those commands :

sudo port install mysql5 +server

this will install MySQL 5.x database and the launchd script needed to start it (on-demand or at startup).
When the installation is done you’ll be asked to install the launchd script, just ignore this part and jump to the initialization part.

To initialize MySQL and secure access to it, just enter those commands

sudo -u mysql mysql_install_db5
sudo -u mysql /opt/local/lib/mysql5/bin/mysqld_safe &
/opt/local/lib/mysql5/bin/mysqladmin -u root password 'your_password'

You should now have a shinny new MySQL 5 installation with a password for your root account.

Then PostgreSQL, let’s type in :

sudo port install postgresql81-server

this will install PostgreSQL 8.1.x database and its launchd script.
When the installation is done, as with MySQL skip the launchd part and go to the initialization by issuing those commands :

sudo mkdir -p /opt/local/var/db/postgresql81/defaultdb
sudo chown postgres81:postgres /opt/local/var/db/postgresql81/defaultdb
sudo su postgres81 -c '/opt/local/lib/postgresql81/bin/initdb -D /opt/local/var/db/postgresql81/defaultdb'

PostgreSQL access authorization is something beyond this article, so I’ll don’t cover it.

If all goes well you should now have 2 working installations, but no simple way to start/stop them. A simple and powerful way of handling this (and launchd scripts, create/edit/load/unload) is Lingon. Just download the last version and go to the “Users Daemons” tab and you will see your two launchd scripts are there waiting for you to load/unload/enable/disable them.

To finish this installation, if you’re a Ruby kind of guy you probably want to access those databases from it. There are two ways to install the needed libraries : MacPorts or RubyGems.

For MySQL, there is no problem with MacPorts just type :

sudo port install rb-mysql

If you prefer the RubyGems solution the command is little more tricky :

sudo gem install mysql -- --with-mysql-config=/opt/local/bin/mysql_config5

[Update]
For MacOS X.5 (Leopard) stock Ruby 1.8.6 :

sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/opt/local/bin/mysql_config5

For PostgreSQL, you can’t do it through MacPorts unless you choose to install postgresql8 (and not postgresql81), because of the dependencies. But you can install the library through RubyGems with :

 sudo gem install postgres -- --with-pgsql-include-dir=/opt/local/include/postgresql81/ --with-pgsql-lib-dir=/opt/local/lib/postgresql81/ 

[Update]
For MacOS X.5 (Leopard) stock Ruby 1.8.6 :

 sudo env ARCHFLAGS="-arch i386" gem install postgres -- --with-pgsql-include=/opt/local/include/postgresql81/ --with-pgsql-lib=/opt/local/lib/postgresql81/ 

This is a simple and yet functional setup to work.

Published on Sun, 19 Nov 2006 13:06

BlogMarks Ruby Library

As said in title, I’m working on a ruby library to interact with BlogMarks.net API and I just release the first beta version (0.1.0).

This project amongst others is available on my projects dedicated website : Jonathan’s Projects, as well as on RubyForge under the name blogmarks. Publishing the project on rubyforge is a great thing because it will be automatically published on their gem server.

I don’t really know how many time it take for a new gem to be integrated in gem server, but as soon as it will be, you’ll be able to install it via :

sudo gem install blogmarks

As you should see on my projects page (and soon on this page), I did a simple Typo Sidebar to show how one can use the library to display his last BlogMarks.

Published on Mon, 30 Jan 2006 11:33

RSS