The Caribbean Weblog

"This blog is continuing @ http://christophemaximin.com "

Aller au contenu | Aller au menu | Aller à la recherche

samedi 29 septembre 2007

Nouvelle bonne habitude : auto-focus

Un court billet pour dire une chose simple, mais qui est assez utile et intéressante à la fois : Si ce n'est pas déjà le cas, quand vous coderez vos prochains sites web, je vous conseille de mettre des "auto focus" sur les premiers champs de tous vos formulaires, par un onload ou comme vous voudrez.

C'est extrêmement pratique et confortable pour l'utilisateur (moi), et ça ne coûte rien à mettre en place.

vendredi 27 juillet 2007

YATWS -beta-

YATWS, a Ruby on Rails, RESTful, AJAX-loaded, easy-to-use multi-level and ads-free tasks-manager -beta- web service. No big deal, I needed it for myself, I created it, that's all.

mercredi 18 juillet 2007

Faire un do...while en ruby

Il se trouve que la vraie structure do ... while n'existe pas en ruby. Sérieusement.
Pour combler ce manque, il devient commun d'utiliser la structure begin...end faite pour gérer le (long)[1] code suceptible de générer une exception (plus d'informations).

Ceci ce présente donc sous la forme suivante, par exemple :

begin
  @user = User.create_guest
end while @user.errors.any?

C'est bête, mais on s'y fait, surtout quand il se trouve que l'on doit vraiment gérer des exceptions dans ce bloc.

Notes

[1] parce que c'est gérable "inline" aussi. Par exemple, si foo.bar génère une exception, avec la ligne suivante, la variable prout prendra pour valeur "pouet" : prout = foo.bar rescue 'pouet'

jeudi 21 juin 2007

Rails : YAML et ActiveRecord (et SQL plus généralement)

S'est posé à moi le problème de transformer le contenu du fichier YAML lib/places.yml suivant en lignes SQL représentatives :

- USA:
  - California:
    - Los Angeles Area
    - San Diego Area
- Europe:
  - France:
    - Ile-de-France
    - Aquitaine:
      - Gironde:
        - Bordeaux
    - Alsace
  - Poland:
    - Mazowieckie:
      - Warszawa

..., fichier yaml qui devient :

+----+------------------+-----------+
| id | name             | parent_id |
+----+------------------+-----------+
|  1 | USA              |         0 | 
|  2 | California       |         1 | 
|  3 | Los Angeles Area |         2 | 
|  4 | San Diego Area   |         2 | 
|  5 | Europe           |         0 | 
|  6 | France           |         5 | 
|  7 | Ile-de-France    |         6 | 
|  8 | Aquitaine        |         6 | 
|  9 | Gironde          |         8 | 
| 10 | Bordeaux         |         9 | 
| 11 | Alsace           |         6 | 
| 12 | Poland           |         5 | 
| 13 | Mazowieckie      |        12 | 
| 14 | Warszawa         |        13 | 
+----+------------------+-----------+

..., contenu qui sera facilement utilisable, notamment avec acts_as_tree.

Voici la (très petite) classe que j'ai créé pour l'occasion (lib/yaml_to_ar.rb):

 require 'yaml'
 class YAML_to_AR


   def initialize(file)
     @data = File.open(file) { |yf| YAML::load( yf ) }
   end


   def insert(with_class, parent_id = 0, data = @data)
     if data.is_a?(Array)
       data.each do |value|
         insert(with_class, parent_id, value)
       end
     elsif data.is_a?(Hash)
       data.each do |key, value|
         new_line = with_class.create(:name => key, :parent_id => parent_id)
         insert(with_class, new_line.id, value)
       end
     elsif data.is_a?(String)
        with_class.create(:name => data, :parent_id => parent_id)
     end
   end


 end

Classe qui s'utilise simplement dans une migration, comme ceci par exemple (@ db/migrate/003_create_places.rb) :

 class CreatePlaces < ActiveRecord::Migration
   def self.up
     create_table :places do |t|
       t.column :name, :string
       t.column :parent_id, :integer
     end

     require 'lib/yaml_to_ar'
     loading = YAML_to_AR.new('lib/places.yml')
     loading.insert(Place)

   end

   def self.down
     drop_table :places
   end
 end

Ensuite, peut se poser la question de rajouter une méthode qui permette de modifier la table avec un fichier YAML du même style, se basant sur une sorte de "diff" entre les deux, mais vu que le problème ne s'est jamais présenté...

vendredi 15 juin 2007

Media Manager / Files Handler

Depuis que je me suis mis au Ruby on Rails, et donc initié au modèle MVC, j'ai toujours été stupéfait de voir un grand nombre de développeurs "gérer" les fichiers externes, envoyés par les internautes, dans leur controller ou leur model.

La logique même de séparation concepts différents aurait dû, selon moi, les inciter à créer des "medias manager", ou sortes de classes/modules pour gérer ces fichiers externes, de leur naissance à leur destruction.

N'ayant pas trouvé ce que je cherchais, j'ai créé il y a quelques mois un couple FileHandler/ImageHandler que j'ai étendu par la suite pour gérer les sons et vidéos. N'ayant depuis jamais encore trouvé de meilleure solution, j'aimerais bien savoir ce que vous en pensez. Voici donc une courte présentation de tout cela :
media manager rails
Et voici un exemple d'utilisation concret, une fois que les fichiers ont bien été 'required' comme il se doit :
in the view (app/views/photos/new.rhtml) :

<% form_for(:photo, :url => photos_path, :html => {:multipart => true}) do |f| %>
  <%= error_messages_for(:photo) %>
  <%=mff 'Sélectionnez le fichier à envoyer', file_field_tag(:file) %>
  <%=mff 'Description (facultatif)', f.text_area(:description) %>
  <p class="submit"><%= submit_tag('Envoyer cette photo »»') %></p>
<% end %>

in the controller (app/controllers/photos_controller.rb) :

class PhotosController < ApplicationController
#[...]
  def create
    @photo = Photo.create(params[:photo])
    @photo.store(params[:file])
    if @photo.save
      flash[:notice] = "Nouvelle photo enregistrée."
      redirect_to :action => 'new'
    else
      @photo.destroy
      render :action => 'new'
    end
  end
#[...]
end

in the model (app/models/photo.rb) :

 class Photo < ActiveRecord::Base
   before_destroy { |record| ImageHandler.delete_with_thumbnails(record.file_name) }

   def store(iostream)
     image = ImageHandler.new(iostream)
     begin
       image.store(self.id) # son nom de fichier sera son id + extension
     rescue
       @erreurs = $!.to_s # si une exception remonte l'ImageHandler ou du FileHandler, on l'ajoute à la liste d'erreurs de validations ActiveRecord
     else
       image.make_thumbnails 100, 150, 200, 250, 300 # chaque nombre représente le width d'un thumbnail de l'image qui sera fait
       update_attribute :file_name, image.raw_name # on rentre son nom dans la bdd
     end
   end

  protected
   def validate
     errors.add_to_base(@erreurs) if defined?(@erreurs) # l'ajout à la base se fait ici en réalité
   end
 end

dimanche 27 mai 2007

Atrasian v2(.0 ?)

Voilà un moment (presque un an?) que j'avais laissé atrasian à l'abandon, principalement par manque de temps et découragement du fait que le site en lui-même était mal fait, tant au niveau du code (c'était mon premier site rails!), de l'administration ou du concept.

(attention: les liens qui suivent sont NSFW)
Le mal est réparé, car le voilà de retour, cette fois proprement divisé en deux parties :

  1. le blog (php wordpress) présent sur http://(www.)atrasian.com
  2. la gallerie (rails de moi-même) présente sur http://gallery.atrasian.com

even boa is happy !

PS: je tiens à rajouter (en avance?) que je ne suis pas (si) stupide. Je sais très bien que l'extrème majorité du contenu présent sur ce site (et tous les sites du genre) est le résultat du miracle du maquillage, de la chirurgie esthétique et de photoshop réunis (ce qui n'empêche pas au résultat d'être admirable, imho).
Mais en faisant ce site, j'ai surtout pensé à mes statistiques qui bondissaient à chaque fois que je prononcais "jun natsukawa" ou "yuko ogura".
Ce site existe donc seulement parce que je n'arrive pas à rester insensible à l'appel des stats (qui va de pair avec l'appel des dollars :-))

mercredi 23 mai 2007

... et pendant que j'y suis ...

Dernièrement, floptwo et moi avons réalisé le site (Rails powered) d'un client. Bon autant le dire tout de suite, le design n'est pas vraiment comme l'on aurait aimé, ni l'organisation de certains élements, mais bon...

Bon alors c'est un site antillais tourné vers les antillais, où l'on peut envoyer des vidéos, sons, images et news, les tagguer, les commenter... Le client, qui produit aussi du contenu audiovisuel, gère tout cela.

http://gwadaxion.com

Voilà.

Pendant que j'y pense ...

Je vient d'ouvrir un nouveau site de petites annonces (Rails powered), pour toute la France (et même un peu plus) cette fois.

http://kolibriannonces.com

Pas beaucoup de fonctions, c'est facile et fonctionnel, il y a des fils rss partout (même sur les recherches), le design très vite fait sent bon.

Voilà.

samedi 28 avril 2007

Rails : Sérialisation de Hash pour base de donnée

J'ai découvert par hasard ceci :

Saving arrays, hashes, and other non-mappable objects in text columns
Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method serialize. This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:

 class User < ActiveRecord::Base
   serialize :preferences
 end

 user = User.create(:preferences => { "background" => "black", "display" => "large" })

 User.find(user.id).preferences # => { "background" => "black", "display" => "large" }

Une dé/sérialisation de données aussi aisée ? J'aime.

mardi 17 avril 2007

Réfléchir avant de coder

Avant, je réfléchissais avant de faire un site.

Je viens de me rendre compte que si je réfléchissais deux fois plus longtemps, voire plus, perdais moins de temps.

C'est drôle la vie, des fois.

mardi 27 mars 2007

2007raisons.com

Je viens à l'instant d'ouvrir un nouveau site, http://www.2007raisons.com (RubyOnRails powered) dont voici la "définition" :

Qu'est-ce que 2007raisons.com ?
C'est un site permettant aux internautes de d'exprimer leur avis sur l'élection présidentielle française de 2007, du 22 avril puis du 6 mai.

Le concept
Plutôt que de proposer un sondage habituel sur les intentions de votes, ce qui n'a pas vraiment de sens visible pour les autres internautes, nous proposons un système tout à fait nouveau mais très efficace : nous invitons les internautes à dire pourquoi ils voteront pour un(e) candidat(e) en particulier, en une ligne et dans un maximum de 200 caractères.
Cette technique permet de savoir ce que pensent les électeurs de leur candidat(e), et de cerner ce qui, au-delà des autres raisons les pousse à effectuer ce choix.
De plus, nous proposons aussi à l'internaute de dire pourquoi il ne votera pas pour un(e) candidat(e), ce qui permet cette fois de cerner la caractéristique du candidat la moins séduisante selon l'internaute.

Quelques soient les raisons, aussi farfelues qu'elles pourront sembler, nous les conserverons avec soin, car pensons cette méthode vraiment efficace au point de tenir un pari, publiquement.

mercredi 14 mars 2007

Rails : Avoir des noms de jours/mois en français -- Override Dates

Ce qui suit permet de franciser les élements de Date et de les rendres disponibles dans les formats de sortie de Time.

Donc, avec table People et un champ created_at en datetime (que ActiveRecord renseignera automatiquement à la création de la ligne), l'on pourra faire Person.find(:first).created_at.to_s(:fr_long) ce qui donnera quelquechose comme mercredi 14 mars 2007 à 13h37. Ceci grace à ActiveRecord qui converti les champs SQL Date et DateTime en objets Time.

### config/environment.rb
# Include your application configuration below
[...]
require 'lib/date_overrides'
[...]
### lib/date_overrides.rb
Date::MONTHS.replace({'Janvier' => 1, 'Fevrier' => 2, 'Mars' => 3, 'Avril' => 4, 'Mai' => 5, 'Juin' => 6, 'Juillet' => 7, 'Aout' => 8, 'Septembre'=> 9, 'Octobre' =>10, 'Novembre' =>11, 'Decembre' => 12})
Date::DAYS.replace({'Dimanche' => 0, 'Lundi' => 1, 'Mardi' => 2, 'Mercredi' => 3, 'Jeudi'=> 4, 'Vendredi' => 5, 'Samedi' => 6})
Date::ABBR_MONTHS.replace({'jan' => 1, 'fev' => 2, 'mar' => 3, 'avr' => 4, 'mai' => 5, 'juin' => 6, 'juil' => 7, 'aou' => 8, 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' => 12})
Date::ABBR_DAYS.replace({'dim' => 0, 'lun' => 1, 'mar' => 2, 'mer' => 3, 'jeu' => 4, 'ven' => 5, 'sam' => 6})
Date::MONTHNAMES.replace [nil] + %w(Janvier Fevrier Mars Avril Mai Juin Juillet Aout Septembre Octobre Novembre Decembre )
Date::DAYNAMES.replace %w(Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi)
Date::ABBR_MONTHNAMES.replace [nil] + %w(jan fev mar avr mai juin juil aou sep oct nov dec)
Date::ABBR_DAYNAMES.replace %w(dim lun mar mer jeu ven sam)

class Time
  alias :strftime_nolocale :strftime

  def strftime(format)
    format = format.dup
    format.gsub!(/%a/, Date::ABBR_DAYNAMES[self.wday])
    format.gsub!(/%A/, Date::DAYNAMES[self.wday])
    format.gsub!(/%b/, Date::ABBR_MONTHNAMES[self.mon])
    format.gsub!(/%B/, Date::MONTHNAMES[self.mon])
    self.strftime_nolocale(format)
  end
end

# exemples de formats de date
Time::DATE_FORMATS[:fr_date] = '%d-%m-%y'
Time::DATE_FORMATS[:fr] = '%d-%m-%y %H:%M'
Time::DATE_FORMATS[:fr_long] = '%A %d %B %Y à %Hh%I'
Time::DATE_FORMATS[:frs] = '%d-%m-%y %H:%M:%s'

dimanche 4 mars 2007

Rails : Ré-ordonner des lignes ActiveRecord

RubyLogo EDIT: Merci à Bounga de m'avoir montré "the right way"... ça m'apprendra à pas asser fouiller dans la doc... En fait, ruby permet de réordonner les résultats comme il faut, de cette façon :

Image.find(:all, :order => 'title').sort_by(&:id)

Voilà, c'est tout... donc en fait le helper qui correspondrait pourrait être :

def reorder_results(result, by = :id)
  result.sort_by(&by)
end

Fin. Le reste du billet sert juste d'explication au pourquoi de la méthode, le code même qui suit étant caduque.


Aujourd'hui, nous allons essayer de palier un "manque" de la classe Array, en rapport avec ActiveRecord (hein?)

Si, après être passé dans un filtre relativement compliqué, vous avez une liste de résultats activerecord, dans un array, à afficher, sachez que vous ne pourrez pas la -ordonner "comme ça".
En effet, en imaginant que nous utilisons une table "images", Image.find(:all).sort nous dit que les Image ne sont pas comparables (NoMethodError: undefined method `<=>' for #<Image:0x409c6bec>), ce qui est le cas des String, Integer et autres constantes "habituelles" de Ruby.

Donc sans hacker le coeur de ActiveRecord, on peut arriver au même résultat en utilisant ma méthode 'reorder_results' comme ceci :

a_classer = Image.find(:all)
reclasses = reorder_results(a_classer, :title)

Je tiens à re-préciser que oui, montré comme cela, ça n'a strictement *aucunt interêt* (totally useless). Oui, on aurait pu faire Image.find(:all, :order => 'title desc') directement, mais :
Imaginez qu'a la place de "a_classer", vous ayez un array de Image, désordonnés, parce qu'issus de filtres de recherches "complexes" tels que "rechercher toutes les images dans toutes les sous-categories (<- récursif) de ImagesCategory.find(1337)".

Eh bien oui il faut réordonner tout cela, et c'est pour ça que reorder_results existe. Cette méthode permet d'ordonner les résultats par n'importe quoi, leur identifiant par défaut, et permet de les ordonner dans le sens inverse.

Exemple :

reorder_results(a_classer, :title, true)

... ordonnera par titre et inversera l'ordre des résultats.

Le code commenté

Une fois n'est pas coutume, je vais décomposer et commenter mon code :

- Déclaration de la méthode, un argument obligatoire, deux facultatifs avec :id et false comme valeurs par défault

 def reorder_results(result, by = :id, reverse = false)

- Pour chaque élément de result :
- On met la valeur du champ line.send(by) (Voir Object#send) par lequel on veut trier dans la variable line_by, sauf si cette valeur est nil (ce qui arrive uniquement quand le champ SQL est à NULL)
- Retourne la valeur de line_by
- Applique un Array#sort sur la liste de résultats retourné, ce qui classe tous les objets comparables : String, Integer, Float et Time sont les seuls suceptibles de contenir la valeur d'un champ SQL par ActiveRecord.
- Met le tout dans determinants

   determinants = result.map {|line| 
     line_by = line.send(by).nil? ? '' : line.send(by)
     line_by
   }.sort

- Comme ça se lit : Inverse l'ordre de l'array determinants à moins que reverse soit égal à false

   determinants.reverse! unless reverse == false

- Prends l'array des résultats passés
- Selectionne son premier élement
- Selectionne sa Classe
- Met cette dernière dans object

   object = result.first.class

- Crée un array vide

   ordered = []

- Pour chaque element de determinants :
- On passe à l'object (object) "l'argument" find_by_(la-variable-by) que l'on converti en Symbol à qui l'on envoie "l'argument" determinant
- Donc, si l'objet était un Image et by valait :age, avec determinant = 17, par exemple, ce se situe après "<<" serait équivalent à : Image.find_by_age(17)
- Avec '<<', l'on ajoute ce résultat (un Image donc) à l'array ordered

   determinants.each do |determinant|
     ordered << object.send("find_by_#{by}".to_sym, determinant)
   end

- On renvoie la variable ordered

   ordered

- Fin (ouf)

 end

... ce qui donne si l'on reprends tout :

 def reorder_results(result, by = :id, reverse = false)
   determinants = result.map {|line| 
     line_by = line.send(by).nil? ? '' : line.send(by)
     line_by
   }.sort
   determinants.reverse! unless reverse == false
   
   object = result.first.class
   ordered = []
   determinants.each do |determinant|
     ordered << object.send("find_by_#{by}".to_sym, determinant)
   end
   ordered
 end

Améliorer la classe Array

Ah oui, c'est effectivement ce que j'ai dit au tout début de ce billet...
Je voulais dire par là que l'on pourrait surcharger la classe Array (ce qui n'a rien de tordu en soi) en lui rajoutant cette méthode (un peu modifiée pour que ça passe), ainsi, l'on pourrait faire quelquechose comme my_reordered_array = my_disordered_array_of_AR_results.reorder_results(:title).

Vite, du coca, je crève de soif.

jeudi 1 février 2007

Rails: afficher un <select> d'un élément utilisant acts_as_tree

RubyLogo acts_as_tree est un petit plugin inclu dans rails permettant de donner un comportement en arbre des élements d'un model (voir son api), ce qui est très utile pour les catégories, entre autres.

Il n'y a en revanche rien de pré-fabriqué pour afficher ces lignes de la bonne façon, outre ceci qui se contente de l'afficher en liste HTML.

Il me fallait un <select> organisé de la même façon.

J'ai donc écrit le code suivant, qui est à placer dans vos helpers (app/helpers/application_helper.rb afin d'être actif partout), qui vous permettra, dans un formulaire, d'utiliser ceci :

<% form_for :post, :url => posts_path do |f| %>
<%= f.select :category_id, options_for_categories(Category.find(:all)) %>
<% end %>

... ce qui vous donnera quelque-chose comme cela :

<select id="post_category_id" name="post[category_id]">
<option value="5">Linux</option>
<option value="6">--ubuntu</option>
<option value="9">----kubuntu</option>
<option value="10">----xubuntu</option>
<option value="7">--redhat</option>
<option value="8">----fedora</option>
<option value="12">BSD</option>
<option value="14">--FreeBSD</option>
</select>

Le code à insérer dans votre helper est le suivant :

 def options_for_categories(categories)
   ret = []
   for category in categories
     if category.parent_id == 0
       ret << [category.title, category.id]
       ret += options_for_subcategories(category)
     end
   end
   ret
 end

 def options_for_subcategories(category, level='')
   ret = []
   if category.children.size > 0
     level += '--'
     category.children.each do |subcat|
       ret << [ level + subcat.title, subcat.id]
       if subcat.children.size > 0
         ret += options_for_subcategories(subcat, level)
       end
     end
   end
   ret
 end

Enjoy.

lundi 22 janvier 2007

Rails : with_scope :find => {} do

RubyLogo Je tenais à poster sur une méthode méconnue de ActiveRecord nommée with_scope

Imaginez :
Dans notre site, qui contient des articles modérés qui appartiennent à des auteurs, nous faisons souvent appel (dans nos controllers) à une sélection des articles validés, avec différentes conditions impliquées. Par exemple :

Article.find(params[:id], :conditions => 'statut = 1')
# ou encore, pour vérifier si l'article (validé) appartient bien un auteur
Article.find(params[:id], :conditions => ['statut = 1 and auteur_id = ?', params[:auteur]])

C'est dans ces conditions que with_scope va nous sauver de ces nombreuses répétitions, qui enfreignent le motto DRY. Dans le model de l'article, nous rajoutons ceci :

 def self.find_active(*args)
   with_scope :find => { :conditions => 'statut = 1'} do
     find(*args)
   end
 end

Ainsi, vous pouvez désormais utiliser :

Article.find_active(params[:id])

Ce qui fait que with_scope est plus puissant qu'un simple merge d'arrays (d'arguments ou d'hashs (de conditions), c'est qu'il permet de fusionner vraiment les conditions. Donc, nous pouvons faire ce genre choses :

Article.find_active(params[:id], :conditions => ['categorie_id = ?', params[:categorie]])

... ce qui fusionnera les conditions 'statut = 1' et ['categorie_id = ?', params[:categorie]] bien comme il faut.

MAIS.

Oui, il y a un mais. En fait, on peut faire mieux que le dernier exemple, surtout si vous ne faites pas ce genre de choses conditions souvent (plus de 3 fois) :

Article.find_by_id_and_categorie_id_and_statut(params[:id], params[:categorie], 1)

Ici, se trouve la puissance des "dynamics finders" ActiveRecord, qui permettent de chercher en impliquant directement le nom des champs dans le nom de la méthode, ce qui a le mérite d'être clair et facile à comprendre, tout en restant souple. Autre exemple pour les yeux :

Person.find_all_by_island_and_type_and_genre_and_sexy('Guadeloupe', 'girl', 'open minded', true)

:-)

Notez enfin la différence notable (wow, "noter la différence notable" ...) entre find_by qui retourne un seul résultat et find_all_by qui retourne un array de résultats.

jeudi 18 janvier 2007

Rails 1.2.1 est de sortie \o/

RubyLogo C'est le changeset 5984 qui a porté la dernière pierre à l'édifice.

Posts de DHH :

Je prédis un grand nombre de posts sur le sujet très bientôt sur la planet rails

YEAH !

mercredi 20 décembre 2006

Mon environnement de developpement web

NB: La lecture de ce post pré-suppose que vous sachiez ce qu'est le motif de conception MVC, vim et screen

Physiquement

Une chaise, une table, un hp pavilion 17", une clavier PC105 *SIMPLE*, une logitech.
Porte fermée, fenetres ouvertes seulement la nuit, noir complet sauf lumière de l'écran, casque sur les oreilles, c'est pour moi l'ambiance idéale pour un devel rapide et efficace. Dans ces conditions, si quelqu'un entre dans ma chambre, en plein dans mon champ de vision, et me parle, je ne l'entends/vois même pas. Parfait.

Technographiquement [1]

Je développe exclusivement sur mon serveur distant (eva), via l'habituel couple ssh/screen/[bash,vim]. C'est ici que ça devient intéressant : Comment optimiser ses multi-fenêtres vim, ses 10 fenêtes de screen [2] et ses 1280*1024 pixels sur chacun des 4 bureaux (au moins) ?

Les fenêtres screen et vim

Je suis arrivé à une certaine stabilité sur les 5 premières fenêtres de screen :
0 => irssi (avec christophe) comme user)
1 => serveur lancé en background + affichage des logs du serveur (tail -f log/*)
2 => vim avec d'ouvert 2 ou 3 controlleurs, plus l'ApplicationController en première fenêtre
3 => vim avec d'ouvert les vues sur lesquelles je travaille en parallèle
4 => polyvalent (bash+vim), sert pour éditer les fichiers moins souvents modifiés, tels les models, les libs (lib/ ) ou les helpers

Les bureaux, gnome-terminal et firefox

screenshots du bureau 1, et du bureau 2

Ces arrangements sont suceptibles de sauter à la moindre Grande Réforme du code (ce qui arrive assez souvent quand l'on apprends à se familiariser avec un nouveau langage (ruby), un nouveau design pattern (mvc), un nouveau framework (ruby on rails).

PS: Le fond d'écran a été gracieusement créé et fourni par floptwo

Notes

[1] techniquement + graphiquement (©® myself)

[2] je ne dépasse par les 10 par pur principe

mercredi 13 décembre 2006

Je suis un artiste

Le développeur est un artiste :

Le mot art vient du latin ars (habileté, métier, connaissance technique). Le terme grec équivalent, techne (τεχνη), a évolué en sens contraire, ne conservant que le sens de technique. On retrouve ici la classique évolution littéraire des racines latines et scientifique des racines grecques.

Philosophiquement, l'art se définit par sa dimension esthétique : il est une création d'œuvres visant à susciter une appréciation esthétique positive, c'est-à-dire à plaire et à toucher la sensibilité par leur seule forme, par leur seule apparence.

jeudi 23 novembre 2006

Ruby on rails : Écrire ses input text (encore plus) simplement

RubyLogo Quand j'écris un formulaire, j'ai pris l'habitude d'écrire mes entrées de texte[1] autour du shéma suivant :

<p><label>%s: %s</label></p>

Ainsi, pour demander un "descriptif de la location", je suis contraint d'écrire ceci [2]:

<p><label>Descriptif de la location: <%= text_field "form", "descriptif_de_la_location" %></label></p>

... ce qui enfreint la règle du Don't Repeat Yourself, et qui est fatiguant tout simplement, lorsque l'on est confronté à plus de 5 inputs du genre.

J'ai donc rajouté ceci à mes helpers (dans app/helpers/application_helper.rb) :

 def winput(input_name, options={})
   pre_options = {
     :markup_scheme => "<p><label>%s: %s</label></p>",
     :text => input_name.capitalize.gsub('_',' '),
     :form_name => 'form',
     :options => {}
   }
   o = pre_options.merge(options)
   markup = text_field o[:form_name], input_name, o[:options]
   return sprintf(o[:markup_scheme], o[:text], markup)
 end

Cet helper me permet de faire exactement la même chose qu'en haut en écrivant seulement :

<%= winput "description_de_la_location" %>

Comme vous le constatez, vous pouvez changer le nom du formulaire, le "markup scheme" (j'ai rien trouvé de mieux sur le coup), et le texte qui va avec. Aussi, les options habituelles du text_field peuvent être aussi passées par le symbol du même nom. Exemple :

<%= winput 'login', :form => 'user', :text => 'Desired login', :options => {:size => 30} %>

... ce qui donnera :

<p><label>Desired login: <input id="user_login" name="user[login]" size="30" type="text" /></label></p>

EDIT (25/11/06) : Je vais vous épargner le code ruby correspondant, mais j'ai un peu amélioré le code afin (entre autres) d'arriver à ce que ceci :

 <% $form_name = 'location' %>
 <%= wtextarea 'descriptif_de_la_location' %>
 <%= wtextarea_f 'situation_geographique' %>
 <%= wtextarea 'tarifs' %>
 <%= winput 'a_partir_de', :text => 'Votre plus bas tarif toutes périodes confondues (en euro)', :after => '€' %>
 <%= radios = radio_button('location', 'animaux_admis', 1, :checked => 'true') + "Oui " + radio_button('location', 'animaux_admis', 0) + "Non"
 markup_scheme 'Les animaux sont-ils admis ?', radios %>

... me sorte cela :

 <p><label>Descriptif de la location :<br /> <textarea cols="40" id="location_descriptif_de_la_location" name="location[descriptif_de_la_location]" rows="20"></textarea></label></p>
 <p><label>Situation geographique (facultatif):<br /> <textarea cols="40" id="location_situation_geographique" name="location[situation_geographique]" rows="20"></textarea></label></p>
 <p><label>Tarifs :<br /> <textarea cols="40" id="location_tarifs" name="location[tarifs]" rows="20"></textarea></label></p>
 <p><label>Votre plus bas tarif toutes périodes confondues (en euro) : <input id="location_a_partir_de" name="location[a_partir_de]" size="30" type="text" value="0" />€</label></p>
 <p><label>Les animaux sont-ils admis ? : <input checked="true" id="location_animaux_admis_1" name="location[animaux_admis]" type="radio" value="1" />Oui <input id="location_animaux_admis_0" name="location[animaux_admis]" type="radio" value="0" />Non</label></p>

L'idée de départ étant d'adapter la méthode à vos besoins, et celon ce qui vous parait pratique. Perso, j'aime.

Notes

[1] Avec le helper text_field 99% du temps

[2] Petites précisions pour les non-utilisateurs de rails : le fait de donner un nom au formulaire dans chaque champ permet de faire la chose suivante newloc = Location.new(params[:form]) pour précharger directement la valeur des champs liés au formulaire, et après rajout d'autres valeurs (newloc.ip_adress = request.remote_ip par exemple), de terminer par un joli newloc.save pour exécuter la requete SQL qui va bien.

mercredi 22 novembre 2006

Apache : Stupid htaccess Tricks

(via koke's weblog)

Pas de blabla, que du bon : http://perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/

Pages: 1 - 2 - 3 - Page suivante >>