Samuel Tardieu @ rfc1149.net

Scala : TD 2

`Paradigmes et langages non classiques 2014

Ce TD permet de manipuler et d’approfondir les différents concepts abordés lors du troisième cours Scala. Le même fichier de configuration pour sbt pourra être initialement utilisé et sera complété par la suite.

Observables

Écrire une fonction qui retourne un observable contenant les caractères composant le résultat d’une requête HTTP :

   def fromURL(url: String): Observable[Char]

puis une fonction qui, en utilisant la précédente, renvoie le contenu agrégé sous la forme d’une chaîne de caractères :

   def getContent(url: String): Observable[String]

Ces observables, quand un nouvel abonné arrivera, devront s’exécuter dans le scheduler IOScheduler() (dans le package rx.lang.scala.schedulers). On utilisera pour cela la méthode subscribeOn(…) de l’observable. Seul fromURL nécessite d’être ainsi équipé, puisque par défaut les observables ne faisant que traiter celui-ci hériteront de cette propriété.

Ne pas hésiter, pendant le développement, à afficher l’url demandée, pour suivre facilement la trace des requêtes lorsqu’elles sont faites.

Si on souhaite utiliser les fonctions de créations d’observables autre que la fonction qui prend un abonné, on tirera avantageusement parti de Observable.defer qui permet de ne retourner un observable que lorsqu’il a un abonné.

Note : pour une requête aussi simple (GET), on pourra utiliser Scala.io.Source.fromURL.

JSON library

Certains services web retournent des données au format JSON. Pour les analyser, on utilisera la bibliothèque spray-json, qu’il faudra ajouter à sbt.

Écrire une fonction qui, en utilisant getContent, renvoie une valeur JSON à partir d’une URL:

   def getJSON(url: String): Observable[JsValue]

On testera cette fonction avec l’URL http://ip.jsontest.com/ qui retourne un objet JSON avec un champ “ip” contenant l’adresse IP de l’appelant.

Trakt API

Le site trakt permet de récupérer des informations sur les différentes séries télévisées, les films, etc. En plus d’être visualisables dans un navigateur, ces informations sont disponibles sous la forme d’une API accessible en REST renvoyant les résultats sous la forme d’objets JSON ou XML.

Pour pouvoir utiliser cette API, il faut obtenir une clé qui devra accompagner les requêtes. Une fois enregistré, la clé s’obtient ici (Settings / API).

Récupération de l’heure

Écrire un observable permettant de récupérer l’heure telle que vue par le serveur Trakt.

   val traktTimestamp: Observable[Int]

En prévision des autres appels à l’API Trakt, on pourra créer des fonctions utilitaires permettant d’accéder à une fonctionnalité donnée de l’API sans répéter la clé d’API et le chemin complet :

  def getTraktJSON(path: String, args: Iterable[String] = List()): Observable[JsValue]

  def getTraktMap(path: String, args: Iterable[String] = List()): Observable[Map[String, JsValue]]

Récupération des informations sur une série télévisée

Écrire une fonction permettant de récupérer les informations sur les différentes saisons d’une série télévisée. title est soit le champ d’identification de Trakt (tvdb_id) soit le slug de la série qu’on obtient en regardant l’URL de la page de présentation d’une série (par exemple “the-walking-dead” pour la série The Walking Dead).

   def traktShowSeasons(title: String): Observable[Season]

où le type Season est défini comme:

   case class Season(season:   Int,
                     episodes: Int,
                     url:      String,
                     images:   Map[String, String])

On utilisera l’object mapper de spray-json pour convertir facilement une chaîne JSON en type Season.

Récupération des mises à jour

Écrire un observable permettant de récupérer les mises à jour ayant eu lieu sur les séries télévisées dans les 12 dernières heures (en utilisant l’heure déterminée par traktTimestamp). Chaque série sera représentée sous la forme d’un dictionnaire Scala.

   val traktUpdated: Observable[Map[String, JsValue]]

Nom des séries mises à jour

Écrire un observable qui renvoie le nom des séries mises à jour ainsi que leur date de mise à jour et leur champ tvdb_id.

   val traktUpdatedByName: Observable[(String, Int, Int)]

On pourra tirer parti de la méthode parallel des observables qui permet d’effectuer des opérations en parallèle et de recoller les résultats.

Bonus : tri par nombre d’épisodes

Écrire un observable retournant la même information que traktUpdated mais en triant les séries par nombre décroissant total d’épisodes.

   val traktUpdatedByEpisodes: Observable[(String, Int, Int)]

On pourra, par exemple, utiliser un observable renvoyant le nombre total d’épisodes pour une série télévisée donnée en utilisant traktShowSeasons, combiner cette information avec la liste obtenue par traktUpdated, convertir les données sous forme de liste, les trier, et les réexploser.