2013-04-08 32 views
11

kod çalıştırma kodu ile aynı dizinde dosya açma Clojure ile bazı testler yazmaya çalışıyorum. Bu testlerden biri test içeriğini (Python'da yaygın olarak kullanılan bir deyim) kullanmak için, çalışan test dosyasıyla aynı dizinde bir html dosyasının açılmasını içerir. *file* varyasyonun işi yapacağını sanıyordum, ama bu durum aslında göreli değil.Clojure

Varsayılan leiningen düzenini kullanan projemize demoproj adı verilir. Testlerim ~/projects/demoproj/test'da. Bu dizin tekrar proje ismini çoğaltır, ben büyük bir hayranı değilim, ama her neyse. Bu nedenle core.clj testleri ~/projects/demoproj/test/demoproj/test/core.clj'dadır. Aynı dizinde small_page.html adlı bir dosyam var. Ben koyarsam test/core.clj aşağıdaki:

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

İşte ne olsun:

demoproj/test/readibility.clj 

Bu proje tabanının test dizinine görecelidir. dosya bu konumda okunamaz çünkü

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

Bu IO hataya neden oluyor şu şekildedir: Ben, yalnızca bu göreli yolu kullanarak örnek html sayfayı okumaya çalıştı. Sıradaki fikrim şu andaki çalışma dizinini almak ve göreceli yolla birleştirmekti. Burada çalışma dizinini nasıl getirdiğini anlatır: mutlak bir yol döndü

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

:

kötü bir şey
/Path-to-home/projects/demoproj 

, bu iki dosyaya doğru yola katılmıyorsun; arada bir test bileşeni eksik. Bu iki yolu birleştirmek, yanlış bir dizin yoluna yol açar.

Yani, sorum şu ki, şu anda yürütülen kod dosyasının mutlak yolunu elde etmenin güvenilir bir yolu var mı? Ve eğer bu mümkün değilse, bu deyime bir alternatif ne olurdu, yani test dosyasına göre bir konumda bulunan bir dosyayı nasıl ayrıştırabilirim?

cevap

16

clojure kodu ve ilişkili kaynaklar bir jar içinde sonlanabildiğinden ve erişmekte olduğunuz dosya gerçek bir dosya sistemi yerine jar'ın bir parçası olarak sonlansa bile kodun çalışmasını istiyorsanız, güvenilir bir yol Bu, io/resource kullanmak ve söz konusu dosyanın bir kaynak yolunda olduğundan emin olmaktır.

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

Projemde şu var:

Örneğin, ben bir akım projesinde benim dizin yapısının bir parçası olarak taraftarları vardır.Cl: Gördüğünüz gibi

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/kaynak Sonra ben sormak dosyasını slurp geçebilir bir URL döndürür:

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

sonra ben repl içinde aşağıdakileri yapabilirsiniz (yapılandırılmış kaynak yollarındaki yol parçasını ararken). Bu kod, tüm uygulama dağıtımı için bir uberjar içine sarılırken hala çalışır, oysa bir io/dosya oluşturmak ve getParent çağrısı bu durumda başarısız olur.

2

Biraz daha uğraştıktan sonra ve Stackoverflow'taki tüm yanıtları okuduktan sonra bunu nasıl yapacağımı anladım. user83510 aslında şu soruya cevap verdi: https://stackoverflow.com/a/11498784/1285782, ancak cevap kabul edilmedi ya da uygun şekilde yükseltilmedi.

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

Bu size dizininin tam yolu verir: hile şudur. Güzel değil ama işe yarıyor.