Affichage des articles dont le libellé est ruby. Afficher tous les articles
Affichage des articles dont le libellé est ruby. Afficher tous les articles

lundi, mars 31, 2008

Experimentations avec les Mixins / Modules et les méthodes statiques (self)

On m'a posé une question aujourd'hui: "Comment définir une méthode statique dans un module et l'inclure dans une classe ?". Simple non ?!
Justement j'avais eu le même problème quand j'avais fait mon projet "natural_sort"
Spontanément j'ai essayé:

module Carnivore
  def self.manger(oiseau)
    puts "slurp! #{oiseau}"
  end
end

class GrosMinet
  include Carnivore
end

Carnivore.manger "titi" # ok ca foncionnne
GrosMinet.manger "titi" # undefined method `manger' for GrosMinet:Class (NoMethodError) WTF ?!
Malheureusement ça ne fonctionne pas :(

Dans NaturalSort, j'ai contourné le problème:

module NaturalSort
  def self.naturalsort(object)
    ...
  end
  def natural_sort
    NaturalSort::naturalsort(to_a)
  end
end
Je suis tombé sur cet article: "Ruby Mixin Tutorial" et j'ai essayé différentes combinaisons, il n'y en pas une qui soit satifaisante dans tous les cas...
Ici vous pourrez voir les principales étapes jusqu'à la version finale, celle qui me satisfait le plus.
Etape n°1: classe statique dans le module uniquement

module Carnivore
  def self.manger(oiseau)
    puts "slurp! #{oiseau}"
  end
end

Carnivore.manger "titi"
Etape n°2: méthode d'instance de classe (l'utilisation classique du module par excellence):

module Carnivore
  def manger(oiseau)
    puts "slurp! #{oiseau}"
  end
end

class GrosMinet
  include Carnivore
end

gros_minet = GrosMinet.new 
gros_minet.manger "titi"
Version finale. 2 grosses subtilités:
  • il n'y a pas de 'self' dans la définition de la méthode 'manger'
  • On utilise 'extends' au lieu de 'include'

module Carnivore
  def manger(oiseau)
    puts "slurp! #{oiseau}"
  end
end

module Chat
  def miauler
    puts "miaou..."
  end
end

class GrosMinet
  include Chat
  # include Carnivore # necessaire à gros_minet.manger("titi")
  extend Carnivore
end

GrosMinet.manger "titi"

gros_minet = GrosMinet.new 
gros_minet.miauler
# gros_minet.manger "titi" # necessite le include Carnivore pour fonctionner

Conclusion: Ca fonctionne et le code est court mais je trouve la syntax un peut étrange, je ne comprend pas trop pourquoi le 'include' n'inclus pas les méthodes 'self' ? il y a quelquechose qui m'échappe pour l'instant...

Du coup je pense que c'est une bonne pratique de ne pas utiliser de méthodes préfixé par 'self' dans le modules et que faire MonModule.ma_methode n'est peut-être pas très orienté objet... après tout les modules ne sont pas vraiment des objets et ne devraient pas être utilisés seuls ? Qu'est ce que vous en pensez ?


Technorati tags:

jeudi, février 21, 2008

Enlever les lignes en double dans un fichier

Une petie astuce que j'ai posté sur le blog de torsten en réponse à sa question:
Comment afficher les lignes d'un fichier en enlevant les doublons (faire une sorte de 'unique' ou 'distinct' sur les lignes du fichier)

Je me suis dit que ça pourrait servir à d'autres donc je le repost ici:
puts IO.readlines('data.txt').uniq

Par contre sur un gros fichier ça doit consommer beaucoup de mémoire...

Technorati tags:

vendredi, février 15, 2008

Comment tester null ou chaine (string) vide

Récemment dans un petit script j'avais le code suivant:
unless(item.nil? or item.emty?)
  ...
end
Où item est soit nil, soit "", soit "foo". Je n'aimais pas faire ça partout dans le code, je voulais être plus "DRY" en faisant quelque chose comme:
unless(item.blank?)
  ...
end
La solution que j'ai trouvé dans un premier temps pour résoudre ce problème "esthétique" était de déclarer la fonction blank? dans String et NilClass; ça conne ça:

class NilClass
  def blank?
    true
  end
end

class String
  def blank?
    to_s.empty?
  end
end
Mais Benjamin C. m'a montrer une manière plus élégante en étendant Object:
class Object
  def blank?
    respond_to?(:empty?) ? empty? : !self
  end
end
Code re-pompé honteusement de rails.
Technorati tags: