Update tutorial.
[ci skip]
This commit is contained in:
parent
32d722ab2d
commit
fc8aec4284
1 changed files with 61 additions and 50 deletions
111
doc/TUTORIAL.md
111
doc/TUTORIAL.md
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue