Monday, January 18, 2010

Smalltalk interactive tutorial

ProfStef est un tutorial intéractif sur Smalltalk (un peu inspiré de Try Ruby).
L'objectif est d'apprendre les bases du langage Smalltalk de manière ludique.

Pour charger ProfStef dans votre image, évaluez le code suivant dans un Workspace:

Gofer new
    squeaksource: 'ProfStef';
    package: 'ProfStef';
    load.



Sunday, January 10, 2010

Blog dédié à Pharo

Je viens de mettre en ligne un blog qui me servira à publier et pointer des tutoriels vidéo sur Pharo. Ça s'appelle Pharocasts et c'est ici: http://pharocasts.blogspot.com/

Friday, January 8, 2010

GUI et Pharo

J'ai fait une vidéo sur Pharo montrant les techniques de base pour disposer des éléments dans une fenêtre et répondre aux clics sur les boutons.



Voici un des exemples de code de la vidéo:

|aWindow aPanel buttonPanel|

aWindow := SystemWindow labelled: 'My first window'.

aPanel := PluggablePanelMorph new.
aWindow addMorph: aPanel fullFrame: (
    LayoutFrame
        fractions: (0@0 corner: 1@1)
        offsets: (0@0 corner: 0@50 negated)).
aPanel color: (Color blue).

buttonPanel := PluggablePanelMorph new.
aWindow addMorph: buttonPanel fullFrame: ( 
    LayoutFrame
        fractions: (0@0.99 corner: 1@1)
        offsets: (0@50 negated corner: 0@0)).
buttonPanel  color: (Color green).


#(one two three) do: [:label| |aButton| 
 aButton := PluggableButtonMorph new label: label; yourself.
 buttonPanel addMorph: aButton fullFrame: nil.
].


aWindow openInWorld.

Monday, January 4, 2010

Ruby 1.9, SQLite et UTF-8

Comme abordé précédemment dans le billet Migrer vers Ruby 1.9, le gem sqlite3-ruby actuel (version 1.2.5) ne fonctionne pas vraiment avec des données UTF-8.

Un fork de la version 1.2.4 qui corrige ces problèmes est disponible ici: http://github.com/qoobaa/sqlite3-ruby.

Pour l'installer, clonez d'abord le repository avec git:

git clone git://github.com/qoobaa/sqlite3-ruby.git

puis allez dans le répertoire créé et construisez le gem:

cd sqlite3-ruby
gem build sqlite3-ruby.gemspec

si tout fonctionne vous avez maintenant le gem sqlite3-ruby-1.2.6.gem. Installez-le:

gem install sqlite3-ruby-1.2.6.gem 

C'est tout pour Linux, sous Windows cela se complique étant donné que le gem intègre une extension C qu'il faut linker avec SQLite. Vous devriez donc tomber sur l'erreur:

Building native extensions.  This could take a while...
ERROR:  Error installing sqlite3-ruby:
        ERROR: Failed to build gem native extension.

ou si vous avec déjà installé le devkit:

checking for sqlite3.h... no

La suite nécessite d'avoir le devkit d'installé sur votre machine (voir http://rubyinstaller.org/download.html et http://wiki.github.com/oneclick/rubyinstaller/development-kit ).

Créez un répertoire qui contiendra les fichiers nécessaires à la compilation de l'extension, à savoir sqlite3.h (dans le sous-répertoire include) et sqlite3.dll (dans le sous-répertoire lib). Par exemple:

C:\Ruby19\sqlite3
            |- include
            |   |- sqlite3.h
            |- lib
                |- sqlite3.dll 

Le fichier sqlite3.h se trouve dans les sources de SQLite: http://www.sqlite.org/sqlite-amalgamation-3_6_21.zip

Le fichier sqlite3.dll se trouve dans la distribution binaire pour Windows: http://www.sqlite.org/sqlitedll-3_6_22.zip

Modifiez ensuite la configuration de la compilation de l'extension pour inclure le répertoire créé. Ouvrez le fichier ext/sqlite3_api/extconf.rb des sources du gem et ajoutez la ligne suivante:

dir_config("sqlite3", "C:\\Ruby19\\sqlite3")

Vous pouvez maintenant regénérer le gem et l'installer:

gem build sqlite3-ruby.gemspec
gem install sqlite3-ruby-1.2.6.gem 

Wednesday, December 30, 2009

Migrer vers ruby 1.9

Je viens de migrer deux applications Rails 2.3.5 vers Ruby 1.9.1 avec deux problèmes majeurs concernant les encodings. Bien que Ruby soit unicode par défaut, pas mal de gems ne parlent pas l'UTF-8 par défaut...

Premier soucis avec ERB qui compile les templates en utilisant ASCII-8BIT par défaut. Cela génère l'erreur suivante:
ActionView::TemplateError (incompatible character encodings: ASCII-8BIT and UTF-8)

Il y a pas mal de discussions sur le sujet ici: https://rails.lighthouseapp.com/projects/8994/tickets/2188-i18n-fails-with-multibyte-strings-in-ruby-19-similar-to-2038

Une solution hacky à coup de monkey patch est de créer un fichier lib/actionview_utf8 comme ceci (c'est la ligne avec le source.force_encoding qui est rajoutée au code original):

module ActionView
  module Renderable #:nodoc:
    private
      def compile!(render_symbol, local_assigns)
        locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join

        source = <<-end_src
          def #{render_symbol}(local_assigns)
            old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
          ensure
            self.output_buffer = old_output_buffer
          end
        end_src
        source.force_encoding(Encoding::UTF_8) if source.respond_to?(:force_encoding)

        begin
          ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
        rescue Errno::ENOENT => e
          raise e # Missing template file, re-raise for Base to rescue
        rescue Exception => e # errors from template code
          if logger = defined?(ActionController) && Base.logger
            logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
            logger.debug "Function body: #{source}"
            logger.debug "Backtrace: #{e.backtrace.join("\n")}"
          end

          raise ActionView::TemplateError.new(self, {}, e)
        end
      end
  end
end

puis d'ajouter les lignes suivantes à environnement.rb:

Rails::Initializer.run do |config|
  ...
  config.after_initialize do 
    require 'lib/actionview_utf8'
  end
end

Ensuite je suis tombé sur le problème des adaptateurs aux bases de données qui retournent de l'ASCI-8BIT au lieu d'UTF-8 à la lecture des données. Une solution du même acabit est décrite ici: http://gnuu.org/2009/11/06/ruby19-rails-mysql-utf8/. Ceci dit ça ne fonctionne qu'avec MySql.

Donc on créé le fichier lib/mysql_utf8:

require "mysql"

class Mysql::Result
  def encode(value, encoding = "utf-8")
    String === value ? value.force_encoding(encoding) : value
  end

  def each_utf8(&block)
    each_orig do |row|
      yield row.map {|col| encode(col) }
    end
  end
  alias each_orig each
  alias each each_utf8

  def each_hash_utf8(&block)
    each_hash_orig do |row|
      row.each {|k, v| row[k] = encode(v) }
      yield(row)
    end
  end
  alias each_hash_orig each_hash
  alias each_hash each_hash_utf8
end

et pour environnement.rb on se retrouve avec:

Rails::Initializer.run do |config|
  ...
  config.after_initialize do 
    require 'lib/actionview_utf8'
    require 'lib/mysql_utf8'
  end
end

ouf, tous les tests passent...