Подтвердить что ты не робот

Открытие файла в том же каталоге, что и работающий код в Clojure

Я пытаюсь написать несколько тестов с помощью Clojure. Один из этих тестов включает открытие html файла в том же каталоге, что и тестовый файл, для использования содержимого в качестве тестового ввода (широко используемая идиома в Python). Я думал, что *file* var выполнит эту работу, но это не так, потому что это относительный.

Скажем, мой проект, использующий макет leiningen по умолчанию, называется demoproj. Мои тесты затем находятся в ~/projects/demoproj/test. Этот каталог снова повторяет пространство имен проектов, которое я не большой поклонник, но что бы то ни было. Итак, тесты для core.clj находятся в ~/projects/demoproj/test/demoproj/test/core.clj. У меня также есть файл под названием small_page.html в том же каталоге. Если я поставлю следующее в test/core.clj:

(println (-> (java.io.File. *file*)
             .getPath))

Вот что я получаю:

demoproj/test/readibility.clj

Это относится к каталогу test базы проекта. Я пробовал читать образец html-страницы, используя только этот относительный путь, следующим образом:

(slurp (-> (java.io.File. *file*)
            .getParent
            (java.io.File. "small_page.html")
            .getPath))

Это вызывает ошибку ввода-вывода, поскольку файл не может быть прочитан в этом месте. Моя следующая идея заключалась в том, чтобы получить текущий рабочий каталог и присоединиться к нему с относительным путем. Вот как я загрузил рабочий каталог:

(println (-> (java.io.File. ".")
             .getCanonicalPath))

Что вернул абсолютный путь:

/Path-to-home/projects/demoproj

Плохо, эти два не присоединяются к правильному пути к файлу; там отсутствует компонент test. Таким образом, объединение этих двух путей приводит к неправильному пути к каталогу.

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

4b9b3361

Ответ 1

Поскольку код clojure и связанные ресурсы могут оказаться в банке, и вы хотите, чтобы код запускался, даже если файл, к которому вы обращаетесь, может оказаться частью фляги, а не реальной файловой системой, надежным способом для этого нужно использовать io/resource и убедиться, что указанный файл находится в пути ресурса.

Например, у меня есть следующая часть моей структуры каталогов в текущем проекте:

|-- project.clj
|-- resources
|   |-- caribou.properties
|   |-- config
|   |   |-- boot.clj
|   |   |-- development.clj
|   |   |-- local-dumped.clj
|   |   |-- local.clj
|   |   |-- production.clj
|   |   |-- staging.clj
|   |   `-- test.clj
|   `-- logging.properties

В моем проекте project.clj есть следующее:

  :resource-paths ["shared" "resources"]

то я могу сделать следующее в моем repl:

user> (do (require '[clojure.java.io :as io]) (io/resource "config/boot.clj"))
#<URL file:/Users/me/this-project/resources/config/boot.clj>
user> (slurp *1)
"(use '[caribou.config :only (read-config configure environment)])\n(require '[clojure.java.io :as io])\n..."

как вы можете видеть, io/resource возвращает URL-адрес, который затем я могу передать, чтобы развернуть файл, который я запрашиваю (поиск фрагмента пути в настроенных путей ресурсов). Этот код по-прежнему работает, если все приложение завернуто в uberjar для развертывания, в то время как создание файла io/file и вызов getParent в этом случае завершаются.

Ответ 2

Я выяснил, как это сделать после того, как поработал немного больше, и фактически прочитал все ответы на Stackoverflow. Пользователь83510 на самом деле ответил на вопрос здесь: fooobar.com/info/487180/..., но ответ не был принят или правильно одобрен. Трюк заключается в следующем:

(-> (ClassLoader/getSystemResource *file*) clojure.java.io/file .getParent)

Это дает вам абсолютный путь к каталогу. Не красиво, но работает.