Как загрузить программные ресурсы в Clojure - PullRequest
28 голосов
/ 11 января 2010

Как вы загружаете программные ресурсы, такие как значки, строки, графические элементы, сценарии и т. Д. В программе Clojure? Я использую макет проекта, аналогичный тому, который используется во многих Java-проектах, где есть каталог ресурсов, висящий от каталога источника. JAR-файл создается из исходного кода и включает в себя ресурсы, но я не могу загрузить ресурсы, как в Java.

Первое, что я попробовал, было что-то вроде

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

Но так и не смог найти ресурс.

Вы можете сделать что-то похожее с

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

где name - это name ресурса для загрузки, но поток - nil.

Вы можете попробовать использовать загрузчик классов контекста с чем-то вроде

...

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

Но strem всегда равен нулю.

В отчаянии я попытался разместить файлы ресурсов почти в каждом каталоге программы. Они правильно копируются в банку, но я все еще не могу их загрузить.

Я посмотрел источники языка для функции load и библиотеки времени выполнения, но не получаю ее.

Любая помощь будет оценена.

РЕДАКТИРОВАТЬ : Вот более конкретный пример. В Java, если вы хотите конвертировать MarkDown в HTML, вы можете использовать скрипт showdown.js и написать что-то вроде:

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**"));
    }
}

когда я создаю проект, все это компилируется и упаковывается в банку. При запуске программа выдает <p>plain, <em>emphasis</em>, <strong>strong</strong></p>

Дословный перевод Clojure кажется довольно простым, но я столкнулся с проблемой при попытке создать InputStreamReader - я не могу написать код, необходимый для поиска файла сценария в банке.

Редактировать : Добавлен тег «уценка», поскольку в посте приведены два полных примера подходов к обработке уценки.

Ответы [ 4 ]

50 голосов
/ 05 августа 2011
(clojure.java.io/resource "myscript.js")
5 голосов
/ 12 января 2010

Это структура каталогов.

В продолжение примера механизма сценариев в OP эквивалент Clojure будет:

(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**")))

Обратите внимание, что путь к ресурсам для этого кода com/domain/resources, а не com/domain/scriptingtest/resources в версии Java. В версии clojure исходный файл example.clj находится в com/domain. В версии Java исходный файл Example.java находится в пакете com/domain/scriptingtest.

При настройке проекта в моей IDE, NetBeans, мастер проекта Java запрашивает пакет для источника. Плагин Clojure, enclojure, запрашивает пространство имен, а не пакет. Я никогда не замечал эту разницу раньше. Следовательно, ожидается ошибка «off-by-one» в структуре каталогов.

4 голосов
/ 16 февраля 2010

вы также можете использовать clojure.lang.RT / baseLoader

(defn serve-public-resource [path]
  (.getResourceAsStream (clojure.lang.RT/baseLoader) (str "public/" path))) 
3 голосов
/ 12 января 2010

Я поместил файл в testpkg / test.txt (относительно текущей директории).

Код:

(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

Первый подход: java.io.BufferedInputStream@1549f94

Второй подход: Файл: / C: /jsight/javadevtools/clojure-1.1.0/testpkg/test.txt

...