Update tutorial.

[ci skip]
This commit is contained in:
Phil Hagelberg 2012-03-06 14:49:39 -08:00
parent 32d722ab2d
commit fc8aec4284

View file

@ -21,22 +21,21 @@ Generating a new project is easy:
|-- project.clj
|-- README.md
|-- src
| `-- my
| `-- stuff.clj
| `-- my_stuff
| `-- core.clj
`-- test
`-- my
`-- test
`-- stuff.clj
`-- my_stuff
`-- core_test.clj
Here we've got your project's README, a `src/` directory containing the
code, a `test/` directory, and a `project.clj` file which describes your
project to Leiningen. The `src/my/stuff.clj` file corresponds to
the `my.stuff` namespace.
Note that we use `my.stuff` instead of just `stuff` since
single-segment namespaces are discouraged in Clojure. Also if you have
namespaces with dashes in the name, the corresponding file will need
to use underscores instead since the JVM has trouble loading files
Note that we use `my-stuff.core` instead of just `my-stuff` since
single-segment namespaces are discouraged in Clojure. Also note that
namespaces with dashes in the name will have the corresponding file
named with underscores instead since the JVM has trouble loading files
with dashes in the name.
## Packaging
@ -46,7 +45,7 @@ fairly useless:
$ lein jar
Created ~/src/my-stuff/my-stuff-0.1.0-SNAPSHOT.jar
Created ~/src/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jar
Libraries for the JVM are packaged up as .jar files, which are
basically just .zip files with a little extra JVM-specific metadata.
@ -62,15 +61,18 @@ repositories for you.
```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.3.0"]])
```
Fill in the `:description` with a short sentence so that your project
will show up in search results once you publish it. At some point
you'll need to flesh out the README too, but for now let's skip ahead
to setting `:dependencies`. Note that Clojure is just another
dependency here. Unlike most languages, it's easy to swap out any
version of Clojure.
will show up in search results once you publish it, and be sure to fix
the `:url` as well. At some point you'll need to flesh out the README
too, but for now let's skip ahead to setting `:dependencies`. Note
that Clojure is just another dependency here. Unlike most languages,
it's easy to swap out any version of Clojure.
## Dependencies
@ -89,13 +91,13 @@ The `lein search` command will search each remote repository:
This shows two versions available with the dependency vector notation
for each. You can copy one of these directly into the `:dependencies`
section in `project.clj`.
vector in `project.clj`.
The "artifact id" here is "lancet", and "1.0.1" is the version you
require. Every library also has a "group id", though for Clojure
libraries it is often the same as the artifact-id, in which case you
may leave it out of the Leiningen dependency notation. For Java
libraries often a reversed domain name is used as the group id.
may omit it. For Java libraries often a reversed domain name is used
as the group id.
Sometimes versions will end in "-SNAPSHOT". This means that it is not
an official release but a development build. Relying on snapshot
@ -116,7 +118,7 @@ install the current project in the local repository with this command:
$ lein install
Wrote pom.xml
Wrote ~/src/my-stuff/target/pom.xml
[INFO] Installing my-stuff-0.1.0-SNAPSHOT.jar to ~/.m2/repository/myproject/myproject/0.1.0-SNAPSHOT/myproject-0.1.0-SNAPSHOT.jar
Note that some libraries make their group-id and artifact-id
@ -134,9 +136,9 @@ in project.clj. See the
Sometimes you want to pull in dependencies that are really only
necessary while developing; they aren't required for the project to
function in production. You can do this by adding a `:dependencies`
entry to the `:dev` profile. These will be available by default unless
you specify another profile from the defaults, but they are not
brought along when another project depends on your project.
entry to the `:dev` profile. These will be available unless you
specify different profiles using the `with-profiles` task, but they
are not brought along when another project depends on your project.
Using [midje](https://github.com/marick/Midje) for your tests would be
a typical example; you would not want it included in production, but it's
@ -145,13 +147,16 @@ needed to run the tests:
```clj
(defproject my-stuff "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[clojure "1.3.0"]]
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.3.0"]]
:profiles {:dev {:dependencies [[midje "1.3.1"]]}})
```
Note that profile-specific dependencies are different from plugins in
context; plugins run in Leiningen's process while dependencies run in
your project itself.
your project itself. (Older versions of Leiningen lacked this distinction.)
If you have dependencies that are not _necessary_ for developing but
just for convenience (things like
@ -200,7 +205,7 @@ this, you attach metadata to various deftests.
(is (= [1 2 3] (:numbers (network-operation)))))
```
Then add a :test-selectors map to project.clj:
Then add a `:test-selectors` map to project.clj:
```clj
:test-selectors {:default (complement :integration)
@ -214,10 +219,10 @@ the integration tests and `lein test :all` will run everything. You
can include test selectors and listing test namespaces in the same
run.
Running `lein test` from the command-line is not a good solution for
test-driven development due to the slow startup time of the JVM. For
quick feedback, either keep a repl open for running the appropriate
call to
Running `lein test` from the command-line is suitable for regression
testing, but the slow startup time of the JVM makes it a poor fit for
testing styles that require tighter feedback loops. In these cases,
either keep a repl open for running the appropriate call to
[clojure.test/run-tests](http://clojuredocs.org/clojure_core/1.3.0/clojure.test/run-tests)
or look into editor integration such as
[clojure-test-mode](https://github.com/technomancy/clojure-mode).
@ -228,7 +233,7 @@ the files on disk—functions that are loaded and then deleted from the
file will remain in memory, making it easy to miss problems arising
from missing functions (often referred to as "getting
slimed"). Because of this it's advised to do a `lein test` run with a
fresh instance periodically, perhaps before you commit.
fresh instance periodically in any case, perhaps before you commit.
## AOT Compiling
@ -253,13 +258,7 @@ outside a function definition that doesn't start with "def" is
suspect. If you have code that should run on startup, place it in a
`-main` function as explained below under "Uberjar".
For projects that include some Java code, you can set the
`:java-source-path` key in project.clj to a directory containing Java
files. (You can set it to "src" to keep Java alongside Clojure source
or keep them it in a separate directory.) Then the javac compiler will
run before your Clojure code is AOT-compiled, or you can run it
manually with the `javac` task.
<!-- TODO: this hasn't been ported to 2.x yet
There's
[a problem in Clojure](http://dev.clojure.org/jira/browse/CLJ-322)
where AOT-compiling a namespace will also AOT compile all the
@ -268,6 +267,14 @@ artifacts to be included in the jars, but you can set
`:class-file-whitelist` to a regex which will be matched against
.class file names you want to keep in order to remove the unwanted
file.
-->
For projects that include some Java code, you can set the
`:java-source-paths` key in project.clj to a vector of directories
containing Java files. (You can set it to ["src"] to keep Java
alongside Clojure source or keep them in a separate directory.) Then
the `javac` compiler will run before your Clojure code is AOT-compiled,
or you can run it manually with the `javac` task.
## What to do with it
@ -278,10 +285,10 @@ of Leiningen projects:
* A server-side application
* A library for other Clojure projects to consume
For the first, you typically either build an uberjar or use a
shell-wrapper. For libraries, you will want to have them published to
a repository like Clojars or a private repository. For server-side
applications it varies as described below.
For the first, you typically either build an uberjar. For libraries,
you will want to have them published to a repository like Clojars or a
private repository. For server-side applications it varies as
described below.
### Uberjar
@ -293,10 +300,14 @@ namespace as your `:main` in `project.clj`. By this point our
```clj
(defproject my-stuff "0.1.0-SNAPSHOT"
:description "This project is MINE."
: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.3.0"]
[org.apache.lucene/lucene-core "3.0.2"]
[lancet "1.0.0"]]
:profiles {:dev {:dependencies [[midje "1.3.1"]]}}
:test-selectors {:default (complement :integration)
:integration :integration
:all (fn [_] true)}
@ -320,7 +331,6 @@ something simple in `src/my/stuff.clj`:
Now we're ready to generate your uberjar:
$ lein uberjar
Cleaning up
Compiling my.stuff
Compilation succeeded.
Created /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jar
@ -328,7 +338,7 @@ Now we're ready to generate your uberjar:
Including lancet-1.0.0.jar
Including clojure-1.2.0.jar
Including lucene-core-3.0.2.jar
Created my-stuff-0.1.0-standalone.jar
Created /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT-standalone.jar
This creates a single jar file that contains the contents of all your
dependencies. Users can run it with a simple `java` invocation,
@ -341,8 +351,6 @@ You can run a regular (non-uber) jar with the `java`
command-line tool, but that requires constructing the classpath
yourself, so it's not a good solution for end-users.
TODO: emphasize lein run; perhaps on the same level as uberjar
Invoking `lein run` will launch your project's `-main` function as if
from an uberjar, but without going through the packaging process. You
can also specify an alternate namespace in which to look for `-main`
@ -354,6 +362,7 @@ launching your project's JVM. This can save memory:
$ lein trampoline run -m my-stuff.server 5000
<!-- TODO: not ported to 2.x yet
### Shell Wrappers
There are a few downsides to uberjars. It's relatively awkward to
@ -386,6 +395,7 @@ classpath and the main namespace, so put %s in the right place. See
[the default
wrapper](https://github.com/technomancy/leiningen/blob/stable/resources/script-template)
for an example.
-->
### Server-side Projects
@ -407,9 +417,10 @@ plugins rather than tasks that are built-in to Leiningen itself.
It may be tempting to deploy by just checking out your project and
using "lein run" on production servers. However, unless you take steps
to freeze all the dependencies before deploying, it could be easy to
end up with unrepeatable deployments. It's much better to use
Leiningen to create a deployable artifact in a continuous integration
setting instead. For example, you could have a
end up with
[unrepeatable deployments](https://github.com/technomancy/leiningen/wiki/Repeatability).
It's much better to use Leiningen to create a deployable artifact in a
continuous integration setting instead. For example, you could have a
[Jenkins](http://jenkins-ci.org) CI server run your project's full
test suite, and if it passes, upload a tarball to S3. Then deployment
is just a matter of pulling down and extracting the known-good tarball
@ -426,7 +437,7 @@ or get it into Maven central, the easiest way is to publish it at
publishing is easy:
$ lein jar, pom
$ scp pom.xml my-stuff-0.1.0.jar clojars@clojars.org:
$ scp target/pom.xml target/my-stuff-0.1.0.jar clojars@clojars.org:
Once that succeeds it will be available as a package on which other
projects may depend. You will need to have permission to publish to