bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#19401: 25.0.50; metar.el (metar-convert-temperature) wrong type argu


From: Wolfgang Jenkner
Subject: bug#19401: 25.0.50; metar.el (metar-convert-temperature) wrong type argument stringp nil
Date: Tue, 13 Jan 2015 15:34:49 +0100
User-agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/25.0.50 (berkeley-unix)

On Thu, Dec 18 2014, Ulf Jasper wrote:

> It appears that the temperature value -1 °C ("M01") is causing the error
>
>     (metar-convert-temperature "M07") => (-7 . degC)
>     (metar-convert-temperature "M01") => error (wrong-type-argument stringp 
> nil)
>
> I suspect that this is the result of `math-mul-symb-fancy' (which
> metar.el calls via calc-units) treating "-1" in a special way
>
>     (math-mul-symb-fancy -7 '(var degC var-degC)) => (* -7 (var degC 
> var-degC))
>     (math-mul-symb-fancy -1 '(var degC var-degC)) => (neg (var degC var-degC))

There are problems in calc (Bug#19582) here.  There's also a small
problem in metar, viz., the string "-degC" is not parsed in the same way
as "-1 degC".

Since `metar-convert-unit' has (at least potentially) the same problem,
the attached patch does a little refactoring of those two functions,
where the actual conversion function from the calc library is passed as
an additional optional argument to `metar-convert-unit', so that
`metar-convert-temperature' reduces to just a call to the latter.

The actual bug is simply resolved by passing t as the last argument to
`math-convert-units' resp. `math-convert-temperature', so that these
functions return the number without a unit.  After all, we already know
which unit we get...

Please note that this patch assumes that the patch from (Bug#19582) has
been applied.
>From 4d72d28ead8f864fad08a3d05f216de940be6b8f Mon Sep 17 00:00:00 2001
From: Wolfgang Jenkner <wjenkner@inode.at>
Date: Sat, 3 Jan 2015 00:34:33 +0100
Subject: [PATCH] [metar] Fix the case where the metar record contains M01
 (bug#19401).

* packages/metar/metar.el (metar-convert-unit): New optional argument.
(metar-convert-temperature): Use it to rewrite this function in terms of
metar-convert-unit.
Pass t as last argument to the underlying calc conversion functions so
that they return only the number, not the unit, thereby fixing the bug
in question.
---
 packages/metar/metar.el | 66 ++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/packages/metar/metar.el b/packages/metar/metar.el
index 7b78f07..9575313 100644
--- a/packages/metar/metar.el
+++ b/packages/metar/metar.el
@@ -239,45 +239,43 @@ If no match if found, nil is returned."
       (when station-code
        (cons station-code (round best-distance))))))
 
-(defun metar-convert-unit (value new-unit)
+(defun metar-convert-unit (value new-unit &optional convert-units-function)
   "Convert VALUE to NEW-UNIT.
 VALUE is a string with the value followed by the unit, like \"5 knot\"
-and NEW-UNIT should be a unit name like \"kph\" or similar."
+and NEW-UNIT should be a unit name like \"kph\" or similar.
+CONVERT-UNITS-FUNCTION designates the function actually doing the conversion.
+It must have the signature of `math-convert-units', which is the default."
   (cl-check-type value string)
-  (cl-check-type new-unit (or string symbol))
-  (cl-multiple-value-bind (value unit)
-      (split-string
-       (math-format-value
-       (math-convert-units (math-simplify (math-read-expr value))
-                           (math-read-expr
-                            (cl-etypecase new-unit
-                                          (string new-unit)
-                                          (symbol (symbol-name new-unit))))))
-       " ")
-    (cons (string-to-number value) (intern unit))))
+  (unless (symbolp new-unit)
+    (setq new-unit (intern new-unit)))
+  (let ((expr (math-simplify (math-read-expr value))))
+    (cl-assert (or (math-zerop expr)
+                  (not (memq (math-single-units-in-expr-p expr) '(nil wrong))))
+              nil
+              "Metar: Not exactly one unit in expression: %S" expr)
+    (let ((res (math-simplify-units
+               (funcall (or convert-units-function 'math-convert-units)
+                        expr
+                        (math-build-var-name new-unit)
+                        t))))
+      (cl-assert (math-realp res) nil
+                "Metar: Not a Calc real number: %S" res)
+      (cons (string-to-number (math-format-value (if (integerp res)
+                                                    res
+                                                  (math-float res))))
+           new-unit))))
 
 (defun metar-convert-temperature (string &optional unit)
-  (let* ((value (concat (if (= (aref string 0) ?M)
-                           (concat "-" (substring string 1))
-                         string)
-                       "degC"))
-        (expr (math-read-expr value))
-        (old-unit (math-single-units-in-expr-p expr))
-        (new-unit (or unit (cdr (assq 'temperature metar-units)))))
-    (if old-unit
-       (cl-multiple-value-bind (value unit)
-           (split-string
-            (math-format-value
-             (math-simplify-units
-              (math-convert-temperature
-               expr
-               (list 'var
-                     (car old-unit)
-                     (intern (concat "var-" (symbol-name (car old-unit)))))
-               (math-read-expr (cl-etypecase new-unit
-                                 (string new-unit)
-                                 (symbol (symbol-name new-unit))))))) " ")
-         (cons (string-to-number value) (intern unit))))))
+  (metar-convert-unit (concat (if (= (aref string 0) ?M)
+                                 (concat "-" (substring string 1))
+                               string)
+                             "degC")
+                     (or unit (cdr (assq 'temperature metar-units)))
+                     (lambda (expr new-unit-var pure)
+                       (math-convert-temperature expr
+                                                 (math-build-var-name 'degC)
+                                                 new-unit-var
+                                                 pure))))
 
 (defcustom metar-url
   "http://weather.noaa.gov/pub/data/observations/metar/stations/%s.TXT";
-- 
2.2.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]