af83

Structurez votre code Ruby

Pour continuer avec les structures de données présentes dans la bibliothèque standard de Ruby, après les Sets, je souhaite vous présenter les Struct. Cette structure permet de créer une sorte de classe légère avec quelques attributs.

Voyons un exemple :

Struct.new("Customer", :name, :address)
customer = Struct::Customer.new("Dave", "123 Main")
customer.name         # -> "Dave"
customer.address      # -> "123 Main"
customer.name = "Joe"
customer.name         # -> "Joe"

À la première ligne, on définit notre structure, avec d'abord son nom, suivi de la liste des attributs. Cette structure sera ensuite accessible via Struct::Customer. À la ligne suivante, on instancie un objet en lui passant les paramètres dans le même ordre que les attributs lors de la définition de la structure. Enfin, on peut utiliser les attributs sur cet objet comme pour une classe normale où ils auraient été définis avec un attr_accessor.

Une première propriété bien sympatique des Struct est de pouvoir accéder aux attributs comme si cet objet était un Hash :

Struct.new("Customer", :name, :address)
customer = Struct::Customer.new("Dave", "123 Main")
customer[:name]          # -> "Dave"
customer[:name] = "Joe"
customer.name            # -> "Joe"

Et l'autre caractérisque que j'apprécie particulièrement chez les Struct est que le constructeur renvoie la classe. Cela permet, par exemple, de l'assigner à une autre constante sans le namespace Struct:: :

Customer = Struct.new("Customer", :name, :address)
customer = Customer.new("Dave", "123 Main")

Dans ce cas, on peut également se passer de passer le nom de la structure en premier paramètre :

Customer = Struct.new(:name, :address)
customer = Customer.new("Dave", "123 Main")

Mais surtout, je l'utilise souvent pour hériter d cette classe. Voici un exemple pris depuis ma gem guide-em-up :

class Index < Struct.new(:root, :current_dir, :data_dir, :themes)

  def html
    file = File.join(data_dir, "/browser.erb")
    tmpl = File.read(file)
    Erubis::Eruby.new(tmpl).result(to_hash)
  end

# ...
end

Dans le même style, Ruby possède des OpenStruct, qui sont un mélange entre les Struct et les Hash. Voici un exemple d'utilisation :

require 'ostruct'
person = OpenStruct.new(:first_name => "John", :last_name => "Doe")
person.age = 42
puts "#{person.first_name} #{person.last_name} a #{person.age} ans."
# -> "John Doe a 42 ans."

Note : par contre, il n'est pas possible d'utiliser la syntaxe de type Hash pour accéder aux attributs d'un OpenStruct. Dommage…

Au final, on ne rencontre pas souvent Struct et OpenStruct quand on lit du code Ruby. Mais ils peuvent être bien pratiques, et c'est pourquoi, je pense que c'est une bonne idée de les connaître. Ils m'ont déjà rendu bien des services par le passé et j'espère que vous pourrez en dire autant dans quelques temps.

blog comments powered by Disqus