String Calculator en Kawa

Hace un par de días nuestro amigo Rodrigo Salado nos compartió aquí su solución de la Kata String Calculator utilizando el lenguaje Groovy , lo cual me inspiró también a mí a publicar mi solución en Kawa para compararlas y ver que ideas se podrían implementar/traducir en Groovy.

Cabe mencionar que yo también me tardé mas de media hora (de hecho 2 pomodoros de 20 min), lo cual corrobora la teoría que teníamos con neodevelop sobre el tiempo necesario para resolver este ejercicio en un Coding-Dojo

He aquí el código en Scheme Kawa:

; -*- coding: utf-8; mode: Scheme -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Coding Kata String Calculator <http://osherove.com/tdd-kata-1/>

(require 'srfi-1 ) ;; List Library
(require '
srfi-13) ;; String Library
(require 'srfi-14) ;; Character-set Library

;; (define-simple-class StringCalculator ()
;;   ;; methods
;;   ((Add numbers ::String) ::int allocation: 'static

(define (Add numbers ::String) ::int
  (let* ((lstnum (filter (lambda (n)
                           (if (<= n 1000) #t #f))
                         (map string->number
                              (string-tokenize
                               numbers
                               (char-set-adjoin char-set:digit #\-)))))
         (negativos (filter negative? lstnum)))
    (if (null? negativos)
        (apply + lstnum)
        (throw (java.lang.RuntimeException
                (format #f
                        "No se permiten negativos: ~s~%"
                        negativos))) )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pruebas Unitarias
(require 'srfi-64) ;; Testing Library

;;(define-alias Add StringCalculator:Add)

(test-begin "string-calculator")
;;(test-assert "Prueba no implementada" #f)
;;Req 1.1 y 1.2
(test-equal 0 (Add "Hola"))
(test-equal 0 (Add ""))
(test-equal "Suma '1'" 1 (Add "1"))
(test-equal "Suma '
1,2'" 3 (Add "1,2"))
;;Req 2 y 3
(test-equal "Suma '
1,2,3'" 6 (Add "1,2,3"))
(test-equal "Suma '
1\n2,3'" 6 (Add "1\n2,3"))
;;Req 4
(test-equal 3 (Add "//;\n1;2"))
;;Req 6, 8 y 9
(test-equal 2 (Add "2,1001"))
(test-equal 6 (Add "//[*][%]\n1*2%3"))
;; pruebas del script de groovy
(test-equal 0 (Add "")) ;;assert 0 == "".sum()
(test-equal 0 (Add " ")) ;;assert 0 == " ".sum()
(test-equal 1 (Add "1")) ;;assert 1 == "1".sum()
(test-equal 1 (Add " 1")) ;;assert 1 == " 1".sum()
(test-equal 1 (Add " 1 ")) ;;assert 1 == " 1 ".sum()
(test-equal 1 (Add "  1  ")) ;;assert 1 == "  1  ".sum()
(test-equal 0 (Add "a")) ;;assert 0 == "a".sum()
(test-equal 3 (Add "1,2")) ;;assert 3 == "1,2".sum()
(test-equal 1 (Add "1, a")) ;;assert 1 == "1, a".sum()
(test-equal 2 (Add "a, 2")) ;;assert 2 == "a, 2".sum()
(test-equal 6 (Add "1,2,3")) ;;assert 6 == "1, 2, 3".sum()
(test-equal 6 (Add "//;\n1, 2, 3")) ;;assert 6 == "//;\n1, 2, 3".sum()
(test-equal 15 (Add "//;'
\n1, 2, 3' 4' 5")) ;;assert 15 == "//;'\n1, 2, 3' 4' 5".sum()
(test-equal 15 (Add "//;'\n1, 2, 3' 4' 5, \n'")) ;;assert 15 == "//;'\n1, 2, 3' 4' 5, \n'".sum()
(test-equal 15 (Add "//;'\n1, 2, 3' 4' 5, \n', a, b; c' d")) ;;assert 15 == "//;'\n1, 2, 3' 4' 5, \n', a, b; c' d".sum()
(test-equal 0 (Add ",;\n")) ;;assert 0 == ",;\n".sum()
(test-error <java.lang.RuntimeException> (Add "-1, 2, 3")) ;;try{ "-1, 2, 3".sum()
(test-error <java.lang.RuntimeException> (Add "-1, 2, 3, -4, -5")) ;;try{ "-1, 2, 3, -4, -5".sum() }catch(e){ println e}
(test-error <java.lang.RuntimeException> (Add "//;'\n1, 2, -3' -4' 5")) ;;try{ "//;'\n1, 2, -3' -4' 5".sum() }catch(e){ println e}

(test-end "string-calculator")

Notas:

  • Escribir una clase con un solo método estático es una mala práctica. Aunque en este caso el requerimiento así lo estipule, he preferido dejar el método Add como una función ordinaria de Scheme y dejar el código de definición de clase y método comentados solo como ejemplo de cómo se hace en Kawa.
  • Agregué al final de las pruebas unitarias, la traducción a Scheme de las pruebas del script de Groovy de Rodrigo para comprobar que el código cumple con las mismas especificaciones. E.d. Pasa las mismas pruebas.

Suponiendo que el código anterior se guarde en el archivo "string-calc.scm" se puede ejecutar desde la línea de comandos como:

$ kawa -f string-calc.scm

Y se obtiene la siguiente salida:

%%%% Starting test string-calculator  (Writing full log to "string-calculator.log")
# of expected passes      28

Hasta aquí la Kata de hoy.

Saludos cordiales y que tengan una excelente semana.