14 juillet 2011

Capistrano and ruby version...

I had a strange problem while running Whenever through Capistrano (see error below).

I tracked down the error to a RubyGems version: http://makandra.com/notes/1051-fixing-uninitialized-constant-activesupport-dependencies-mutex-nameerror

But when I ran Whenever manually on the server, it worked fine!

So, why was Capistrano using a different version of RubyGems? Because it was using a different version of Ruby!

I had to add the following to my deploy.rb file:

set :default_environment, {
'PATH' => "/opt/ruby-enterprise-1.8.7-2011.03/bin:$PATH"
}



* executing "cd /var/rails/my_app/releases/20110708073140 && bundle
exec whenever --update-crontab my_app"
servers: ["122.248.242.46"]
[122.248.242.46] executing command
** [out :: 122.248.242.46] /var/rails/my_app/shared/bundle/ruby/1.8/
gems/activesupport-2.3.8/lib/active_support/dependencies.rb:55:
uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/activesupport-2.3.8/lib/active_support.rb:57:in `require'
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/activesupport-2.3.8/lib/active_support.rb:57
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/activesupport-2.3.8/lib/active_support/all.rb:8:in `require'
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/activesupport-2.3.8/lib/active_support/all.rb:8
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/whenever-0.6.8/lib/whenever.rb:2:in `require'
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/whenever-0.6.8/lib/whenever.rb:2
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/whenever-0.6.8/bin/whenever:5:in `require'
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/gems/whenever-0.6.8/bin/whenever:5
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/bin/whenever:19:in `load'
** [out :: 122.248.242.46] from /var/rails/my_app/shared/bundle/ruby/
1.8/bin/whenever:19

18 avril 2011

Ecosystème Rails: Bundler + GitHub = maîtrise de vos dépendances externes

La communauté Rails est très active et créative: elle innove constamment et tout un écosystème d'outils en résulte. Cet écosystème m'aide énormément dans mon travail, mais il peut vous aider vous aussi, même si vous n'utilisez pas Rails.

C'est pourquoi je voudrais présenter ces outils dans une série de posts. Je commence aujourd'hui avec Bundler et GitHub, une combinaison extraordinaire pour maîtriser vos dépendances externes.

Bundler

Bundler est un gestionnaire de "gems" (les librairies externes de Ruby, l'équivalent des eggs en Python, des jars en Java, etc.).

Dans un projet qui utilise Bundler, il suffit de spécifier dans un fichier "Gemfile" la liste des gems que l'on veut utiliser:

gem "pg"
gem 'will_paginate'
gem "transaction-simple"
gem "color"

Ensuite, il suffit de demander à Bundler d'installer les dépendances ("bundle install") et toutes les gems sont installées.

Si une des gems installées dépend d'autres gems, celles-ci seront également automatiquement installées par Bundler.

De plus, Bundler permet de gérer différents environnements (par exemple: test, développement, production) et d'appliquer ces environnements à différents types de serveurs (serveur de test, serveur d'intégration, serveur de production, ...).

GitHub

GitHub est un serveur Git, avec des services construits autour.

GitHub a la particularité d'être gratuit pour les projets open-source. Ce site est très populaire dans la communauté Ruby (ce qui est normal, puisque les créateurs sont des Rubyistes connus) et pratiquement toutes les "gems" de Ruby ont leur code en open-source sur GitHub.

Parmi les services apportés par GitHb, deux vont nous intéresser plus particulièrement dans ce post: fork et pull request.

Maîtrise de vos dépendances externes


L'avantage de l'open-source, c'est que si vous trouvez un bug dans une "gem", ou que vous voulez étendre la fonctionnalité d'une "gem", vous pouvez plonger directement dans le code source et le modifier par vous-même.

GitHub pousse les choses plus loin: une fois que vous avez un compte sur GitHub, il vous suffit de trouver le projet que vous voulez modifier et d'appuyer sur le bouton "Fork" pour créer, sous votre compte, un nouveau clone de la librairie:


Vous pouvez maintenant effectuer vos modifications sur votre copie de la libraire externe.


Bundler intègre cette nouvelle version de la "gem", avec un simple lien vers votre version GitHub:

gem "pg"
gem 'will_paginate', :git => "git@github.com:cbonnet99/will_paginate.git"
gem "transaction-simple"
gem "color"

Boucler la boucle: pull request


A présent, dans l'esprit open-source, si vous avez fixé un bug (avec un test, bien sûr!), vous devez proposer un patch à l'auteur de la "gem". Là encore, GitHub vous mâche le travail avec "pull request".

Lorsque votre patch est prêt, il vous suffit d'appuyer sur le bouton "Pull request" et l'auteur de la librairie originale sera notifié de votre changement:




Il ou elle pourra alors l'intégrer dans le code source avec un simple "merge" et un "commit".

Conclusion


La puissance de Bundler combiné à GitHub rendent simple un problème complexe: la gestion des dépendances externes d'un projet.
De surcroît, ces outils donnent tout son sens au concept d'open-source et permettent à tout un chacun de contribuer aux projets open-source avec un investissement de temps minimal.

16 avril 2011

Create a remote branch in Git and track it

Create a remote branch:

git push origin origin:refs/heads/new_feature_name

Make sure everything is up to date:

git fetch origin

Start tracking the branch:

git checkout --track -b new_feature_name origin/new_feature_name

07 février 2011

Article de JavaWorld sur JRuby

Un article intéressant de 2007 sur JRuby:

http://www.javaworld.com/javaworld/jw-02-2007/jw-02-jruby.html

Les points principaux:

To a Java developer, Rails seems like the natural culmination of trends in the evolution of Java Web frameworks: less unnecessary code, more abstraction and dynamism, and fuller out-of-the-box functionality

If you have the flexibility to choose a new approach for your next project, consider Rails. Even easier to use than lightweight Java frameworks, Ruby on Rails seems like a natural next step in a Web developer's journey towards simplicity and expressiveness

JRuby a énormément progressé depuis 2007: ses performances sont largement supérieures à Ruby MRI 1.8.7, par exemple.

Mais il est intéressant de noter que JavaWorld parlait déjà du potentiel de JRuby en 2007!

Présentation de JRuby

La semaine dernière, j'ai présenté JRuby dans un brainstorm. Voilà les diapositives de la présentation:

http://www.slideshare.net/CyrilleBonnet/jruby-lalliance-de-ruby-avec-java

04 février 2011

Installer JRuby et Rails

Dans ce post, je vais décrire comment installer JRuby. Ensuite je vous montrerai comment faire tourner une application Rails 3 de base avec JRuby.

Tout d'abord, vous allez devoir installer JRuby. Vous pouvez installer directement les exécutables, que vous téléchargez sur le site de JRuby.

Toutefois, si, comme moi, vous utilisez plusieurs versions de Ruby, je vous conseille fortement d'utiliser Ruby Version Manager (RVM).

Une fois que RVM est installé, une seule ligne de commande suffit pour installer JRuby:
rvm install jruby

Ensuite, pour commencer à utiliser JRuby:
rvm use jruby

Quand vous aurez fini, pour revenir à votre version de Ruby par défaut, il suffit de faire:
rvm reset

Vous pouvez vérifier la version de JRuby que vous allez utiliser:
jruby -v

A présent, installons Ruby on Rails:
jruby -S gem install rails

Pour créer une nouvelle application Rails 3:
jruby -S rails new demo_jrails -m http://jruby.org/rails3.rb

Rails 3 inclut toutes les dépendances vers les libraires externes (gems en Ruby) dans un seul fichier Gemfile. Pour installer ces dépendances sur votre machine locale, il suffit de faire:
jruby -S bundle install

Quant à votre fichier de configuration de base de données, il ne dévoilera pas que vous utilisez JDBC et aura l'air tout à fait ordinaire (notez que j'utilise Postgresql):
development:
  adapter: postgresql
  encoding: unicode
  database: demo_jrails_development
  pool: 5
  username: USER
  password: PWD

Si vous avez des problèmes avec la connection à la base de données, commencez par regarder le README d'ActiveRecord JDBC Adapter sur GitHub.

Enfin, si vous voulez utiliser des JARs dans votre JRuby, il convient de créer une variable d'environnement CLASSPATH. J'ai fait pointer la mienne vers le répertoire lib de JRuby:
export CLASSPATH=/~/.rvm/rubies/jruby-1.5.1/lib

Amusez-vous bien avec JRuby et Rails!

Dans un prochain post, nous verrons comment créer un fichier de déploiement Java.

28 janvier 2011

JRuby: l'alliance de Ruby avec Java

A Toulouse, beaucoup d'entreprises ont standardisé leurs investissements informatiques autour de Java. De ce fait, tous leurs développements se font dans ce langage.

Mais ces choix sont-ils vraiment nécessaires? Je vous propose de faire un tour du côté de Ruby, un langage de programmation extraordinairement expressif, qui sait aussi travailler avec Java.

Ruby: flexibilité et productivité

Beaucoup d'outils innovants sortis ces dernières années ont été écrits en Ruby:
  • Rails: framework pour le développement d'applications Web,
  • Cucumber: pour l'écriture et l'exécution de tests d'acceptance,
  • RSpec: tests de comportement
  • et beaucoup d'autres...

Au-delà des outils, de nombreuses applications Web ont été développées avec Ruby (et Rails, pour la plupart):

De même, dans le monde anglophone, de très nombreuses start-ups choisissent Ruby, afin de se développer rapidement.

Le rythme soutenu de toutes ces innovations n'est pas dû au hasard: Ruby est un langage dynamique et flexible, qui s'adapte rapidement à de nouvelles contraintes. Ou comme le dit très justement Jamis Buck, Ruby est de la pâte à modeler.

Java: maturité et standardisation

Par contraste, pour Jamis, Java est un jeu de Lego: des blocs fixes, faciles à assembler et à réutiliser. Une image qui, là encore, colle assez bien à la réalité.

Java est un langage très répandu, très "industrialisé". Les différentes offres de Java Virtual Machines, par exemple, sont robustes et matures. De nombreux outils de gestion permettent d'administrer et d'exploiter efficacement des applications tournant dans une JVM.

De manière similaire, Java a bénéficié du développement de très nombreuses librairies: open-source, commerciales et même en interne pour les grandes entreprises comme Airbus. Ces librairies sont souvent robustes et adaptées aux processus industriels en place.

Malheureusement, jusqu'ici, bénéficier de la robustesse et de la maturité de Java revenait à se passer de la flexibilité et de la puissance d'expression des langages dynamiquement typés tels que Ruby.

Java + Ruby = JRuby

L'objectif de JRuby est justement de réconcilier ces deux mondes. JRuby est une implémentation du langage Ruby, écrite 100% en Java.

Avec JRuby, vous programmez en Ruby et vous pouvez utiliser n'importe quelle librairie Java: les objets Java sont créés et manipulés directement en Ruby!

De surcroît, JRuby est très rapide: voyez, par exemple, les résultats du Ruby Great Shootout 2010.

Conclusion

JRuby combine le meilleur de deux mondes apparemment opposés: la solidité et la maturité de Java, avec la flexibilité et la puissance d'expression de Ruby.

Si votre entreprise utilise Java et cherche à développer rapidement des applications Web, JRuby est une option à ne pas négliger.

N'hésitez pas à me contacter si vous avez des questions.

Je vais revenir à JRuby dans un prochain blog: au plaisir de vous revoir...

17 janvier 2011

Get a random element from an array

I used that expression before:
random_choice = array[rand(array.size)]

Then I read this quicktip and decided to try:
random_choice = array.choice

Unfortunately, on my production server, I still have Ruby 1.8.6. So, after a long search, I finally settled on:
random_choice = array.rand

Which is supported in both Ruby 1.8.6. and 1.8.7

11 octobre 2010

Bind socket to interface: No such device

My VM with Ubuntu on it has trouble sometimes dealing with the changes between bridged eth0 and eth1.

The symptom:
SIOCSIFFADDR: No such device
eth0: ERROR while getting interface flags: No such device
Bind socket to interface: No such device
Failed to bring eth0

First check all your network interfaces:
ifconfig -a
You should see that the eth1 interface is actually present (but not connected).

Note the MAC address of eth1. Edit /etc/udev/rules.d/70-persistent-net.rules and change eth1 -> eth0 (the MAC address should be the correct one). You can delete the old line for eth0.

Restart the VM and the network should be OK.

28 septembre 2010

Using multiple inheritance for Python mocks

Today, I needed to mock just one function from a class instance.

I used multiple inheritance to achieve that like so:



The ProdEngineMock class inherits everything from the ProdEngine class, except the mocked function.

Nice and elegant!

25 septembre 2010

Convert a sql_ascii Postgres database to a UTF8 one

pg_dump -f your_db.dmp your_db

iconv -f ISO8859-1 -t UTF-8 your_db.dmp > utf.dmp

psql your_utf_db < utf.dmp

Note that Rails was used to input the data into my old sql_ascii database, so the encoding was consistent. You might not be so lucky...

Identify large tables on Postgres

To quickly know which of your Postgres tables are the largest:

select relname, reltuples from pg_class order by reltuples desc;

reltuples are the number of rows, so this command will show your largest tables first.

Rails validates_length_of and byte encoding

Why you should NEVER create a Postgres database with the default sql_ascii encoding set to use with Rails


Ruby prior to 1.9 considers strings as bytes, and that can cause some maddening issues. In my experience, all encoding issues are maddening...

Anyway, I had a validates_length_of like so:



I got a problematic lead from a customer (that included special Word characters that were multi-bytes), put them in a test and started a debug session:



What???

After some digging, Rails, in order to consider characters and not bytes, uses split(//).size instead of size directly. Split(//) is the default tokenizer of validates_length_of and it can be changed as an option passed to the validates method. See http://railspikes.com/2009/7/20/validates_length_of-gotcha for more details.

My original problem, though, was that the lead was 499 characters, but 517 bytes and my Postgres database was encoded with the default sql_ascii encoding set.

Therefore, my constraint on Postgres column lead "character varying(500)" translated to 500 bytes maximum...

Conclusion: never ever create a Postgres database with the default sql_ascii encoding set to use with Rails. Always use the utf8 encoding set. Even if you deal only with English: special characters exist in all languages...

15 septembre 2010

Samba to follow symbolic links on Ubuntu

Add to /etc/samba/smb.conf:
follow symlinks = yes
wide symlinks = yes
unix extensions = no
And reload the Samba configuration:
sudo service smbd reload

Mount a new hard drive on Ubuntu

Check that the disk is available:
sudo lshw -C disk
(this will give you a list of available disks, find the one you want to mount and copy its logical name. For instance, the logical name could be: /dev/sdb)

Partition the disk on the command line:
sudo fdisk /dev/sdb 

Create a new partition: n
Select a primary partition: p
Select the first partition: 1
Write the new partition: w

Format the new disk:
sudo mkfs -t ext3 /dev/sdb1

Create a new mount point:
sudo mkdir /media/extradrive

Edit /etc/fstab (sudo vi /etc/fstab) and add a line:

/dev/sdb1 /media/extradrive      ext3    defaults        0       2

Reload the mounts:
sudo mount -a

Change the ownership and rights of the new drive:
sudo chown -R USERNAME:USERNAME /media/extradrive
sudo chmod 755 /media/extradrive

Where are my packages?

A good trick to know where your Python packages are located:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

Change environment variables for Apache on Mac OS X

In order to get a new environment variable accessible to Apache on Mac OS X (10.6), you need to edit the /etc/launchd.conf file and add:

setenv MY_VAR /my/value/here

Create an Ubuntu VM with Sun's VirtualBox (with Oracle XE)

sudo mkdir /mnt/cdrom
sudo mount /dev/cdrom /mnt/cdrom
cd /mnt/cdrom/
sudo ./VBoxLinuxAdditions-x86.run

sudo mkdir /mnt/downloads
sudo mount.vboxsf Downloads /mnt/downloads/

sudo cp /mnt/downloads/oracle-xe-universal_10.2.0.1-1.0_i386.deb

sudo apt-get install bc
sudo apt-get install libaio1

#expand swap:
sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
sudo mkswap /swapfile
sudo vi /etc/fstab and add at the bottom:
/swapfile none swap sw 0 0

dpkg -i oracle-xe-universal_10.2.0.1-1.0_i386.deb

sudo /etc/init.d/oracle-xe configure

Export from another machine:
exp full=y file=shi.dump
(you are prompted for username/pwd, use sys as sysdba)

Increase the number of processes available to Oracle:
ALTER SYSTEM SET PROCESSES=150 SCOPE=SPFILE;

MAKE SURE that:

* SID in tnsnames.ora is the same as ORACLE_SID in environment variables (it is case sensitive!)

* ORACLE_HOME doe NOT end with a /

in Oracle:
CREATE USER reb identified by reb;
GRANT CREATE SESSION TO reb;
GRANT UNLIMITED TABLESPACE TO reb;


imp fromuser=reb commit=y ignore=y file=shi.dump

Same for users: SEL1, SEL2, SEL3, IDCX, LEB, STATIC, RMSAUTO, RMSMAN

For RAD, users are: RMSUSER, RMSMAN, RMSAUTO, IDCX, NMS, NMSGSYS

Grant special privileges to users that need to create tables and sequences:
GRANT CREATE TABLE TO nmsgsys;
GRANT CREATE SEQUENCE TO nmsgsys;
GRANT CREATE TABLE TO nms;
GRANT CREATE SEQUENCE TO nms;

Create user NMS_USER (same syntax as above) and grant privileges:

sqlplus sys/sysdba@ctbtoenv/xe as sysdba @grant_privileges NMS NMSUSER
sqlplus sys/sysdba@ctbtoenv/xe as sysdba @grant_sequence_privileges NMS NMSUSER
sqlplus sys/sysdba@ctbtoenv/xe as sysdba @grant_privileges NMSGSYS NMSUSER
sqlplus sys/sysdba@ctbtoenv/xe as sysdba @grant_sequence_privileges NMSGSYS NMSUSER

sudo adduser nmsuser (pwd: nmsuser)

17 août 2009

RubyZip and MS Office .docx

To create a .docx Word document, you need to zip up a number of files. If you use the rubyzip gem (as seems natural), you'd get a nasty warning:

"Microsoft Office cannot open this file because the .zip archive file
is an unsupported version."


Instead, use the command-line zip command and it works like a charm. See another post describing a similar problem.

attr_accessor and timestamps

I had an attribute set with attr_accessor. Then in a before_update, I would set an actual DB field on certain conditions like so:


def before_update
if ....
self.my_db_field = self.my_attribute_from_attr_accessor
end


The problem I encountered is that, if the attribute in attr_accessor is the only one that is modified, the updated_at timestamp is not changed...

If you look at the lifecycle of an ActiveRecord update, I think the timestamp update occurs some time BEFORE the before_update...

Too bad! A simple workaround, though, is to put the code above in the validation, as this definitely gets executed before the timestamp update.