liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

output-template.fnl (2444B)


      1 (local svc (require :anoia.svc))
      2 
      3 (fn json-escape [s]
      4   ;; All Unicode characters may be placed within the quotation marks,
      5   ;; except for the characters that MUST be escaped:
      6   ;; quotation mark, reverse solidus, and the control characters (U+0000
      7   ;; through U+001F). (RFC 8259)
      8   (-> s
      9       (string.gsub
     10        "[\"\b\f\n\r\t]" {
     11                          "\b" "\\b"
     12                          "\"" "\\\""
     13                          "\f" "\\f"
     14                          "\n" "\\n"
     15                          "\r" "\\r"
     16                          "\t" "\\t"
     17                          })
     18       (string.gsub
     19        "([\x00-\x1b])"
     20        (fn [x] (string.format "\\u%04X" (string.byte x))))))
     21 
     22 
     23 (fn substitute [text opening closing]
     24   (let [delim (.. opening "(.-)" closing)
     25         myenv {
     26                : string
     27                : table
     28                : math
     29                : ipairs
     30                : tonumber
     31                : type
     32 
     33                :output
     34                (fn [service-path path default]
     35                  (let [s (assert (svc.open service-path))]
     36                    (or (s:output path) default)))
     37                :lua_quote #(string.format "%q" $1)
     38                :json_quote (fn [x] (.. "\"" (json-escape x) "\""))
     39                }]
     40     (string.gsub text delim
     41                  (fn [x]
     42                    (let [chunk (if (= (x:sub 1 1) ";")
     43                                    (x:sub 2)
     44                                    (.. "return " x))]
     45                      (assert ((load chunk x :t myenv))
     46                              (string.format "missing value for %q" x)))))))
     47 
     48 (fn run []
     49   (let [[opening closing] arg
     50         out (substitute (: (io.input) :read "*a") opening closing)]
     51     (io.write out)))
     52 
     53 (import-macros { : define-tests : expect : expect= } :anoia.assert)
     54 (define-tests
     55   (expect= (pick-values 1 (substitute "var={{ 2 + 3 }}" "{{" "}}")) "var=5")
     56   (expect= (pick-values 1 (substitute "{{ json_quote(\"o'reilly\") }}" "{{" "}}"))
     57            "\"o'reilly\"")
     58 
     59   (expect= (pick-values 1 (substitute "{{; local a=9; return a }}" "{{" "}}")) "9")
     60 
     61   ;; "globals" set in one interpolation are available in subsequent ones
     62   (expect= (pick-values 1 (substitute "{{; a=42; return a }} {{ a and 999 or 0 }}" "{{" "}}")) "42 999")
     63 
     64   (fn slurp [name]
     65     (with-open [f (assert (io.open name))] (f:read "*a")))
     66   (expect=
     67    (pick-values 1 (substitute (slurp "example.ini")  "{{" "}}"))
     68    (slurp "example.ini.expected")))
     69 
     70 { : run }