URL: https://linuxfr.org/users/martoni/journaux/taptempo-en-scala Title: TapTempo en Scala Authors: martoni Date: 2018年07月23日T21:34:06+02:00 License: CC By-SA Tags: taptempo et scala Score: 22 [Le sujet TapTempo](https://linuxfr.org/users/mzf/journaux/un-tap-tempo-en-ligne-de-commande) est très intéressant pour apprendre un nouveau langage de programmation. En effet, il est beaucoup plus complet qu'un simple Hello World ! Il nous impose de se plonger dans les arcanes du langage et de ses outils pour gérer le temps, l'affichage mais aussi les arguments de la ligne de commande ou les structures «complexe» comme les listes ou les buffers. Bon évidemment, quand il s'agit d'un langage de description hardware comme [présenté la dernière fois avec Chisel](https://linuxfr.org/users/martoni/journaux/un-composant-electronique-taptempo-avec-chisel3) on évite la ligne de commande ! Par contre, Chisel étant basé sur le langage [Scala](https://scala-lang.org/), il est intéressant de se plonger dedans histoire de le maitriser un minimum. Voici donc mon humble version de TapTempo en Scala. Langage étrange au paradigme bipolaire (;)) : Fonctionnel et Objet. Ce langage [a déjà été décrit dans les colonnes de LinuxFR](https://linuxfr.org/news/sortie-de-scala-2-10), il est basé sur une machine virtuelle Java et permet d'appeler les classes et fonctions de ce même langage. Et j'ai appris récemment que la réciproque est également vraie : On peut appeler les classes/fonctions Scala en Java. ```Scala // TapTempo import jline.console.ConsoleReader /* to read keyboard */ import scala.collection._ import sys.process._ /* shell cmd execution with ! */ val VERSION = "1.0" val PRECISION = 0 val PRECISIONLIST = List("%.00f", "%.01f", "%.02f", "%.03f", "%.04f", "%.05f") val RESET_TIME = 5 val SAMPLE_SIZE = 5 val SECOND = 1e9 val MIN = 60*SECOND object TapTempo { def usages() { println("-h, --help affiche ce message d'aide") println("-p, --precision changer le nombre de décimale du tempo à afficher") println(" la valeur par défaut est 0 décimales, le max est 5 décimales") println("-r, --reset-time changer le temps en seconde de remise à zéro du calcul") println(" la valeur par défaut est 5 secondes") println("-s, --sample-size changer le nombre d'échantillons nécessaires au calcul du tempo") println(" la valeur par défaut est 5 échantillons") println("-v, --version afficher la version") } def printversion() { println("TapTempo Scala version " + VERSION) } def tempo(tfifo: mutable.Buffer[Double]):Double = { var sum = 0.0 tfifo.foreach(sum += _) sum/tfifo.length } def main(args: Array[String]) { val arglist = args.toList type OptionMap = Map[Symbol, Int] /****************/ /* parsing args */ /****************/ def nextOption(map : OptionMap, list: List[String]) : OptionMap = { def isSwitch(s : String) = (s(0) == '-') list match { case Nil => map case ("-h" | "--help") :: tail => usages(); sys.exit(0) case ("-v" | "--version") :: tail => printversion; sys.exit(0) case ("-p" | "--precision") :: value :: tail => nextOption(map ++ Map('precision -> value.toInt), tail) case ("-r" | "--reset-time") :: value :: tail => nextOption(map ++ Map('rtime -> value.toInt), tail) case ("-s" | "--sample-size") :: value :: tail => nextOption(map ++ Map('ssize -> value.toInt), tail) case option :: tail => println("Unknown option " + option) sys.exit(0) } } val options = nextOption(Map(), arglist) var precision = options.getOrElse('precision, -1) if(precision < 0 || precision> 5) precision = PRECISION var rtime = options.getOrElse('rtime, -1) if(rtime == -1) rtime = RESET_TIME var ssize = options.getOrElse('ssize, -1) if(ssize == -1) ssize = SAMPLE_SIZE /* Minimum caracters for completed read */ (Seq("sh", "-c", "stty -icanon min 1 < /dev/tty") !) /* Do not print input caracters */ (Seq("sh", "-c", "stty -echo < /dev/tty") !) var timefifo = mutable.Buffer.fill[Double](ssize)(0.0) var fifocount = 0 println("Appuyer sur une touche en cadence (q pour quitter).") var c = 0 var i = 0 var current_time = System.nanoTime() var old_time = System.nanoTime() do { c = Console.in.read current_time = System.nanoTime() val tempotime = MIN/(current_time - old_time) if(tempotime < 60/rtime){ fifocount = 0 } if(fifocount < ssize){ fifocount += 1 } timefifo(i) = tempotime i = (i + 1) % ssize if(fifocount == ssize){ printf("Tempo : " + PRECISIONLIST(precision) + "\n", tempo(timefifo)) } else { printf("Tempo : %d/%d\n", fifocount, ssize) } old_time = current_time } while (c != 113) // While 'q' is pressed println("Bye Bye!") } } TapTempo.main(args) ``` Voila voila, le programme est également disponible sur mon github (oui oui je sais çémal). Ce petit exercice m'a permis de découvrir un peu plus de ce langage suisse très prisé du monde de la finance. Mais il y a encore du chemin pour le maîtriser. À oui j’oubliai, pour le lancer en tant que script faire : ```bash $ scala -nc TapTempo.sc ``` Patienter un certain temps — hé oui on parle quand même d'une machine virtuel java et de compilation de bytecode, çélong ! — puis taper la touche de votre choix, 'q' pour quitter. ```bash Appuyer sur une touche en cadence (q pour quitter). Tempo : 1/5 Tempo : 2/5 Tempo : 3/5 Tempo : 4/5 Tempo : 152 Tempo : 186 Tempo : 195 Tempo : 164 Tempo : 159 Tempo : 162 Tempo : 157 Tempo : 156 Tempo : 159 Bye Bye! ```

AltStyle によって変換されたページ (->オリジナル) /