configuration properties clojure

configuration - cargando archivo de configuración en clojure como estructura de datos



properties (5)

¿Hay alguna función de lector en clojure para analizar la estructura de datos de Clojure? Mi caso de uso es leer archivos de propiedades de configuración y un valor para una propiedad debe ser una lista. Me gustaría poder escribir esto como:

propiedades de archivo:

property1 = ["value1" "value2"]

y en clojure:

(load-props "file.properties")

y obtener un mapa con el valor {property1, ["value1" "value2"]

En este momento, estoy haciendo lo siguiente, con el mismo archivo de entrada "file.properties":

(defn load-props [filename] (let [io (java.io.FileInputStream. filename) prop (java.util.Properties.)] (.load prop io) (into {} prop))) ;; returns: ;; {"property1" "[/"valu1/", /"valu2/"]"} (load-props "file.properties")

Pero no puedo encontrar el modo de analizar el resultado con el vector de un clojure. Básicamente estoy buscando algo así como el archivo de Erlang: consultar / 1 función. ¿Alguna idea de cómo hacer esto?


¿Hay alguna función de lector en clojure para analizar la estructura de datos de Clojure?

Sí. Se llama read . También puede usarlo para leer datos de configuración.

Un archivo props.clj contiene

{:property1 ["value1" 2] :property2 {:some "key"}}

se puede leer así:

(ns somens.core (:require [clojure.java.io :as io]) (:import [java.io PushbackReader])) (def conf (with-open [r (io/reader "props.clj")] (read (PushbackReader. r))))

Al leer fuentes que no son de confianza, podría ser una buena idea pasar de *read-eval* :

(def conf (binding [*read-eval* false] (with-open [r (io/reader "props.clj")] (read (PushbackReader. r)))))

Para volver a escribir los datos de configuración en un archivo, debe consultar las funciones de impresión como pr y friends.


Si desea leer archivos de propiedades estilo java, mire la respuesta de Dave Ray, aunque los archivos de propiedades tienen muchas limitaciones.

Si está utilizando Clojure 1.5 o posterior, le sugiero que use edn , la notación de datos extensible utilizada en Datomic, básicamente estructuras de datos clojure, sin ejecución de código arbitrario, y la capacidad de agregar etiquetas para cosas como instancias o tipos arbitrarios.

La forma más sencilla de usarlo es a través read-string y slurp :

(require ''clojure.edn) (clojure.edn/read-string (slurp "filename.edn"))

Eso es. Tenga en cuenta que read-string solo lee una sola variable, por lo que debe configurar su configuración como un mapa:

{ :property1 ["value1" "value2"] }

Entonces:

(require ''clojure.edn) (def config (clojure.edn/read-string (slurp "config.edn"))) (println (:property1 config))

devoluciones

["value1" "value2"]



java.util.Properties implementa Map para que esto se pueda hacer muy fácilmente sin analizar manualmente los archivos de propiedades:

(require ''clojure.java.io) (defn load-props [file-name] (with-open [^java.io.Reader reader (clojure.java.io/reader file-name)] (let [props (java.util.Properties.)] (.load props reader) (into {} (for [[k v] props] [(keyword k) (read-string v)]))))) (load-props "test.properties") ;=> {:property3 {:foo 100, :bar :test}, :property2 99.9, :property1 ["foo" "bar"]}

En particular, los archivos de propiedades son más complicados de lo que piensas (comentarios, escapes, etc., etc.) y java.util.Properties es muy bueno para cargarlos.


(use ''[clojure.contrib.duck-streams :only (read-lines)]) (import ''(java.io StringReader PushbackReader)) (defn propline->map [line] ;;property1 = ["value1" "value2"] -> { :property1 ["value1" "value2"] } (let [[key-str value-str] (seq (.split line "=")) key (keyword (.trim key-str)) value (read (PushbackReader. (StringReader. value-str)))] { key value } )) (defn load-props [filename] (reduce into (map propline->map (read-lines filename))))

MANIFESTACIÓN

user=> (def prop (load-props "file.properties")) #''user/prop user=> (prop :property1) ["value1" "value2"] user=> ((prop :property1) 1) "value2"

ACTUALIZAR

(defn non-blank? [line] (if (re-find #"/S" line) true false)) (defn non-comment? [line] (if (re-find #"^/s*/#" line) false true)) (defn load-props [filename] (reduce into (map propline->map (filter #(and (non-blank? %)(non-comment? %)) (read-lines filename)))))