11

Clojure でいくつかのテストを作成しようとしています。これらのテストの 1 つは、実行中のテスト ファイルと同じディレクトリにある 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))

その場所でファイルを読み取ることができないため、IO エラーが発生します。私の次のアイデアは、現在の作業ディレクトリを取得し、それを相対パスに結合することでした。作業ディレクトリを取得する方法は次のとおりです。

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

絶対パスを返したもの:

/Path-to-home/projects/demoproj

悪いことに、これら 2 つはファイルへの正しいパスに結合されません。test間に欠けているコンポーネントがあります。したがって、これら 2 つのパスを結合すると、ディレクトリ パスが正しくなくなります。

それで、私の質問は、現在実行されているコード ファイルの絶対パスを取得する信頼できる方法はありますか? これが不可能な場合、このイディオムの代わりになるものは何でしょうか。つまり、テスト ファイルからの相対位置にあるファイルを解析するにはどうすればよいでしょうか?

4

2 に答える 2

18

Because clojure code and associated resources can end up in a jar, and you want the code to run even if the file you are accessing can end up as part of the jar rather than a real file system, the reliable way to do this is to use io/resource, and ensure that the file in question is in a resource-path.

For example, I have the following as a part of my directory structure in a current project:

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

I have the following in my project.clj:

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

then I can do the following in my 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..."

as you can see, io/resource returns a URL that I can then pass to slurp up the file I ask for (looking up the path fragment in the configured resource paths). This code still works if the whole app is wrapped up into an uberjar for deployment, whereas making an io/file and calling getParent fails in this case.

于 2013-04-08T16:23:58.430 に答える
2

もう少しグーグルで調べて、実際にStackoverflowのすべての回答を読んだ後、これを行う方法を見つけました。user83510 は実際にhttps://stackoverflow.com/a/11498784/1285782で質問に回答しましたが、回答は受け入れられなかったり、適切に支持されたりしませんでした。トリックは次のとおりです。

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

これにより、ディレクトリへの絶対パスが得られます。美しくはありませんが、機能します。

于 2013-04-08T10:33:24.900 に答える