Nicolas Cavigneaux
29 03 2011

MacRuby - Introduction à HotCocoa - Ajout de fonctionnalités

posté par dans les catégories technologies, alternatives, interpréteur, apple

Dans nos précédents articles concernant HotCocoa nous avons vu les bases de la création d’un projet ainsi que la mise en place de l’interface utilisateur. Pour l’heure, les interactions utilisateurs sont gérées de manière factices. Nous allons aujourd’hui mettre en place les routines réelles de récupération et d’affichage des flux RSS / ATOM.

Préparation

Le but est de récupérer un flux RSS (ou ATOM) depuis l’adresse fournie par l’utilisateur. Plutôt que d’analyser nous même le flux récupéré nous allons utiliser un gem pour nous faciliter la tâche. En effet, il est tout à fait possible d’utiliser des gems écrits pour Ruby MRI depuis MacRuby. Les deux interpréteurs étant compatibles, vous ne devriez pas rencontrer de problèmes hormis pour certains gems écrits en C et non en Ruby pur.

J’ai choisi d’utiliser FeedParser qui suffira largement à notre utilisation. Avant de pouvoir l’utiliser il faut bien évidemment l’installer, nous allons donc passer par macgem (version dédiée à la gestion des gems pour MacRuby) :

macgem install ruby-feedparser

Nous pouvons maintenant passer à l’écriture du code. Vous retrouverez le code complet sur notre compte GitHub.

require 'rubygems'
require 'hotcocoa'
require 'feedparser'
require 'open-uri'

class Application

  include HotCocoa

  def start
    application :name => "SynbiozFeeds" do |app|
      app.delegate = self
      window(:size => [640, 480], :center => true, :title => "Synbioz Feed", :view => :nolayout) do |win|
        win.will_close { exit }

        win.view = layout_view(:layout => {:expand => [:width, :height], :padding => 0, :margin => 0}) do |vert|
          vert << layout_view(:frame => [0, 0, 0, 40], :mode => :horizontal, :layout => {:padding => 0, :margin => 0, :start => false, :expand => [:width]}) do |horiz|
            horiz << label(:text => "Flux RSS", :layout => {:align => :center})
            horiz << @feed_field = text_field(:layout => {:expand => [:width]})
            horiz << button(:title => 'lire', :layout => {:align => :center}) do |b|
              b.on_action { load_feed }
            end
          end

          vert << scroll_view(:layout => {:expand => [:width, :height]}) do |scroll|
            scroll.setAutohidesScrollers(true)
            scroll << @table = table_view(:columns => [column(:id => :data, :title => '')], :data => []) do |table|
               table.setUsesAlternatingRowBackgroundColors(true)
               table.setGridStyleMask(NSTableViewSolidHorizontalGridLineMask)
               table.on_action do
                 url = NSURL.URLWithString(table.dataSource.data[table.clickedRow][:link])
                 NSWorkspace.sharedWorkspace.openURL(url)
               end
            end
          end
        end
      end
    end
  end

  def load_feed
    url = @feed_field.stringValue
    unless url.nil? || url =~ /^\s*$/
      feed = FeedParser::Feed.new open(url).read
      latest_posts = feed.items[0..9]

      latest_posts.each do |p|
        @table.dataSource.data << {:data => "#{p.title} par #{p.creators.join(', ')}", :link => p.link}
      end
      @table.reloadData
    end
  end
end

Application.new.start

Détaillons les quelques changements qui rendent notre application fonctionnelle.

Chargement des données d’un flux

Interface vide

L’idée étant de pouvoir entrer l’URL d’un flux RSS ou ATOM pour en récupérer les 10 dernières entrées et les afficher dans un tableau par ordre chronologique inverse. Il faut donc pouvoir lire les données distante (flux XML) et les interpréter.

Voici comment procéder :

def load_feed
  url = @feed_field.stringValue
  unless url.nil? || url =~ /^\s*$/
    feed = FeedParser::Feed.new open(url).read
    latest_posts = feed.items[0..9]

    latest_posts.each do |p|
      @table.dataSource.data << {:data => "#{p.title} par #{p.creators.join(', ')}", :link => p.link}
    end
    @table.reloadData
  end
end

Il faut commencer par modifier notre méthode load_feed.

On récupère l’URL du flux entré par l’utilisateur qu’on lit directement grâce à open. open fournit par open-uri permet, entre autre, de lire directement le contenu d’une réponse HTTP. On obtient donc une chaîne contenant notre flux RSS / ATOM.

Maintenant entre en jeu FeedParser qui va nous retourner une structure de données contenant les articles ainsi que toutes les infos dont on peut avoir besoin.

À la ligne suivante, on ne conserve que les 10 derniers articles parus. On parcourt ensuite ces articles pour mettre à jour le tableau qui sera affiché à l’utilisateur. Pour chaque article, on crée une ligne dans laquelle on affiche le titre et l’auteur.

Vous noterez qu’en plus des données (clé :data), on passe également le lien (clé :link) vers la page web de l’article. Ceci sera utilisé pour ouvrir le navigateur de l’utilisateur lorsqu’il cliquera sur un titre d’article.

Voici le résultat obtenu :

Interface avec articles

Interaction utilisateur

Modifions maintenant le code qui génère notre tableau :

vert << scroll_view(:layout => {:expand => [:width, :height]}) do |scroll|
  scroll.setAutohidesScrollers(true)
  scroll << @table = table_view(:columns => [column(:id => :data, :title => '')], :data => []) do |table|
     table.setUsesAlternatingRowBackgroundColors(true)
     table.setGridStyleMask(NSTableViewSolidHorizontalGridLineMask)
     table.on_action do
       url = NSURL.URLWithString(table.dataSource.data[table.clickedRow][:link])
       NSWorkspace.sharedWorkspace.openURL(url)
     end
  end
end

Seul un bloc d’instructions a été ajouté. Il permet, lorsque l’utilisateur clique sur une ligne de résultat, de charger l’article dans le navigateur par défaut.

On définie donc le comportement de l’action via la méthode on_action qui prend un bloc en paramètre. Dans ce bloc, on récupère depuis la source de données l’adresse associée à la ligne cliquée : table.dataSource.data[table.clickedRow][:link]. On utilise ensuite NSURL.URLWithString() sur la chaîne récupérée pour obtenir une URL facilement manipulable par les classes et méthodes Cocoa.

Il ne nous reste plus maintenant qu’à demander l’ouverture de l’URL dans le navigateur par défaut. Cocoa nous propose une classe et des méthodes pour le faire en toute simplicité : NSWorkspace.sharedWorkspace.openURL(url)

Conclusion

Avec seulement quelques lignes de code modifiées, on passe d’une maquette sans vie à quelque chose de fonctionnel.

On voit clairement que grâce à la concision de Ruby et la richesse de Cocoa, il est très simple de prototyper une application pour ensuite lui ajouter des fonctionnalités. Je trouve réellement plaisant de pouvoir écrire des applications Mac natives si facilement et de surcroît à l’aide de mon langage préféré sans pour autant sacrifier les performances.

L’équipe Synbioz.

Libres d’être ensemble.

Articles connexes

09 11 2010

Introduction à MacRuby

MacRuby, qu’est ce que c’est ? MacRuby est une implémentation alternative de Ruby 1.9 basée sur le coeur des technologies Mac OS X telles que les librairies d’Objective-C, son garbage collector ou e…

Lire la suite
23 05 2013

Introduction à RubyMotion

RubyMotion est un framework permettant d’écrire des applications iOS et OS X natives en Ruby. Le code Ruby est compilé exactement de la même façon que le serait du code Objective C. Toutes les APIs C…

Lire la suite

Ajouter un commentaire

Notre expérience vous intéresse ? Inscrivez-vous à nos articles !

×

Newsletter

Join us

Continue the conversation

Phone
0 805 69 35 35

Our latest news

Our latest tweets

Pour échanger autour de nos vidéos, rendez vous directement sur notre chaine Youtube https://t.co/YHSF65VEqI

Hackademy : Découvrez en vidéo la mise en place et l'impact d'index composites avec #postgresql http://t.co/jdCuDzma66

Présentation des index composites avec #postgresql en vidéo sur #hackademy https://t.co/k9BfpxDISo