https://github.com/duct-framework/core
The core library of the Duct framework
https://github.com/duct-framework/core
clojure duct framework integrant
Last synced: 6 months ago
JSON representation
The core library of the Duct framework
- Host: GitHub
- URL: https://github.com/duct-framework/core
- Owner: duct-framework
- Created: 2017-04-10T13:59:27.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2024-01-23T20:23:12.000Z (almost 2 years ago)
- Last Synced: 2025-06-09T14:51:11.774Z (7 months ago)
- Topics: clojure, duct, framework, integrant
- Language: Clojure
- Homepage:
- Size: 171 KB
- Stars: 77
- Watchers: 3
- Forks: 21
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# Duct core
[](https://travis-ci.org/duct-framework/core)
The core of the next iteration of the [Duct][] framework. It extends
the [Integrant][] micro-framework with support for modules, asset
compilation and environment variables.
[duct]: https://github.com/duct-framework/duct
[integrant]: https://github.com/weavejester/integrant
## Installation
To install, add the following to your project `:dependencies`:
[duct/core "0.8.1"]
## Usage
First we need to read in an Integrant configuration from a file or
resource:
```clojure
(require '[clojure.java.io :as io]
'[duct.core :as duct])
(defn get-config []
(duct/read-config (io/resource "example/config.edn")))
```
Once we have a configuration, we have three options. The first option
is to `prep-config` the configuration, which will load in all relevant
namespaces and apply all modules.
This is ideally used with `integrant.repl`:
```clojure
(require '[integrant.repl :refer :all])
(set-prep! #(duct/prep-config (get-config)))
```
Alternatively we can `prep-config` then `exec-config` the configuration. This
initiates the configuration, then blocks the current thread if the
system includes any keys deriving from `:duct/daemon`. This is
designed to be used from the `-main` function:
```clojure
(defn -main []
(-> (get-config) (duct/prep-config) (duct/exec-config)))
```
You can change the executed keys to anything you want by adding in an
additional argument. This is frequently used with the `parse-keys`
function, which parses keywords from command-line arguments:
```clojure
(defn -main [& args]
(let [keys (or (duct/parse-keys args) [:duct/daemon])]
(-> (get-config)
(duct/prep-config keys)
(duct/exec-config keys))))
```
This allows other parts of the system to be selectively executed. For
example:
```
lein run :duct/compiler
```
Would initiate all the compiler keys. And:
```
lein run :duct/migrator
```
Would initiate the migrator and run all pending migrations. If no
arguments are supplied, the keys default to `[:duct/daemon]` in this
example.
## Keys
This library introduces a number of Integrant components:
* `:duct/const` is a component that returns its value when initialized.
* `:duct/module` denotes a Duct module (see the modules section).
* `:duct/profile` denotes a Duct profile (see the profiles section).
* `:duct.core/environment` specifies the environment of the
configuration, and may be set to `:development` or `:production`. It
does nothing on its own, but may be used by modules.
* `:duct.core/project-ns` specifies the base namespace of your
project. This is often used by modules for determining where to put
things. For example, public web resources are typically placed in the
`resources//public` directory.
## Readers
This library also introduces five new reader tags that can be used in
Duct configurations:
* `#duct/env "VARNAME"` allows an environment variable to be
referenced in the configuration.
* `#duct/include "path"` will include replace the tag with the
resource at the specified path. This allows a configuration to be
split up into separate files.
* `#duct/resource "path"` will convert a resource path into a URL
* `#duct/displace` is equivalent to `^:displace`, but works with
primitive values
* `#duct/replace` is equivalent to `^:replace`, but works with
primitive values
## Modules
Modules are Integrant components that initialize into a pure
function. This function expects a configuration as its argument, and
returns a modified configuration.
Most modules derive from `:duct/module`. This both identifies them,
and ensures they are executed after profiles.
Here's a simple example module:
```clojure
(require '[integrant.core :as ig])
(derive :duct.module/example :duct/module)
(defmethod ig/init-key :duct.module/example [_ {:keys [port]}]
(fn [config]
(assoc-in config [:duct.server.http/jetty :port] port)))
```
This above module updates the port number of the `:duct.server.http/jetty`
key. By itself this isn't hugely useful, but modules can be made to
update many different components at once.
Modules can also have dependencies, achieved using
`integrant.core/prep-key`:
```clojure
(defmethod ig/prep-key :duct.module/example [_ options]
(assoc options ::requires (ig/ref :duct.module/parent)))
```
This adds a reference to the module's options, ensuring that Integrant
will initialize the `:duct.module/parent` module before
`:duct.module/example`.
You can also have optional dependencies with `integrant.core/refset`:
```clojure
(defmethod ig/prep-key :duct.module/example [_ options]
(assoc options ::requires (ig/refset #{:duct.module/parent})))
```
## Profiles
A profile is (currently) a type of module that merges the value of the
key into the resulting configuration.
There are five profile keys included in this library:
* `:duct.profile/base` is the base of all new profiles
* `:duct.profile/dev` is a profile for development
* `:duct.profile/local` is a profile only on your local development
machine
* `:duct.profile/test` is a profile for testing
* `:duct.profile/prod` is a profile for production
## Documentation
* [API Docs](https://duct-framework.github.io/core/index.html)
## License
Copyright © 2020 James Reeves
Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.