2010-01-11 14 views
28

¿Cómo se cargan recursos del programa como iconos, cadenas, elementos gráficos, scripts, etc. en un programa Clojure? Estoy usando un diseño de proyecto similar al de muchos proyectos Java donde hay un directorio de "recursos" colgando de un directorio "fuente". Se crea un archivo jar desde el origen e incluye los recursos, pero parece que no puedo cargar los recursos como lo haría en Java.Cómo cargar los recursos del programa en Clojure

Lo primero que intenté fue algo así como

(ClassLoader/getSystemResource "resources/myscript.js") 

Pero nunca pudo encontrar el recurso.

se puede hacer algo similar con

... 
    (let [cls (.getClass net.mydomain.somenamespace) 
     strm (.getResourceAsStream cls name)  ] 
... 

donde nombre es el name del recurso a la carga, pero la corriente es nil.

Puedes probar a utilizar el cargador de clases de contexto con algo así como

... 

(let [thr (Thread/currentThread) 
     ldr (.getContextClassLoader thr) 
     strem (.getResourceAsStream ldr name)] 
... 

Pero strem siempre es nula.

En la frustración, he intentado colocar los archivos de recursos en casi todos los directorios del programa. Se copian correctamente en el contenedor, pero todavía no puedo cargarlos.

He examinado las fuentes de idioma para la función load y la biblioteca de tiempo de ejecución, pero no la estoy "obteniendo".

Cualquier ayuda sería apreciada.

EDIT: Aquí hay un ejemplo más concreto. En Java, si desea convertir MarkDown a HTML, es posible utilizar el script showdown.js y escribir algo como:

package scriptingtest; 

import java.io.InputStreamReader; 
import javax.script.Invocable; 
import javax.script.ScriptEngine; 
import javax.script.ScriptEngineManager; 

public class Example { 

    private Object converter; 

    public String transformMarkDown(String markdownString) { 
     ScriptEngineManager manager = new ScriptEngineManager(); 
     ScriptEngine engine = manager.getEngineByName("js"); 
     try { 
      engine.eval(new InputStreamReader(getClass().getResourceAsStream(
        "resources/showdown.js"))); 
      converter = engine.eval("new Showdown.converter()"); 
     } catch (Exception e) { 
      return "Failed to create converter"; 
     } 
     try { 
      return ((Invocable) engine).invokeMethod(converter, "makeHtml", 
        markdownString).toString(); 
     } catch (Exception e) { 
      return "Conversion failed"; 
     } 
    } 

    public static void main(String[] args) { 
     System.out.println(new Example().transformMarkDown("plain, *emphasis*, **strong**")); 
    } 
} 

cuando se crea el proyecto, todo se compila y se envasa en un frasco. Cuando se ejecuta, el programa emite <p>plain, <em>emphasis</em>, <strong>strong</strong></p>

Una traducción literal de Clojure parece bastante sencillo, pero me encuentro con problemas tratando de crear el InputStreamReader - Me parece que no puede escribir el código necesario para encontrar el archivo de secuencia de comandos en el frasco .

Editar: Se agregó la etiqueta "markdown" ya que la publicación brinda dos ejemplos completos de enfoques para el procesamiento de rebajas.

+0

¿Es posible añadir un ejemplo en java? –

+0

@arthur: Se agregó un ejemplo más concreto en Java. ¿Cómo lograrías lo mismo en Clojure? – clartaq

Respuesta

5

Es la estructura del directorio.

Continuando con el ejemplo del motor de secuencias de comandos en el PO, un equivalente de Clojure sería:

(ns com.domain.example 
    (:gen-class) 
    (:import (java.io InputStreamReader)) 
    (:import (javax.script ScriptEngineManager ScriptEngine))) 

(defn load-resource 
    [name] 
    (let [rsc-name (str "com/domain/resources/" name) 
     thr (Thread/currentThread) 
     ldr (.getContextClassLoader thr)] 
    (.getResourceAsStream ldr rsc-name))) 

(defn markdown-to-html 
    [mkdn] 
    (let [manager (new ScriptEngineManager) 
     engine (.getEngineByName manager "js") 
     is (InputStreamReader. (load-resource "showdown.js")) 
     _ (.eval engine is) 
     cnv-arg (str "new Showdown.converter().makeHtml(\"" mkdn "\")")] 
    (.eval engine cnv-arg))) 

(defn -main 
    [] 
    (println (markdown-to-html "plain, *emphasis*, **strong**"))) 

Tenga en cuenta que la ruta de acceso a los recursos es com/domain/resources para este código en contraposición a com/domain/scriptingtest/resources en la versión de Java. En la versión clojure, el archivo fuente, example.clj está en com/domain. En la versión de Java, el archivo fuente, Example.java se encuentra en el paquete com/domain/scriptingtest.

Al configurar un proyecto en mi IDE, NetBeans, el asistente del proyecto Java solicita un paquete adjunto para la fuente. El complemento Clojure, enclojure, pide un espacio de nombres, no un paquete. Nunca antes había notado esa diferencia. De ahí el error "off-by-one" en la estructura del directorio esperado.

3

Puse el archivo en testpkg/test.txt (relativo al directorio actual).

Código:

(def x 5) 
(def nm "testpkg/test.txt") 
(def thr (Thread/currentThread)) 
(def ldr (.getContextClassLoader thr)) 
(def strem (.getResourceAsStream ldr nm)) 
(def strem2 (ClassLoader/getSystemResource nm)) 
(. System/out (println "First Approach:")) 
(. System/out (println strem)) 
(. System/out (println)) 
(. System/out (println)) 
(. System/out (println "Second Approach:")) 
(. System/out (println strem2)) 

$ java -cp \; clojure.jar clojure.main test.clj

Primera aproximación:. [email protected]

Segundo enfoque: file:/C: /jsight/javadevtools/clojure-1.1.0/testpkg/test.txt

+0

Sí, esto puede funcionar bien en el REPL. Pero, ¿es posible poner esto en una función, generar una clase, poner la clase compilada en un contenedor junto con los recursos, ejecutar la clase en el contenedor y hacer que cargue con éxito los recursos? Lo siento si no estaba claro acerca de querer compilar en una clase y construir un jar. El inglés es solo mi segundo idioma. La confusión es mi primera ;-) – clartaq

+0

El código funciona de la misma manera en ambos sentidos. – jsight

+0

No estoy seguro de por qué esto fue votado negativamente, pero le doy un +1 ya que la salida sí me indicó la estructura de directorios necesaria. – clartaq

4

también se puede utilizar clojure.lang.RT/baseLoader

(defn serve-public-resource [path] 
    (.getResourceAsStream (clojure.lang.RT/baseLoader) (str "public/" path))) 
49
(clojure.java.io/resource "myscript.js") 
Cuestiones relacionadas