Leiningen - fxjwind - 博客園
http://www.cnblogs.com/fxjwind/archive/2013/03/07/2948005.html
https://github.com/technomancy/leiningen
1 What's Leiningen
Leiningen is a tool for automating Clojure projects without setting your hair on fire.
If you come from the Java world, Leiningen is "Maven meets Ant without the pain". For Ruby and Python folks, Leiningen combines RubyGems/Bundler/Rake and pip/Fabric in a single tool.
Clojure項(xiàng)目自動(dòng)化創(chuàng)建, 編譯, 打包和部署的工具集. 具體可以提供如下功能,
It manages various project-related tasks, and can:
create new projects
manage dependencies for your project
run tests
run a REPL (without you having to worry about adding dependencies to the classpath)
compile Java sources (if any)
run the project (if the project is an app)
generate a maven-style "pom" file for the project
compile and package projects for deployment
publish libraries to maven artifact repositories such as Clojars
run custom automation tasks written in Clojure (leiningen plug-ins)
2 Basic Usage
help, 幫助手冊
Use lein help
to see a complete list. lein help $TASK
shows the usage for a specific task.
new, 創(chuàng)建新項(xiàng)目
$ lein new [TEMPLATE] NAME # generate a new project skeleton
run, 執(zhí)行, 以-main函數(shù)會(huì)入口函數(shù)
****$ lein run -m my.namespace # run the -main function of a namespace
test, 執(zhí)行test namespace目錄里面的所有testcase
$ lein test [TESTS] # run the tests in the TESTS namespaces, or all tests
repl, launch repl
****$ lein repl # launch an interactive REPL session
uberjar, 將project打包成jar
****$ lein uberjar # package the project and dependencies as standalone jar
串聯(lián)執(zhí)行
You can also chain tasks together in a single command by using the do
task with comma-separated tasks:
$ lein do clean, test foo.test-core, jar
在project directory內(nèi)執(zhí)行命令
Most tasks need to be run from somewhere inside a project directory to work, but some (new
, help
, search
, version
, andrepl
) may run from anywhere.
3 Create Project
使用lein new來創(chuàng)建新的clojure項(xiàng)目, 會(huì)在當(dāng)前目錄創(chuàng)建項(xiàng)目目錄my-stuff.
$ lein new my-stuffGenerating a project called my-stuff based on the 'default' template.$ cd my-stuff$ find .../.gitignore./doc./doc/intro.md./project.clj./README.md./src./src/my_stuff./src/my_stuff/core.clj./test./test/my_stuff./test/my_stuff/core_test.clj
Namespace Mapping Convention
創(chuàng)建project時(shí), 會(huì)自動(dòng)創(chuàng)建namespace my-stuff.core
my-stuff.core
instead of just my-stuff
since single-segment namespaces are discouraged in Clojure. Namespace在FP里面比較重要, 比在OO里面重要, 因?yàn)閷?duì)于OO還有class, 其實(shí)就是做了一層的namespace封裝, 有效的避免沖突 但是對(duì)于FP, 直接就是function, 如果不加合理的namespace, 那就太容易沖突了 所以這兒使用my-stuff.core, 在project內(nèi)部需要namespace的分層, 除了core, 肯定應(yīng)該有其他的子namespace……
4 Project.clj, Configuration
首先可以看出data=code, 配置文件一樣可以用clojure文件來寫, 只要實(shí)現(xiàn)macro, 配置文件直接就可以run, 很牛!
Default自動(dòng)生成的project.clj的模板如下:
(defproject my-stuff "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.4.0"]])
一個(gè)簡單的例子,
(defproject myproject "0.5.0-SNAPSHOT" :description "A project for doing things." :license "Eclipse Public License 1.0" :url "http://github.com/technomancy/myproject" :dependencies [[org.clojure/clojure "1.4.0"]] :plugins [[lein-ring "0.4.5"]])
實(shí)際使用的會(huì)比這個(gè)復(fù)雜很多, 參考下面的sample.project.clj
See the sample.project.clj file (also available via lein help sample
) for a detailed listing of configuration options.
通過profiles可以根據(jù)不同的情況設(shè)定不同的configuration
The project.clj
file can be customized further with the use of profiles.
Dependencies
Overview
Clojure is a hosted language and Clojure libraries are distributed the same way as in other JVM languages: as JARs.
JARs (.jar
files) are basically just .zip
files with a little extra JVM-specific metadata. They usually contain .class
files (JVM bytecode) and .clj
source files, but they can also contain other things like config files, JavaScript files or text files with static data.
必須要指明, project和其他包的依賴關(guān)系, 這樣leiningen才能自動(dòng)的下載配置相關(guān)包, 以保證project可以被正常的編譯和運(yùn)行.
Artifact IDs, Groups, and Versions
Artifact IDs, 包的名字, 如clojure, hibernate Groups, 一般是reversed域名, 如com.cedarsoft.utils.legacy Versions, 版本號(hào), 1.3.4 [com.cedarsoft.utils.legacy/hibernate "1.3.4"]
Clojure libraries often use the same group-id and artifact-id (as with clj-http), in which case you can omit the group-id.
[clj-http "0.5.5"]
Snapshot Versions
Sometimes versions will end in "-SNAPSHOT". This means that it is not an official release but a development build.
所以自動(dòng)生成的project.clj的版本是帶"-SNAPSHOT": my-stuff "0.1.0-SNAPSHOT"
當(dāng)然盡量不要在dependency里面加snapshot的版本, 除了你知道你在干嗎, 并確實(shí)需要這樣... 另外的原因是對(duì)于snapshot version, leiningen每天都會(huì)去更新最新版, 所以有效率問題...
Adding a snapshot dependency to your project will cause Leiningen to actively go seek out the latest version of the dependency daily (whereas normal release versions are cached in the local repository) so if you have a lot of snapshots it will slow things down.
Artifact IDs, Groups和Namespace的關(guān)系
Note that some libraries make their group-id and artifact-id correspond with the namespace they provide inside the jar, but this is just a convention. There is no guarantee they will match up at all.
Repositories
Dependencies are stored in a maven repository (類似PyPi)
There are several popular open source repositories. Leiningen by default will use two of them: clojars.org and Maven Central.
leiningen需要根據(jù)配置的dependency, 來自動(dòng)的找到這些包, 去哪兒找, 默認(rèn)是clojars.org and Maven Central
可以自行增加third-party repositories You can add third-party repositories by setting the :repositories
key in project.clj. See the sample.project.clj.
5 Running Code
Lein REPL
The REPL is an interactive prompt where you can enter arbitrary code to run in the context of your project.
lein repl和一般的repl相比, 最大的優(yōu)勢是, project context awareness 對(duì)于一般的repl, 能夠被require的包都必須要在classpath底下能夠找到, 如果沒有, 你需要自己去download并配置到classpath里面去 而lein會(huì)自動(dòng)的管理dependency, 只需要在project.clj里面把需要的denpendency寫清楚, lein會(huì)自動(dòng)完成download和classpath配置 所以只需要在project目錄下執(zhí)行l(wèi)ein repl, 即可以require當(dāng)前project namespace的所有代碼, 以及所有denpendency的庫 這個(gè)相當(dāng)方便, 尤其在測試的時(shí)候
需要注意的是, lein repl其實(shí)是可以在任何目錄下執(zhí)行的, 但是如果不是project目錄, 那就和普通repl沒有任何區(qū)別.
Lein REPL還有命令提示, 主要有如下命令
函數(shù)執(zhí)行
user=> (require 'my-stuff.core)niluser=> (my-stuff.core/foo “me”)me Hello, World!nil
如果在denpendency中加了[clj-http "0.5.5"]
user=> (require '[clj-http.client :as http])niluser=> (def response (http/get "http://leiningen.org"))#'user/response
幫助文檔, doc, javadoc, clojuredocs
doc, find-doc顯示幫助文檔 javadoc, 顯示java的幫助文檔
clojuredocs
offers more thorough examples from the ClojureDocs site.
ClojureDocs is a community-powered documentation and examples repository for the Clojure programming language.
clojuredocs這個(gè)挺管用, 比如你不知道reduce怎么用
user=> (user/clojuredocs reduce)
就會(huì)給出很多例子, 也可以直接去網(wǎng)站查, 更好看些, http://clojuredocs.org/clojure_core/clojure.core/reduce
查看源代碼, source
user=> (source my-stuff.core/foo)(defn foo "I don't do a whole lot." [x] (println x "Hello, World!"))nil
Lein Run
如果要使用lein run去運(yùn)行namespace, 必須先實(shí)現(xiàn)-main函數(shù), 因?yàn)閘ein run -m會(huì)在namespace里面找-main, 如果沒有, 會(huì)報(bào)錯(cuò)
(defn -main "I don't do a whole lot." [& args] (println "Hello, World!"))
$ lein run -m my-stuff.coreHello, World!
Providing an alternate -m
argument will tell Leiningen to look for the -main
function in another namespace. Setting a default :main
in project.clj
lets you omit -m
. 比如加上如下配置,
:main my-stuff.core
可以直接運(yùn)行, 不用-m $ lein run Hello, World!
6 Tests
We haven't written any tests yet, but we can run the failing tests included from the project template:
$ lein testlein test my.test.stuffFAIL in (a-test) (stuff.clj:7)FIXME, I fail.expected: (= 0 1) actual: (not (= 0 1))Ran 1 tests containing 1 assertions.1 failures, 0 errors.
Once we fill it in the test suite will become more useful. Sometimes if you've got a large test suite you'll want to run just one or two namespaces at a time; lein test my.test.stuff
will do that. You also might want to break up your tests using test selectors; see lein help test
for more details.
7 Make Jar
Generally speaking, there are three different goals that are typical of Leiningen projects:
An application you can distribute to end-users
A library for other Clojure projects to consume
A server-side application
Uberjar
The simplest thing to do is to distribute an uberjar. This is a single standalone executable jar file most suitable for giving to nontechnical users. 最簡單的方式, 直接打包成可執(zhí)行的jar
- 在project.clj加上:main, 配置-main存在的namespace
- 在namespace聲明中, 加上:gen-class. 不加會(huì)報(bào)錯(cuò)(Error: Could not find or load main class my_stuff.core)
(ns my-stuff.core (:gen-class))3. Generate your uberjar. 會(huì)生成兩個(gè)jar, standalone版本是包含所有依賴包的
$ lein uberjarCompiling my.stuffCompilation succeeded.Created /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jarIncluding my-stuff-0.1.0-SNAPSHOT.jarIncluding clj-http-0.4.1.jarIncluding clojure-1.3.0.jarIncluding lucene-core-3.0.2.jarCreated /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT-standalone.jar
- 象普通jar一樣的執(zhí)行
$ java -jar my-stuff-0.1.0-standalone.jar Hello world.Welcome to my project! These are your args: (Hello world.)
Framework (Uber)jars
看下面的例子, 對(duì)于hadoop這樣framework的包, 無法也無需打包到j(luò)ar里面 因?yàn)楸仨殞?shí)際的運(yùn)行環(huán)境里面有hadoop集群否則, 根本運(yùn)行不了 所以使用:provided, 表示需要, 但是不包含在jar里面, 需要使用者保證運(yùn)行環(huán)境符合.
(project example.hadoop "0.1.0" ... :profiles {:provided {:dependencies [[org.apache.hadoop/hadoop-core "0.20.2-dev"]]}} :main example.hadoop)
Server-side Projects
There are many ways to get your project deployed as a server-side application. Aside from the obvious uberjar approach, simple programs can be packaged up as tarballs with accompanied shell scripts using the lein-tar plugin and then deployed using pallet, chef, or other mechanisms.
Publishing Libraries
If your project is a library and you would like others to be able to use it as a dependency in their projects, you will need to get it into a public repository.
可以將生成的jar發(fā)布到public庫里面
$ lein deploy clojars
8 Getting Started with Eclipse and Counterclockwise
Eclipse的leiningen插件, 使用更方便
http://dev.clojure.org/display/doc/Getting+Started+with+Eclipse+and+Counterclockwise
ctrl+alt+s, 執(zhí)行當(dāng)前cljr文件, 并啟動(dòng)repl