Sam on ze web

RSS

Redcar et Gnome 3

Un petit billet rapide pour expliquer comment j’ai fait pour mettre un favori associé à Redcar dans Gnome 3, sous Ubuntu 11.10.

Selon que l’on utilise RVM ou rbenv pour installer Redcar il y a une petite différence : avec RVM il est facile de créer un wrapper pour rendre disponible une commande indépendamment de la version de Ruby activée, ce qui est vraiment très pratique. Il suffit donc d’utiliser le produit du wrapper pour lancer Redcar quelque soit le contexte. Avec rbenv cette facilité n’existe pas, et il faut alors aller chercher la commande dans le répertoire bin de la version de ruby utilisée lors de l’installation.

Avec rbenv et jruby-1.6.5 :

/home/sam/.rbenv/versions/jruby-1.6.5/bin/redcar

Avec RVM en ayant créé une commande wrapped_redcar :

/home/sam/.rvm/bin/wrapped_redcar

Une fois la bonne commande et son chemin identifiés, il faut créer le fichier redcar.desktop dans le répertoire ~/.local/share/applications . Attention, il s’agit bien de créer le fichier sous son HOME et par ailleurs sur le système.

Voici un exemple de contenu :

[Desktop Entry]
Name=redcar
GenericName=Redcar Text Editor
Comment=Edit text files
Exec=/home/sam/.rbenv/versions/jruby-1.6.5/bin/redcar
Terminal=false
Type=Application
StartupNotify=true
MimeType=text/plain;
Icon=accessories-text-editor
Categories=TextEditor;

Pour être honnête je ne sais pas si toutes les valeurs sont les plus adaptées, mais ça fonctionne très bien.

A titre d’exemple il y a pas mal de fichiers dans /usr/share/applications, et c’est d’ailleurs en copiant l’un d’eux que j’ai constitué le mien (d’où l’anglais dans les libellés).

Mise en route de Rails 3.1 avec Postgresql

Débuter l’utilisation de Postgresql peut présenter quelques difficultés. Il n’y a rien de compliqué ou d’insurmontable, mais sans avoir les bonnes informations cela peut être décourageant.

Je vais présenter ici comment mettre en route un projet Rails en utilisant Postgresql, accompagné de quelques bricoles utiles. Le tout sous Ubuntu 11.10, mais le principe général est indépendant du système.

Pré-requis : avoir Rails déjà installé et quelques connaissances de base à son sujet.

Contexte

Comme indiqué précédemment la distribution est Ubuntu 11.10, utilisant ainsi Postgresql 9.1. Cela fonctionnera indifféremment avec une version Desktop (par exemple pour le développement) ou une version Server (pour le déploiement). Je n’ai testé qu’en 32 bits.

J’ai utilisé Ruby 1.9.2 installé via rvm et Rails 3.1.

Voici la liste des paquets ajoutés par rapport à une installation flambant neuve :

sudo apt-get install ssh build-essential curl git-core

sudo apt-get install zlib1g-dev libreadline6-dev libssl-dev

Installation

Installation de Postgresql :

sudo apt-get install postgresql libpq-dev

La librairie libpq-dev servira à compiler le gem pg.

Il est possible d’installer pgadmin3 pour se faciliter la vie (à condition d’avoir une couche graphique sur son système), mais son utilisation ne sera pas abordée ici :

sudo apt-get install pgadmin3

Création du projet

Choisir un répertoire où créer son projet, s’y placer, puis exécuter :

rails new monappli -d postgres

L’option -d postgres est facultative. Si elle est omise il faudra ajouter soi-même le gem pg dans le fichier Gemfile, et remplacer complètement le contenu du fichier database.yml.

Voici le contenu du fichier database.yml :

development:
  adapter: postgresql
  encoding: unicode
  database: demo
  pool: 5
  username: demo
  password: secret

Pour le test, créer un modèle (User, Utilisateur, TarteAuConcombre, ou n’importe quoi qui fasse l’affaire):

rail g model User

Il faut ensuite modifier le fichier de migration créé pour que le modèle contienne quelque chose de tangible.

Pour aller plus loin, il faut créer une base demo, pour un utilisateur demo ayant secret comme mot de passe.

Créer l’utilisateur et la base de données

Nous voici arrivé à la première difficulté : seul l’utilisateur postgres a accès à Postgresql, et il n’a pas de mot de passe. Pourtant rien n’est perdu :

sudo -s -u postgres

psql

create user demo;

alter user demo with encrypted password ‘secret’;

create database demo owner demo;

\q

exit

DETAIL IMPORTANT : Postgresql peut accepter le compte système de l’utilisateur comme authentification, il ne faut pas créer un compte correspondant à votre identifiant système sans quoi le comportement sera différent de ce qui est expliqué ici (mais ça n’a rien d’interdit non plus…). Par ailleurs en production il est fort possible que le compte système et le compte Postgresql soient différents, autant s’y préparer.

Seconde difficulté

A ce stade on peut penser qu’il est possible de lancer sa migration, se connecter à la base facilement, …. soyons optimistes :

rake db:migrate

Et… c’est raté. Il est impossible de se connecter à la base car l’utilisateur ne peut pas se connecter avec un socket de domaine unix (ou socket IPC).

Ceci ne fonctionnera pas non plus :

psql demo -Udemo -W

Il y a deux solutions, la première est simplement d’utiliser une connexion TCP en ajoutant le host dans le fichier database.yml, il faudra également le spécifier systématiquement lors l’usage de la commande psql. La seconde solution est modifier les paramètres d’authentification lors de l’utilisation des sockets IPC, et c’est ce que nous allons faire.

Modification du fichier pg_bha.conf

Editer (avec vi, nano, gedit, redcar, … ) le fichier /etc/postgresql/9.1/main/pg_hba.conf . Il faut impérativement le faire après une élévation de privilège, exemple avec vi :

sudo vi /etc/postgresql/9.1/main/pg_hba.conf

Repérer la section “local” for Unix socket domain, mettre la ligne avec peer en commentaire, et ajouter une ligne avec md5 comme méthode de connexion comme ci-dessous :

# “local” is for Unix domain socket connections only
#local   all             all                                     peer
local   all             all                                     md5

Conserver la ligne initiale en commentaire au lieu de simplement remplacer la méthode de connexion permet de savoir quelle était la configuration initiale. Sur un serveur en production ajouter un commentaire précisant l’auteur, la date et le motif du changement peut s’avérer très utile d’une manière générale.

Les nouveaux paramètres ne sont pas pris en compte automatiquement. Comme nous sommes sur une machine de développement, nous allons faire les choses de manière radicale en demandant le redémarrage de Postgresql :

sudo /etc/init.d/postgresql restart

A ce stade il doit être possible de lancer sa migration avec succès :

rake db:migrate

Pour en savoir plus sur le fichier pg_hba.conf : http://docs.postgresql.fr/9.1/client-authentication.html

Utilisation de la commande psql

Après avoir exécuté la migration, voici de quoi prendre en main la commande psql pour effectuer des requêtes en ligne de commande :

psql demo -Udemo -W
    saisir le mot de passe ‘secret’ au prompt

\?
   la liste de commandes propres à psql

\h

    la liste des commandes de Postgresql

\h select

    une aide sur la célèbre commande select

\dt

    la liste des tables

\d User

    le détail de la table User

\q

    fin de la partie

Bonus : enregistrer les mots de passe

La commande psql ne permet pas de spécifier un mot de passe en argument, cela a pour conséquence l’obligation de saisir le mot de passe via un prompt. Non seulement cela n’est pas très agréable à l’usage mais surtout rend compliqué l’utilisation de la commande dans un batch. Pour se faciliter la vie, il est possible d’enregistrer pour l’utilisateur du système une liste d’accès aux bases Postgresql , aussi bien locales que distantes.

Il faut créer (ou éditer s’il est présent) le fichier ~/.pgpass ( comprendre /home/monlogin/.pgpass ). Voici un exemple de contenu correspondant à notre exemple :

localhost:*:*:demo:secret

Pour des raisons de sécurité, il est impératif de modifier les droits du fichier. Si ce changement n’est pas fait le fichier sera ignoré :

chmod 0600 ~/.pgpass

Désormais le mot de passe est facultatif :

psql demo -Udemo

A noter que dans ce contexte localhost désigne aussi bien une connexion par socket IPC que via TCP.

Pour en savoir plus sur le fichier de mots de passe : http://docs.postgresqlfr.org/9.1/libpq-pgpass.html

Liens utiles

Héritage et méthodes de classe

Voici une limitation de C# qui m’a donné du fil à retordre cette semaine : une méthode statique d’une classe de base ne peut pas utiliser une méthode statique d’une classe dérivée.

Typiquement une classe de base a une méthode statique effectuant un traitement commun à l’ensemble des classes qui en seront dérivées. Une partie du comportement doit être ajustable via une seconde méthode (toujours statique). La classe de base implémente une version par défaut, et les classes dérivées ré-implémentent le comportement au besoin.

C’est techniquement impossible, C# ne permet pas ce comportement avec des méthodes statiques. La seule manière simple et rapide de s’en sortir est d’utiliser des méthodes d’instances.

Ayant supposé que c’est la pratique de Ruby qui m’a amené à tant d’optimisme lors de la conception, j’ai vérifié le comportement par acquis de conscience. J’ai ai profité pour vérifier également celui de Python (mon expérience en python étant limitée il ne faudra pas m’en vouloir si j’ai fait une boulette).

Exemple en Ruby (1.9.2)


# encoding: utf-8

class Base
  
  def self.methode_dans_base
    methode_a_remplacer
  end
  
  def self.methode_a_remplacer
    puts "Comportement de base par defaut, a remplacer au besoin :("
  end
  
end

class DeriveeA < Base; end

class DeriveeB < Base
  
  def self.methode_a_remplacer
    puts "Comportement de B, remplacé :)"
  end
  
end


Base.methode_dans_base
DeriveeA.methode_dans_base
DeriveeB.methode_dans_base

Tout est au mieux dans le meilleur des mondes possibles comme dirait Pangloss :

Comportement de base par defaut, a remplacer au besoin :(
Comportement de base par defaut, a remplacer au besoin :(
Comportement de B, remplacé :)

Exemple en Python (2.7)


# -*- coding: utf-8 -*-

class Base(object):
  
    @classmethod
    def methode_dans_base(cls):
        cls.methode_a_remplacer()
    
    @classmethod
    def methode_a_remplacer(cls):
        print("Comportement de base par defaut, a remplacer au besoin :(")


class DeriveeA(Base):
    pass
    
    
class DeriveeB(Base):

    @classmethod
    def methode_a_remplacer(cls):
        print("Comportement de B, remplacé :)")

    
Base.methode_dans_base()
DeriveeA.methode_dans_base()
DeriveeB.methode_dans_base()

Là aussi le résultat est celui attendu :

Comportement de base par defaut, a remplacer au besoin :(
Comportement de base par defaut, a remplacer au besoin :(
Comportement de B, remplacé :)

Exemple en C# (4)

Inutile de sortir l’artillerie lourde avec Visual Studio, par exemple sous mono ça se compilera très bien avec mcs .


using System;

class Base
{
  public static void MethodeDansBase()
  {
    MethodeARemplacer();
  }

  public static void MethodeARemplacer()
  {
    Console.WriteLine("Comportement de base par defaut, a remplacer au besoin :(");
  }
}


class DeriveeA : Base {}


class DeriveeB : Base
{
  public static new void MethodeARemplacer()
  {
    Console.WriteLine("Comportement de B, remplacé :)");
  }
}


class Program
{
  static void Main()
  {
    Base.MethodeDansBase();
    DeriveeA.MethodeDansBase();
    DeriveeB.MethodeDansBase();
  }
}


Et là, c’est le drame :

Comportement de base par defaut, a remplacer au besoin :(
Comportement de base par defaut, a remplacer au besoin :(
Comportement de base par defaut, a remplacer au besoin :(

J’imagine que l’on peut parvenir à un résultat similaire à Ruby et Python en utilisant la réflexion, d’ailleurs si quelqu’un a un exemple à titre de curiosité je suis preneur.

Git : faire du ménage dans son arborescence

Mes collègues et moi avons récemment été confrontés à un problème sur un projet utilisant Visual Studio (C#) : le nettoyage de la solution (ou sa reconstruction) était impossible, il ne faisait pas le travail complètement. Il fallait nettoyer les sous-répertoires tels que bin et obj manuellement, ce qui était plutôt pénible vu le nombre de projets dans la solution.

Indépendamment de ce problème, en changeant de branche il est utile de s’assurer que les bases sont saines avant de compiler.

La solution simple et brutale :

git clean -f -d -x

Cette commande efface les fichiers et sous-répertoires non suivis par Git, typiquement ce qui est dans le fichier .gitignore, ou ce qui n’a pas encore été ajouté (git add).

ATTENTION : ceci efface tout fichier non suivi par git, même si c’est du code fraîchement ajouté dans un fichier tout neuf. Il est donc vivement conseillé de bien réfléchir avant de lancer cette commande, et si possible de le faire juste après un commit, un pull, … et pas en plein travail.

Pour en savoir plus :

git help clean
Nov 8

Rails, Cucumber et le français

L’approche de cucumber est intéressante : fournir un scénario de test en langue naturelle, puis construire la plomberie pour l’exécution. Mais l’immense majorité des exemples, tutoriaux, … sont en anglais, à tel point que l’on peut se demander si d’autres langues sont supportées, et si oui comment procéder. C’est possible, c’est facile, et je vous présente ici un petit exemple en français.

Le choix de la langue n’est pas anecdotique : pour un projet open source l’anglais s’impose (comme pour toute autre forme de projet international), mais pour un projet interne il est plus simple d’utiliser la langue locale, surtout si la terminologie métier est riche, voir complexe.

Pour l’exemple je vais me contenter d’un scénario pour un site ayant une page d’accueil qui affiche “Bienvenue” dans son contenu. Ce n’est certainement pas le test le plus pertinent, mais l’objectif est uniquement d’illustrer l’utilisation du français avec cucumber, rien d’autre.

Les tests peuvent être écrits en français, à condition de l’indiquer en début de fichier comme ci-dessous :

features/accueil.feature


#language: fr
Fonctionnalité: Arriver sur le site
  Afin de glander sur le net
  En tant que visiteur quelconque
  Je souhaite voir la page d'accueil du site
  
  Scénario: Arriver sur le site
    Etant donné que je visite la page d'accueil
    Alors je dois voir "Bienvenue"

Reste à coder les diverses étapes du test (notez la précision de l’encodage en début de fichier) :

features/step_definitions/web_steps_fr.rb


# encoding: utf-8

Etantdonné /^que je visite la page d'accueil$/ do
  visit '/'
end

Alors /^je dois voir "([^"]*)"$/ do |contenu_attendu|
  page.should have_content(contenu_attendu)
end

Au delà ce cet exemple (trop) simpliste, il existe d’autres termes pouvant être utilisés dans la définition d’un scénarios : Soit, Quand, Et, Mais, …. la liste exhaustive est disponible dans le gem gherkin (ce n’est pas directement dans cucumber) :

https://github.com/cucumber/gherkin/blob/master/lib/gherkin/i18n.yml

Maintenant vous pouvez développer avec un béret et une baguette sous la bras.

Nov 6

Rendre un site statique

Etant en train de mettre un peu d’ordre dans mon vieil hébergement mutualisé (un peu dans la continuité de la création de ce blog), j’ai modifié un site dynamique basé sur une vieille version de Joomla pour qu’il soit statique.

Pour quelle raison réaliser une telle opération qui fait perdre en fonctionnalité ? Parce-que …

  • le site ne bouge plus (depuis fort longtemps).
  • la version de Joomla n’est plus à jour, et rien ne justifie une lourde migration puisque le contenu du site est figé.
  • il sera plus réactif et libérera des ressources pour un autre site (les joies du mutualisé et des connexions aux bases sql limitées).

L’opération est très simple, j’ai pour cela utilisé httrack (en ligne de commande). C’est un aspirateur de site qui permet de réaliser un miroir local d’un site existant, il modifie donc les liens dans les documents. C’est très pratique pour une consultation offline, mais pas dans notre cas. Il faut donc ajouter l’option “-K4” pour conserver les liens d’origine :

httrack -w -K4 http://lehamstermasque.onzeweb.info

Reste ensuite à remplacer le code sur le serveur web après avoir neutralisé les éventuels formulaires (recherche, contact, …). Inutile de préciser qu’une bonne sauvegarde n’est pas une option ;)

Nov 6

Rails 3 in action et cucumber_rails

Si vous lisez Rails 3 in action et testez les exemples de BDD du chapitre 3 (il est disponible en ligne, coup de chance ^^), vous risquez de rencontrer un problème suite aux évolutions de cucumber_rails.

Le fichier web_step.rb (et quelques autres) ne sont plus disponibles dans les versions récentes du gem, il semble que les éléments disponibles aient une mauvaise influence sur le style d’écriture des scénarios (trop bas niveau): https://github.com/cucumber/cucumber-rails/issues/174

Une solution simple est d’utiliser une version une version précédente du gem :

group :test, :development do
  gem 'rspec-rails', '~> 2.5'
end

group :test do
  gem 'cucumber-rails', '~> 1.0.0'
  gem 'capybara'
  gem 'database_cleaner'
  gem 'factory_girl'
end

Les fichiers supprimés avaient le mérite de donner des exemples simples. Pour veux qui utilisent une version récente, les fichiers supprimés peuvent êtres consultés dans GitHub en revenant au moins de mai 2001.

Les éléments intéressants sont :

  • step_definitions/web_step.rb
  • support/paths.rb
  • support/selector.rb
Nov 5

On se lance !

Le premier billet. ZE first billet… c’est pas rien. Mais en même temps il ne faut pas s’attendre à y lire des révélations fracassantes.

J’ai un blog depuis un moment basé sur Wordpress, que je ne nourris plus vraiment : je n’aime pas parler écrire pour ne rien dire et publier des trucs et astuces déjà lu 100x sur le web. Du coup il n’est plus sérieusement maintenu pour diverses raisons (certaines +/- techniques).

Mais de temps en temps, quelque chose d’intelligent et d’utile pourrait être publié pas mes soins. Je vous accorde que cela n’arrive pas souvent, mais lorsque l’envie me prend (comme ça, subitement), ça me fait mal au cœur de publier sur une plate-forme mourante (pas Wordpress, juste mon installation).

Alors ce jour j’essaie Tumblr. Je regrette de ne plus avoir totalement la main sur ma plate-forme, mais je refuse de continuer à utiliser des outils en PHP en mutualisé. L’autre solution c’est de développer ma propre plate-forme sur mesure (Rails ou autre) et de l’héberger sur un serveur dédié (avec accès SSH, taches planifiées, toussa toussa). Pas le temps dans l’immédiat, et trop coûteux pour l’usage que j’en ferais. Après maintes tergiversations et disputes avec moi-mêmes, la décision est prise, et voilà ce blog ouvert.

Ce n’est pas forcément un choix sur le long terme, mais dans l’immédiat ça rend service. Avant toute chose on va tester tumblr plus en profondeur et améliorer la personnalisation.