Une solution pour réduire la consommation d’énergie

Il y a quelques jours Nicolas Hulot était l'invité du Grand Journal et a exposé une idée pour limiter la consommation d'énergie que je trouve à la fois juste et simple à mettre en place.

Il s'agit selon lui d'instaurer un prix de l'énergie variable.

Aujourd'hui nous sommes dans un modèle de consommation de masse ; où plus j'achète et plus le coût à l'unité diminue.

L'idée serait de mettre en place l'inverse, c'est à dire d'avoir un prix de l'énergie exponentiel, plus je consomme d'énergie et plus celle ci me coûte cher à l'unité.

Voilà à mon sens les conséquences d'un tel raisonnement:

  • Taxer les plus riches qui veulent continuer à vivre comme tel au dépend de la planète.
  • Diminuer le prix du ticket d'entrée d'accès à l'énergie (prix de base plus faible).
  • Réduire la consommation globale d'énergie et donc d'émission de gaz à effet de serre.

Aujourd'hui j'ai du mal à croire en la responsabilité citoyenne. Sans une carotte les gens (je m'inclue volontiers) n'agissent pas. Ce n'est pas forcément par manque de volonté mais parce qu'il est difficile de percevoir le fruit de ses efforts. On a du mal à distinguer les implications de nos actions au jour le jour.

Bien entendu avoir une formule mathématique de type exponentiel risque de transformer les factures d'électricité en vrai casse tête mais pour simplifier on peut imaginer un système de palier.

Dans ce système reste à définir une base de consommation par citoyen réaliste, sachant que notre niveau de consommation est aussi variable selon notre âge.

Bref, on en a bien profité mais il va falloir commencer à se serrer la ceinture dude !

Ecriture d’un DSL en Ruby

Résistance sociale & langage de script

Vues et layouts avec Haml, Erb et Markaby

rubyDans la version 0.6.2 de Capcode, qui devrait être disponible dans quelques jours, j’ai ajouté la possibilité d’utiliser des layouts1. Pour cela j’ai fait un plongeon un peu plus profond dans les entrailles d’Erb, Haml et Markaby. Sans vous assommer avec Capcode, regardons comment implémenter cela facilement dans un projet fictif.

Avant de commencer…

L’idée générale de ce qui va suivre est de faire, quelque soit le moteur de rendu que nous préférons, toujours à peu prêt la même chose. Je dis à peu prêt, car si avec Haml et Erb, il semble logique d’utiliser des fichiers pour la partie vue+layout, ce n’est pas le cas avec Markaby. Quoi qu’il en soit, nous allons créer une base de framework en faisant en sorte que l’utilisation de la méthode de rendu choisie diverge le moins possible entre les trois possibilités.

Partons de ce qui est fait en Rails. Si nous générons un nouveau contrôleur contenant deux actions, nous obtenons, dans app/controllers une classe qui ressemble à ceci :

class MonControllerController < ApplicationController
  def ActionUne
  end
 
  def ActionDeux
  end
end

Par défaut, le rendu de ActionUne se fait via le fichier app/views/mon_controller/ActionUne.html.erb et celui de ActionDeux se fait via le fichier app/views/mon_controller/ActionDeux.html.erb

Nous allons nous calquer sur une solution similaire. Pour cela nous allons créer une classe Controller dont héritera notre contrôleur. Dans les actions de ce contrôleur (définies comme des méthodes) nous expliciterons la méthode de rendu. Tout ceci nous donnera quelque chose comme cela :

class MonApp < Controller
  def test( arg )
    # ...
    render_XXX( *params )
  end
end

Notre objectif étant de proposer trois méthodes de rendu (Erb, Haml et Markaby), nous allons créer les trois méthodes suivantes :

  • render_erb( vue, layout )
  • render_haml( vue, layout )
  • render_markaby( vue, layout )

Haml

Le Haml (XHTML Abstraction Markup Language) est un langage de balisage utilisé pour décrire simplement le XHTML d’une page internet sans utiliser les traditionnelles lignes de code.2

Je ne m’étendrai pas sur la syntaxe Haml et laisse le soin à ceux qui ne l’ont jamais utilisé de parcourir la documentation. La chose essentielle à savoir c’est que l’inclusion de code se fait via le helper yield. Par exemple, si nous avons la vue suivante :

%p "Bonjour le monde!"

et que nous voulons l’inclure dans le layout suivant, nous utiliserons le helper yield à l’emplacement ou nous souhaitons faire l’inclusion de la vue :

%html
  %body
    %h1 "Welcome!"
    = yield

Ainsi, nous obtiendrons (virtuellement) ceci :

%html
  %body
    %h1 "Welcome!"
      %p "Bonjour le monde!"

Qui sera donc transformé en HTML comme ceci :

<html>
  <body>
    <h1>"Welcome!"</h1>
    <p>Bonjour le monde!</p>
  </body>
</html>

La transformation de code Haml en HTML est très simple à faire :

Haml::Engine.new( haml ).to_html( )

haml contient le code à transformer. Si dans ce code nous voulons utiliser des variables, nous avons plusieurs solutions. La première consiste à les déclarer en paramètre de la méthode Haml::Engine.to_html. Ainsi, si dans notre code Haml nous voulons utiliser une variable ma_variable nous pouvons utiliser la syntaxe suivante :

Haml::Engine.new( "%p= ma_variable" ).to_html( nil, : ma_variable => "Hello" )
# => "<p>Hello</p>\n"

Cette solution est élégante, mais peu pratique, car nous ne connaissons pas forcément toutes les variables utilisées dans le code Haml. Les plus attentifs auront remarqué le passage de l’objet de type NilClass passé en premier paramètre de Haml::Engine.to_html. Ce premier paramètre est en fait l’objet de contexte dans lequel est évalué le template Haml. Donc nous pouvons également faire cela :

@ma_variable = "Hello"
Haml::Engine.new( "%p= @ma_variable" ).to_html( self )
# => "<p>Hello</p>\n"

Si nous savons enfin que Haml::Engine.to_html peut également prendre un bloc en paramètre, nous imaginons très facilement comment utiliser un layout :

Haml::Engine.new( layout ).to_html(self) { Haml::Engine.new( vue ).render(self) }

layout contient le template Haml pour le layout et vue le template de la vue.

Nous pouvons donc très facilement faire l’implémentation dans notre pseudo-framework :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rubygems'
require 'haml'
 
module Helper
  def render_haml( f, l = nil )
    if( !l.nil? and File.exist?( l ) )
      Haml::Engine.new( open( l ).read ).to_html(self) { 
        Haml::Engine.new( open( f ).read ).render(self) 
      }
    else
      Haml::Engine.new( open( f ).read ).to_html( self )
    end
  end
end
 
class Controller
  include Helper
end

Comme vous pouvez le voir, nous passons en paramètre de render_haml le nom du fichier pour la vue et celui du layout.

Pour tester ce code, il suffit de créer ces deux fichiers :

page.haml

%p= @message

layout.haml

%html
  %body
    %h1 "Welcome!"
    = yield

Nous avons également besoin d’une petite classe héritant de la classe Controller :

class Pipo < Controller
  def test_haml( message )
    @message = message
    render_haml( "page.haml", "layout.haml" )
  end
end
 
puts Pipo.new().test_haml( "OK avec Haml!" )

Erb (ou eRuby)

eRuby est un système de template qui permet d’embarquer du code Ruby dans un document texte.3

Tout utilisateur de Rails est ici en terrain connu puisqu’eRuby est le système de template utilisé par défaut. L’utilisation d’un layout se fait, ici aussi, via un yield. Donc, si nous reprenons le même exemple que celui utilisé avec Haml, avec ce template comme layout :

<html>
  <body>
    <h1>"Welcome!"</h1>
    <%= yield %>
  </body>
</html>

Et ce template comme vue :

<p>Bonjour le monde!</p>

Nous obtiendrons le code suivant :

<html>
  <body>
    <h1>"Welcome!"</h1>
    <p>Bonjour le monde!</p>
  </body>
</html>

La transformation d’un template Erb ressemble fortement à ce que nous avons vu avec Haml :

ERB.new( erb ).result()

Si en plus nous utilisons des variables dans le template, nous devons passer le contexte d’exécution à la méthode Erb.result. La grande différence avec Haml vient du fait qu’avec Erb, ce contexte est soit un objet Proc soit un objet Binding. Nous retiendrons la seconde solution :

ma_variable = "Hello"
ERB.new( "<p><%= ma_variable %></p>" ).result( binding )
# => "<p>Hello</p>"

Nous utilisons donc Kernel#binding comme contexte, qui nous renvoie l’objet de type Binding au point d’appel.

Pour mettre en place la gestion des layout, nous allons devoir jouer avec l’objet Binding. En effet, rien dans Erb ne permet d’utiliser des blocs. Nous allons donc devoir le faire évaluer via l’objet Binding. Si vous regardez la documentation de Kernel#binding, vous verrez comment faire évaluer une variable via l’objet Binding :

def getBinding(param)
  return binding
end
b = getBinding("hello")
eval("param", b)   #=> "hello"

Nous allons utiliser la même méthode pour un bloc :

def getBinding
  binding
end
 
b = getBinding { "hello" }
eval( "yield", b )
# => "hello"

Nous savons donc maintenant comment utiliser un layout avec Erb :

def getBinding
  binding
end
 
ERB.new( layout ).result( getBinding { 
  ERB.new( vue ).result(binding) 
} )

Nous pouvons donc faire l’implémentation de la méthode de rendu pour Erb dans notre pseudo-framework :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
require 'erb'
 
module Helper
  def getBinding
    binding
  end
 
  def render_erb( f, l = nil )
    if( !f.nil? and File.exist?( l ) )
      ERB.new(open(l).read).result( getBinding { 
        ERB.new(open(f).read).result(binding) 
      } )
    else
      ERB.new(open(f).read).result(binding)
    end
  end
end
 
class Controller
  include Helper
end

Nous pouvons maintenant créer le fichier pour la vue :

page.rhtml

<p><%= @message %></p>

Le fichier du layout :

layout.rhtml

<html>
  <body>
    <h1>Welcome!</h1>
    <%= yield %>
  </body>
</html>

Puis faire un test :

class Pipo < Controller
  def test_erb( message )
    @message = message
    render_erb( "page.rhtml", "layout.rhtml" )
  end
end
 
puts Pipo.new().test_erb( "OK avec Erb!" )

Markaby

Markaby est un petit bout de code permettant d’écrire des pages HTML en pur Ruby.4

La grosse différence avec Haml et Erb, c’est qu’avec Markaby, nous allons écrire nos vues et layouts en Ruby. Ainsi, notre layout aura la tête suivante :

def layout
  html do
    body do
      h1 "Welcome!"
      yield
    end
  end
end

Et la vue aura la forme suivante :

p "Bonjour le monde!"

Ce qui devra permettre d’obtenir le code suivant :

<html>
  <body>
    <h1>"Welcome!"</h1>
    <p>Bonjour le monde!</p>
  </body>
</html>

Le passage de Markaby à HTML se fait simplement en passant le bloc de code Markaby au constructeur de l’objet Markaby::Builder puis en utilisant la méthode Markaby::Builder.to_s

Markaby::Builder.new {
  html do
    body do
      p "Hello"
    end
  end
}.to_s
# => "<html><body><p>Hello</p></body></html>"

Pour l’utilisation de variables dans le code Markaby, nous pouvons utiliser les mêmes méthodes que celles proposées par Haml. A savoir, soit le passage de variables déclarées sous forme de Hash en paramètre du constructeur :

Markaby::Builder.new( {:ma_variable => "Hello"} ) { p ma_variable }.to_s
# => "<p>Hello</p>"

Soit en précisant le contexte d’exécution :

@ma_variable = "Hello"
Markaby::Builder.new( {}, self ) { p @ma_variable }.to_s
# => "<p>Hello</p>"

Le code Markaby n’étant rien d’autre que du code Ruby, l’utilisation de layout est donc très simple :

Markaby::Builder.new({}, self) { self.send( layout ) { self.send( vue ) } }.to_s

L’implémentation dans notre pseudo-framework devient donc aisée :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require 'rubygems'
require 'markaby'
 
module Views; end
 
class Markaby::Builder
  include Views
end
 
module Helper
  def render_markaby( f, l = nil )
    Markaby::Builder.new({}, self) { 
      if self.respond_to?(l)
        self.send(l.to_s) { self.send(f.to_s) }
      else
        self.send(f.to_s) 
      end
    }.to_s
  end
end
 
class Controller
  include Views
  include Helper
end

Comme vous pouvez le voir, nous incluons un nouveau module Views. C’est en effet dans celui-ci que nous définirons le code de nos vues et layouts. L’ajout des lignes 6 à 8 permet de s’assurer que les méthodes définies dans le module Views sont visibles dans le bloc passé au constructeur de Markaby::Builder. Enfin, nous devons également inclure le module Views dans la classe Controller.

Il ne reste plus qu’à tester :

class Pipo < Controller
  def test_markaby( message )
    @message = message
    render_markaby( :page, :layout )
  end
end
 
module Views
  def page
    p @message
  end
 
  def layout
    html do
      body do
        h1 "Welcome!"
        yield
      end
    end
  end
end
 
puts Pipo.new().test_markaby( "OK avec Markaby!" )

Oui, mais avec Rails… et patati, et patata!

Rails propose un système amusant permettant d’utiliser plusieurs yield dans un même layout. Pour savoir quoi faire pour chaque yield, il existe le helper content_for qui réagit en fonction du paramètre envoyé par yield. Ainsi avec le layout suivant :

<html>
  <head>
    <%= yield :head %>
  </head>
  <body>
    <%= yield :content %>
  <body>
</html>

Je peux m’amuser à créer les vues suivantes :

index.html.erb

<% content_for :head do %>
  <%= stylesheet_link_tag :style_index %>
  <title>Index page</title>
<% end %>
 
<% content_for :content do %>
  <h1>Index</h1>
  <p>Ma page d'index...</p>
<% end %>

other.html.erb

<% content_for :head do %>
  <%= stylesheet_link_tag :style_other %>
  <%= javascript_include_tag :defaults %>
  <title>Le titre de ma page</title>
<% end %>
 
<% content_for :content do %>
  <h1>Bla bla bla...</h1>
  <p>Une autre page...</p>
<% end %>

Vous avez compris le principe…

Et bien entendu, vous voulez pouvoir faire la même chose… Je ne vais pas pousser l’idée à fond et me contenter simplement de permettre de récupérer les paramètres du yield dans la vue.

Dans la version Haml, remplacez la ligne 7 à 9 par ceci :

7
8
9
10
      Haml::Engine.new( open( l ).read ).to_html(self) { |*args| 
        @__args__ = args
        Haml::Engine.new( open( f ).read ).render(self) 
      }

Dans la version Erb, remplacez les lignes 10 à 12 par :

10
11
12
13
      ERB.new(open(l).read).result( get_binding { |*args| 
        @__args__ = args
        ERB.new(open(f).read).result(binding) 
      } )

Dans la version Markaby, remplacez les lignes 12 à 18 par :

12
13
14
15
16
17
18
19
20
21
    Markaby::Builder.new({}, self) { 
      if self.respond_to?(l)
        self.send(l.to_s) { |*args| 
          @__args__ = args
          self.send(f.to_s) 
        }
      else
        self.send(f.to_s) 
      end
    }.to_s

Il suffit alors d’inspecter le contenu de la variable @__args__ dans les vues pour récupérer les valeurs passées au yield.

Si vous souhaitez voir tout cela en application, je vous renvoie au code des systèmes de rendu de Capcode

1 des schémas
2 Wikipedia
3 Wikipedia aussi…
4 Pas wikipedia

Ruby at ThoughtWorks

Observer Vs Callback

Il y a peu au boulot, j'ai indiqué ma désapprobation des Observeurs face au Callback. Je vais donc le coucher ici par écrit mon sentiment.

L'Observeur

Dans Rails, il y a au premier abord une fonctionnalité vraiment intéressante. L'Observeur. Grâce à lui, on peux définir une classe qui vérifie le comportement d'un model et effectue certaine action suite à ses observations. Il permet d'ajouter des événements avant/après l'enregistrement, la mise a jour ou la destruction d'un model.

Pour mettre en place un observeur, il suffit de créer une classe héritant de ActiveRecord::Observer, mettre son code dedans et la définir comme observeur dans le fichier environment.rb. Rien de plus simple et ça marche très bien.

Le Callback

Mais Rails a déjà intégré dans ses models, les fonctions de callback utilisé par le observeur. En effet, on peux tout à fait définir N action after_save ou before_create. Ces méthodes seront appelés à l'événement voulu.

Mais que choisir ?

C'est là où je dis que le callback est plus intéressant que l'observeur. En effet, un callback fait exactement la même chose qu'un Observeur. Mais lui au moins on sait qu'il est là. En ouvrant la classe on découvre le callback. Pour détecter un Observeur, il faut regarder les fichiers de config de Rails et ouvrir une à une les classes Observeurs.

Même le cas du nombre de ligne n'est pas réel car il est tout à fait possible de sortir ses callbacks dans des modules. De même pour une réutilisation sur plusieurs classes. Le module le permet sans problème.

Personnellement, je n'ai jamais constater un seul cas où l'observeur avait plus d'intérêt que des callback. Si vous en trouvez, je suis vraiment curieux.


Article original écrit par Cyril Mougel et publié sur Shiny happy people coding | lien direct vers cet article | Si vous lisez cet article ailleurs que sur Shiny happy people coding, c'est qu'il a été reproduit illégalement et sans autorisation.

Fin… et suite…

Voilà, le temps et venu. Je ferme définitivement ce blog pour me consacrer pleinement au suivant.

See you there.

Tiny Tiny Reia Web Server

devIl y a quelques mois, sur mon ancien blog, je vous proposais un petit bout de code montrant comment développer un mini serveur Web en Erlang. Aujourd’hui, je vous propose de comparer ce code avec son équivalent en Reia.

Avant de recopier le code ci-dessous, il faut savoir deux ou trois petites choses à partir de ce langage.

Premièrement, il ne supporte pas les tabulations ! C’est un peu énervant et je vous conseille donc, si ce n’est pas fait, de régler votre éditeur de code de façon à systématiquement remplacer les tabulations par des espaces. Ensuite, c’est encore un jeune langage (un peu plus d’un an) qui ne propose pas tout ce que l’on est en droit d’attendre d’un langage moderne. Cependant, étant bâti au dessus d’erlang, vous pouvez très facilement utiliser ce dernier dans votre code reia. Comme vous pouvez le voir, j’use et j’abuse de cette possibilité dans le code qui suit. Donc, vous lancer dans reia sans avoir la moindre notion d’erlang n’est pas forcement ce qu’il y a de plus simple1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
module HTTPServer
  def start()
    start(8080)
  end
 
  def start(port)
    case gen_tcp::listen(port, [:binary, (:active, false)])
    when (:ok, listenSocket)
      "HTTP server started on port #{port}".puts()
      loop(listenSocket)
    when error
      throw error
    end
  end
 
  def loop(listenSocket)
    case gen_tcp::accept(listenSocket)
    when (:ok, socket)
      Process.spawn { handle_connection(socket) }
      loop(listenSocket)
    when (:error, reason)
      throw reason
    end
  end
 
  def handle_connection(socket)
    try communication(socket)
    catch error
      throw error
    end
    ok = gen_tcp::close(socket)
  end
 
  def communication(socket)
    (:ok, binary) = gen_tcp::recv(socket, 0)
    (:ok, (address, _)) = inet::peername(socket)
 
    rTmp = binary.to_string().split(/\r\n/)
    result = /([^\s]*)\s*([^\s]*)\s*(.*)/.match( rTmp[0] )
    file = result[2].sub(/^\//, "")
 
    content = ""
 
    case file::read_file(file.to_atom())
      when (:ok, html)
        content = "HTTP/1.1 200 OK\r\nServer: Reia Server/1.0.0\r\n\r\n#{html.to_string()}"
      when (:error, reason)
        content = "HTTP/1.1 200 OK\r\nServer: Reia Server/1.0.0\r\n\r\n<html><body>404 error</body></html>"
    end
 
    case gen_tcp::send(socket, content.to_binary())
    when (:ok)
      true
    when (:error, reason)
      throw reason
    end
  end 
end
 
HTTPServer.start()

1 Je dis cela uniquement pour votre bien…

Vulnérabilité de type DoS dans la librairie BigDecimal

Une faille du type déni de service (DoS) a été révélée dans la librairie standard BigDecimal. La conversion des objets BigDecimal en Float ouvrait la voie à des erreurs de segmentations volontaires.

ActiveRecord se base sur cette classe, aussi la plupart des applications Rails sont elles touchées par ce bug, mais ce n'est pas une faille exclusive à Rails.

Description

Un attaquant peut provoquer un DOS en forçant BigDecimal à scanner un nombre immense, du type :

BigDecimal("9E69999999").to_s("F")

Versions touchées

branche 1.8

  • 1.8.6-p368 et toutes les versions précédentes
  • 1.8.7-p160 et toutes les versions précédentes

branche 1.9

  • Aucune des versions 1.9.1 n'est affectée

Solution

branche 1.8

Une mise à jour vers 1.8.6-p369 ou ruby-1.8.7-p173 règle le problème.

CapApbility.run

projetsLe projet CapApbility avance doucement. J’ai eu pas mal de ratés au départ. Initialement, je pensais faire du spécifique par plateforme. J’ai donc mis en place, avec succès, des applications sur Mac et Windows. Les premières utilisant une version de CapApbility en Cocoa et la seconde en C#. C’était presque trop facile puisqu’il ne s’agissait que de créer une simple fenêtre avec un composant browser, capable au préalable de lancer une application externe, d’afficher le contenu de la page principale du site une fois cette application externe lancée, et de fermer l’application (externe) lors de la fermeture de la fenêtre. Bref pas de quoi fouetter un chat, du simple NSTask dans un thread en Cocoa, et le génialement énervant couple System.Diagnostics.ProcessStartInfo / System.Diagnostics.Process sous Windows. Bref, vous l’aurez compris nous ne sommes pas dans le la haute voltige. L’exploit était presque plus d’avoir choisi des technologies non portables… En fait, plus qu’un exploit c’était une bêtise. Heureusement, elle est réparée P et j’ai donc porté mon développement sous XULRunner me permettant ainsi de gérer la partie interface via XUL et la partie code avec XPConnect.

Résultat des courses, j’ai une solution fonctionnelle.

Comme vous pouvez le voir, le lancement est un peu lent. Probablement parce que je trace pas mal de choses. Cela devrait donc se régler facilement.

Pour gérer le lancement du server de l’application, j’utilise nsIProcess avec XULRunner 1.9.1b, seule version gérant nsIProcess.kill(). Le statut de beta ne devrait perturber personne, car XULRunner 1.9.1 est le coeur de Firefox 3.5, dont la sortie est imminente. Mon seul regret vient du comportement d’nsIProcess sous Windows qui, tout comme System.Diagnostics.Process, ne peut pas lancer un process externe sans ouvrir une immonde fenêtre DOS.

Et la suite ?

Tout d’abord, un peu de refactoring du code (c’est fonctionnel, mais qu’est-ce que c’est moche !) avant de placer le code dans le dépôt SVN. Ensuite il faudra tester, tester, tester et encore tester. Tout cela en fabriquant les applications à la main. L’exemple ci dessous fonctionne sur les trois plateformes cibles, mais vu son haut niveau fonctionnel, je ne veux pas le considérer comme sérieux. Je testerai donc, entre autres, avec ceci. La dernière étape consistera à fabriquer un système de création des applications à la Prism.