iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 15
0
Software Development

擁抱 Clojure系列 第 15

[第 15 天] 擁抱 Clojure:命名空間與專案(二)

命名空間與專案(二)

命名空間

保護資訊

以上的函式都會引用到命名空間中的公開資訊,如果有些資訊想要隱藏不被使用,可以在使用 def 設立 Vars 物件時加上 private 詮釋資料 (Metadata):

user=> (def pub "It's public")
user=> (def ^:private priv "It's private")
user=> (in-ns 'foo)
foo=> (clojure.core/refer 'user)
foo=> pub
;; => "It's public"
foo=> priv
;; => Unable to resolve symbol: priv in this context

上面的範例雖然使用了 user 命名空間的 priv 物件,卻因爲在定義時宣告私有,因此無法正常取用。使用插入符號 (^) 會將詮釋資料添加至 Vars 物件。讓 Clojure 讀取器 (Reader) 採用不同處理方式的字元,被稱爲讀取器巨集 (Reader Macro)。

Clojure 提供了更簡便的方式定義私有函式,便是使用 defn- 定義函式。繼續以下範例之前,請先按下 Ctrl-D 終止 REPL,再輸入 lein repl 開啓新的 REPL:

user=> (defn- greeting [name] (str "Hello, " name))
user=> (in-ns 'bar)
bar=> (clojure.core/refer 'user)
bar=> (greeting "Catherine")
;; => Unable to resolve symbol: greeting in this context

ns 巨集

在實際的專案中,其實並不常使用 referrequire 以及 use,Clojure 提供了 ns 巨集,既具備了載入其他命名空間的功能,還可以建立新的命名空間:

(ns examples.ns
  (:use clojure.test)
  (:require [clojure.zip :as zip])
  (:import java.util.Date))

ns 巨集會試着建立第一個參數名稱指定的命名空間,並切換到該命名空間,之後的修飾子分別對應了 userequireimport 等功能。

實際專案中,檔案會在一開始使用 ns 巨集以建立該檔案隸屬的命名空間,並寫上欲載入的其他命名空間。

專案

專案結構

進入這個小節之前,請先把 REPL 終止 (按下 Ctrl-D),並在命令列下切換到你擺放 Clojure 專案的目錄下,如果沒有,在家目錄下建立 Projects 是個不錯的主意。

假設現在的新專案是爲漢堡店建立網站,首先切換到家目錄的 Projects 目錄下,使用 Leiningen 建立名爲 burger-shop 的專案:

$ cd ~/Projects
$ lein new app burger-shop

Leiningen 建立的專案 burger-shop 會長得像這樣:

.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── doc
│   └── intro.md
├── project.clj
├── resources
├── src
│   └── burger_shop
│       └── core.clj
└── test
    └── burger_shop
        └── core_test.clj

project.clj 爲專案的配置描述文件,記載了專案的名稱、授權、使用到的套件以及編譯選項;resources 目錄則用來擺放程式會使用到的資源檔案;LICENSEREADME.md 則分別是此專案的授權聲明,以及 Markdown 格式的說明檔。

應用程式的原始碼被擺放在 src 目錄下,test 目錄下則放了用來測試應用程式的測試程式。Clojure 遵照 Java 對於套件的目錄命名規則,即是 x.y.z 套件將放在 x/y/z 的目錄結構中。

Leiningen 爲新專案建立了 burger_shop 這個命名空間,並依照規則創建目錄結構。使用你的編輯器,將 src/burger_shop/core.clj 檔案打開,它應該像下面這樣:

(ns burger-shop.core
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

Leiningen 爲這個檔案建立了 burger-shop.core 命名空間,並擺放在 burger_shop 目錄中的 core.clj 檔案,Clojure 程式檔案以 clj 爲副檔名。由於 Java 目錄命名不可有橫線符號 (-),因此使用底線符號 (_) 取代之。

使用第三方函式庫

除了自己寫的程式之外,實際專案還會使用別人已經開發好的函式庫,想要使用第三方函式庫,需要先以編輯器打開專案目錄下的 project.clj

(defproject burger-shop "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :main ^:skip-aot burger-shop.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

若是想要使用 cheshire 函式庫,以獲得解析 json 的功能,可以在 Clojars 找到的頁面中看到資訊:

Leiningen/Boot
[cheshire "5.8.0"]

將中括號內的文字並包含中括號,寫上 :dependencies 所在的那一行並存檔:

(defproject burger-shop "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [cheshire "5.8.0"]]
  :main ^:skip-aot burger-shop.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

當我們運行或編譯專案時,便會下載 cheshire 第三方函式庫:

$ lein run
Retrieving cheshire/cheshire/5.8.0/cheshire-5.8.0.pom from clojars
...
Hello, World!

以上範例的最後一行即是專案執行的結果。

(未完待續)


上一篇
[第 14 天] 擁抱 Clojure:命名空間與專案(一)
下一篇
[第 16 天] 擁抱 Clojure:命名空間與專案(三)
系列文
擁抱 Clojure30

尚未有邦友留言

立即登入留言