Créer votre propre gem

Publié dans développement
le

Après mon premier article sur Ruby, attardons nous un peu plus sur la création de notre première gem (oui j'utilise ce terme tel quel).

Qu'allons-nous créer ?

Et comme il nous faut un sujet d'étude, je vous propose de partir sur la création d'une gemme nous permettant de consulter les informations de vos séries préférées en passant par l'API du fameux site thetvdb. Nous la nommerons shows.

Le commencement

À la base, une gem n'est rien de plus qu'un répertoire contenant un fichier particulier, le fichier .gemspec.

Commençons donc par créer l'architecture de notre gem en créant les répertoires et fichiers suivants :

  • bin/
  • lib/
    • shows/
      • version.rb
  • shows.gemspec

Le fichier .gemspec

Ce fichier est en fait un manifest permettant de décrire votre gem, son nom, sa version, ses auteurs, ... ainsi que tous les fichiers qui doivent être packagés lors de la construction.

Voici ce que nous avons pour notre gem :

# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)

require 'shows/version'

Gem::Specification.new do |s|
    s.name = "shows"
    s.version = Shows::VERSION
    s.authors = ["Julien Leicher"]
    s.email = ["your@email.com"]
    s.homepage = ""
    s.summary = "A cli application to follow TV show releases"
    s.description = "A cli application to follow TV show releases!"

    s.rubyforge_project = "shows"

    s.files = Dir['lib/**/*', 'bin/**/*']
end

La première ligne permet ici de compléter le PATH de ruby pour inclure notre répertoire lib/.

Même si la plupart des informations se passent de commentaire, intéressons-nous à la dernière ligne :

s.files = Dir['lib/**/*', 'bin/**/*']

Ici nous avons précisé les répertoires contenant du code source pour notre gem à l'aide de la classe Dir. Cependant, si votre projet fait partie d'un dépôt git, on voit souvent ce genre de chose :

s.files = `git ls-files`.split("\n")

Ce qui permet de déléguer le listage du contenu à la commande git. C'est à vous de voir.

shows/version.rb

Vous avez sans doute remarqué la présence de require 'shows/version' dans le .gemspec, regardons le contenu du fichier lib/shows/version.rb :

# -*- encoding: utf-8 -*-
module Shows

    VERSION = '1.0.0'

end

Simple, n'est-ce pas ? Un simple module Ruby avec une constante.

Construire & installer votre gem

Basique

C'est bien sympa mais ce serait cool de pouvoir construire et installer notre gem ! Rien de plus simple, à la racine de votre gem, lancer gem build shows.gemspec pour construire votre gem et gem install shows-1.0.0.gem pour l'installer, vous devriez obtenir ceci à la suite de ces deux commandes :

WARNING:  licenses is empty
WARNING:  no homepage specified
    Successfully built RubyGem
    Name: shows
    Version: 1.0.0
    File: shows-1.0.0.gem

Successfully installed shows-1.0.0
    Parsing documentation for shows-1.0.0
    Installing ri documentation for shows-1.0.0
    Done installing documentation for shows after 0 seconds
    1 gem installed

Avec Rake

Maintenant, on aimerait bien faire en sorte que ce soit plus rapide, car taper ces 2 commandes à longueur de journée risque de devenir fatiguant. Nous allons donc utiliser Rake pour nous faciliter la vie.

Créer un fichier Rakefile à la racine de votre projet :

# -*- encoding: utf-8 -*-
require "bundler/gem_tasks"

Ces tâches sont tellement basiques que bundler nous les fournit déjà (il vous sera toutefois nécessaire d'installer les gems rake et bundler si vous souhaitez utiliser cette technique).

Désormais, pour construire et installer votre gem, un simple rake install et le tour est joué !

Ajouter un exécutable

Notre gem est installée mais nous voulions surtout pouvoir y'accéder en ligne de commande afin d'avoir notre propre outil.

Dans le répertoire bin/, créer un fichier shows et copier le contenu suivant :

# -*- encoding: utf-8 -*-
#!/usr/bin/env ruby

require 'shows/version'

puts("Hello from shows #{Shows::VERSION}!")

De manière à ce qu'il soit disponible après l'installation de notre gem, il faut le préciser dans le fichier .gemspec, ajouter donc la ligne suivante après la ligne s.files (...) :

s.executables = ['shows']

Après avoir reconstruit et réinstallé la gem, vous devriez pouvoir lancer la commande shows et voir ce magnifique message :

Hello from shows 1.0.0!

Si ce n'est pas le cas, vérifier votre PATH.

Un peu de structure

Il arrive un moment où vous voulez séparer votre gem dans plusieurs fichiers mais être capable, avec un simple require 'shows' d'accéder aux différentes fonctions.

Heureusement, c'est très simple à faire et nous allons le voir en séparant notre simple message "Hello".

Commencer par créer le fichier lib/shows/cli.rb et remplisser le comme ceci :

# -*- encoding: utf-8 -*-
require 'shows/version'

module Shows

    def self.execute
        puts("Hello from shows #{Shows::VERSION}!")
    end

end

On crée une fonction toute simple dans notre module et c'est cette fonction que nous souhaitons appeler depuis notre exécutable.

Dans notre fichier bin/shows, on doit donc modifier notre code :

# -*- encoding: utf-8 -*-
#!/usr/bin/env ruby

require 'shows/cli'

Shows::execute

Vous comprenez rapidement que si on ajoute d'autres fichiers, on va vite se perdre avec les require. De manière à simplifier tout ça, créer un fichier lib/shows.rb avec le contenu qui suit :

# -*- encoding: utf-8 -*-
require 'shows/cli'

et n'oublier pas de modifier le fichier bin/shows encore une fois :

# -*- encoding: utf-8 -*-
#!/usr/bin/env ruby

require 'shows'

Shows::execute

Et voilà ! Une gem bien organisée, une ! En règle générale, on préférera éviter d'inclure de base la partie cli dans lib/shows.rb, le but étant d'avoir tout d'abord une librairie utilisable à son tour par d'autres librairies.

Dans les prochains épisodes, nous parlerons de tests et commencerons à implémenter sérieusement les différentes fonctionnalités de notre application. En attendant, le code source se trouve sur Github.