Follow me
RSS feed
My sources
My Viadeo

Happy happymapper

Greg | 09 Nov 2009

devSi vous suivez ce blog, vous savez que je travaille1 depuis plusieurs mois sur un outil permettant de montrer la puissance des APIs développées dans la boite dans laquelle je travaille. L'outil en question, outre sont côté fonctionnel spécifique, présente la particularité de fonctionner avec l'ensemble des bases de données médicamenteuses proposées par VIDAL. J'entends par là le fait que les données étant diffusées à l'international, il existe, non seulement une version Française, mais également une version pour les Emirats Arabes Unis, pour l'Espagne, le Portugal, ... Et alors ?

Et alors, ce besoin a des impacts non négligeables sur le développement de certaines fonctions. Je ne vais pas entrer dans les détails de la sécurisation d'une prescription, mais juste vous dire que pour la prise en compte de l'état pathologique d'un patient, nous codons cet état via la CIM. Or l'utilisation de cette classification, et plus fortement sa diffusion, est soumise à une licence payante pour chaque pays. Or VIDAL n'ayant acquis qu'une licence pour la France, les versions internationales de la base n'intègrent pas les libellés de la CIM. Tout mon problème était de savoir comment permettre de travailler avec ces libellés quand la démo se fait à l'international ? Plus précisément, comment faire en sorte qu'une personne ayant acquis la licence puisse utiliser mon outil avec sa CIM.

Initialement, j'avais opté pour une solution consistant à déporter la classification dans une base SQLite ne contenant qu'une seule table avec trois colonnes :

cim10

Par défaut cette base ne contenait que les codes CIM sans les libellés. Il suffisait, localement, de remplacer le fichier SQLite pour pouvoir accéder aux libellés.

Tout cela était sans compter sur le fait que les personnes qui ont besoin de cet outil ont souvent une approche technique proche de l'état larvaire, et que leur demander de créer un fichier SQLite, aussi simple soit-il, tient du roman de science-fiction chez certains2. J'ai donc dû chercher du côté des outils plus classiques de cette population chez qui Excel est un prolongement synaptique. J'ai alors découvert que ce merveilleux outil est capable de générer des fichiers XML. Sauvé3 !

Maintenant que nous savons que nous pouvons utiliser du XML, un simple fichier formaté comme ce qui suit suffit :

<cims>
  <cim10>
    <code>A00.-</code>
    <parent></parent>
    <label>Cholera</label>
  </cim10>
  <cim10>
    <code>A00.0</code>
    <parent>A00.-</parent>
    <label>Choléra classique</label>
  </cim10>

  ...
</cims>

Parcourir un fichier XML est une chose relativement facile avec Ruby. Il existe un grand nombre de modules pour nous y aider. Dans le cas présent, j'ai choisis HappyMapper. Ce dernier permet mapper du XML dans des objets. Ainsi, avec le fichier XML des codes CIM, il suffit de créer l'objet suivant :

class Cim10
  include HappyMapper
  
  element :code, String
  element :parent, String
  element :label, String
end

Si ensuite nous parsons le contenu du fichier XML (via Cim10.parser nous obtenons un tableau d'objets Cim10 :

cims = Cim10.parse(File.read("cim10-fr.xml"))

Tout le problème maintenant c'est de pouvoir faire des recherches dans ce tableau. Pour cela je me suis amusé à transformer le tableau de sortie en utilisant une nouvelle classe : HappyArray :

require "rubygems"
require "active_record/dynamic_finder_match"

class HappyArray < Array
  def find( h )
    r = HappyArray.new
    self.each do |cim|
      keep = true
      h.each do |k, v|
        term = v
        term = v.join('|') if v.class == Array
        keep = keep && !(cim.send(k).downcase.match(term.downcase).nil?)
      end
      r << cim if keep
    end
    return r
  end
  
  def method_missing(method_name, *args, &block)
    if match = ActiveRecord::DynamicFinderMatch.match( method_name )
      finder = {}
      match.attribute_names.each do |f|
        finder[f.to_sym] = args.shift
      end
      return find( finder )
    end
    return HappyMapper.new
  end
end

Cette classe me permet ainsi de faire ceci :

cims = Cim10.parse(File.read("cim10-fr.xml"))
happyCims = HappyArray.new(cims)

results = happyCims.find( :label => "choléra" )
# => Tableau des objets Cim10 dont le libellé contient le terme "choléra"

results = happyCims.find_by_label_and_code( ["choléra", "vaccin"], "A00" )
# => Tableau des objets Cim10 dont le libellé contient "choléra" ou "vaccin" et dont le code contient "A00"

Je n'ai pas voulu ajouter les méthodes de la classe HappyArray à la classe Array car finalement elles ne peuvent servir que dans le cas d'une utilisation avec HappyMapper. La question maintenant c'est de savoir si je sécurise un peu ce code et le propose comme patch pour HappyMapper ou pas ?

1 Vous pouvez aussi regarder ceci ;)
2 Suivez mon regard...
3 Enfin presque... Le problème, maintenant, va être d'expliquer comment faire :(

Copyright © 2009 - 2011 Grégoire Lejeune.
All documents licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License, except ones with specified licence.
Powered by Jekyll.