Duct 0.11 νλ‘μ νΈμ μ£Όμ λ³κ²½ μ¬νμ μκ°ν©λλ€. μ΄ λ¬Έμλ λ³κ²½ μ¬νμ μμΈν μ€λͺ νκ³ κ·Έλ κ² κ΅¬ν λ μ΄μ λ₯Ό μ€λͺ ν©λλ€.
μ΄ λ³κ²½ μ¬νμ μν λ²μ μ ꡬνλμ΄ μκ³ μλμ κ°μ΄ ν μ€νΈ ν΄λ³Ό μ μμ΅λλ€:
lein new duct-alpha <project> <hints...>
0.10 μ΄ν λ²μ μμλ λͺ¨λμ λ§λ€ λ μλ μ²λΌ μ½λλ₯Ό μμ±νμ΅λ€:
(defmulti ig/init-key ::module [_ options]
{:req [::precondition]
:fn (fn [config] config)})λͺ¨λμ μ΄κΈ°ν νλ ν€λ λ§΅μ 리ν΄ν©λλ€. :fn ν€λ μ€μ μ λ³κ²½νλλ° μ¬μ©νλ μμ ν¨μμ
λλ€.
:req ν€λ λͺ¨λμ΄ μ΄κΈ°ν λκΈ° μ μ μ€μ μ νμν νμ ν€ μ»¬λ μ
μ
λλ€. νμ ν€λ Ductκ° κ° λͺ¨λμ΄
μμ‘΄μ±μ λ§μΆ° μμλλ‘ μ μ©νκΈ° μν΄ νμν©λλ€.
λ¬Έμ λ μ΄λ―Έ Integrantμ μμ‘΄μ±μ κ΄λ¦¬νκΈ° μν μ λ§λ€μ΄μ§ κΈ°λ₯μ΄ μλ€λ κ²μ λλ€. μμ‘΄μ± μμλ₯Ό μν λ κ°μ κ°λ³ μμ€ν μ΄ μλ κ² λ³΄λ€ λͺ¨λ ν€μ μΌλ° ν€λ₯Ό νλμ μμ€ν μΌλ‘ μ°λ κ²μ΄ λ ν©λ¦¬μ μ λλ€.
μ΄μ λ²μ μ Integrantμ μ€μ μ λ³κ²½νλ λ°©λ² μΈμ μ°Έμ‘° ν€λ₯Ό μΆκ°ν λ°©λ²μ΄ μμμ΅λλ€. λͺ¨λμ΄ λ€λ₯Έ ν€μ μμ‘΄ νλ€λ©΄ μλμΌλ‘ μ°Έμ‘°λ₯Ό μΆκ°ν μ μλ λ°©λ²μ΄ νμν©λλ€.
μ΄λ₯Ό μν΄ Integrant 0.7μ prep-key λ©ν°λ©μλκ° μΆκ°λμμ΅λλ€. prep-key λ©ν°λ©μλλ
μ€μ μ΄ μ΄κΈ°νλκΈ° μ μ prep ν¨μμ μν΄ λΆλ¦½λλ€. μ΄λ κ² νλ©΄ μ€μ μ μμ±ν νμλ μ°Έμ‘°λ₯Ό μΆκ°ν΄
μμ‘΄μ± μμλ₯Ό λ§λ€ μ μμ΅λλ€.
Duct λ²μ 0.11 μ΄ν λͺ¨λμ λ€μκ³Ό κ°μ΄ μμ±ν©λλ€:
(defmulti ig/prep-key ::module [_ options]
(assoc options ::requires (ig/ref ::precondition)))
(defmulti ig/init-key ::module [_ options]
(fn [config] config))prep λ¨κ³μ λͺ¨λμ΄ νμν λ€λ₯Έ ν€μ λν μ°Έμ‘°λ ::requires νλΌμ΄λΉ ν€μ μΆκ° λ©λλ€.
λͺ¨λμ΄ μ΄κΈ°ν λ λ ::precondition ν€ λ€μμ ::module ν€κ° μ΄κΈ°ν λλλ‘ λ³΄μ₯ν΄ μ€λλ€.
μ΄μ λ²μ μ ductμλ λͺ¨λ ν€μ μΌλ° Integrant ν€κ° κ°μ μ€μ μ μμμ΅λλ€:
{:duct.core/project-ns foo
:duct.module/example {}}νμ§λ§ μ΄λ° λ°©μμ μ°λ©΄ μ΄κΈ°νλ₯Ό νκΈ° μ μ λͺ¨λ ν€μ μΌλ° ν€κ° λΆλ¦¬λμ΄μΌ νλ λ¬Έμ κ° μμ΅λλ€. λ λͺ¨λ ν€μ μΌλ° ν€κ° λ νΌλ°μ€λ₯Ό 곡μ νλ©΄ λ¬Έμ κ° λ μλ μμ΅λλ€.
κ°μ μ€μ λ§΅μ λͺ¨λ ν€μ μΌλ° ν€κ° ν¨κ» μλ κ²μ νΈλ¦¬νμ§λ§ μΆμνλ₯Ό κΉ° μ μμ΅λλ€.
ν΄κ²° λ°©λ²μ λͺ¨λ ν€λ₯Ό μΌλ° ν€λ‘ λΆν° λͺ ννκ² λΆλ¦¬νλ κ²μ λλ€. Duct 0.11 λ²μ μλ λͺ¨λ λͺ¨λ ν€μ μ΄ λ°©λ²μ μ μ©λμμ΅λλ€. μΌλ° ν€λ μλμ κ°μ΄ νλ‘ν μμ μλλ€:
{:duct.profile/base {:duct.core/project-ns foo}
:duct.module/example {}}νλ‘νμ λ¨μν νλ‘ν μ€μ κ°μ μ 체 μ€μ κ°μ meta-merge νλ λͺ¨λ μ λλ€.
κ·Έ κ²°κ³Ό κ³μΈ΅ μ¬μ΄μ λͺ νν λΆλ¦¬λ κ³μΈ΅ ꡬ쑰λ₯Ό λ§λλλ€: Duct μ€μ μ λμνλ μμ€ν μ νμν μμ‘΄μ±κ³Ό ν¨κ» Integrant μ€μ μ λ§λλλ€.
νλ‘νμ΄ λ€λ₯Έ λͺ¨λμ΄ μμλκΈ° μ μ μ€ν λλ κ²μ 보μ₯νλ €λ©΄ μμ‘΄μ±μ μ μν λ°©λ²μ΄ νμν©λλ€. μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ Integrant 0.7 λ²μ μ refsets κΈ°λ₯μ΄ μΆκ°λμμ΅λλ€. Refsetμ ref μ²λΌ λμνλλ° λ§€μΉλλ λͺ¨λ ν€μ setμ μμ±ν΄ μ€λ€λ μ μ΄ refμ λ€λ¦ λλ€.
:duct/profile μ μμν ν€κ° μ€ν λ νμ :duct/module μ μμν ν€λ₯Ό μ μ©νκΈ° μν΄
refsetμ μΈ μ μμ΅λλ€. duct.core μ μλμ κ°μ΄ μ μ λμ΄ μμ΅λλ€:
(defmethod ig/prep-key :duct/module [_ profile]
(assoc profile ::requires (ig/refset :duct/profile)))refμ refset, ν€μλ μμ κ°μ 볡μ‘νμ§λ§ μμΈ‘ κ°λ₯ν μμ‘΄μ± κ·Έλνλ₯Ό μ€μ ν μ μμ΅λλ€.
In version 0.10 and below, includes were handled by a special key,
:duct.core/include:
{:duct.core/include ["example"]}This will look for a resource named example.edn and meta-merge it
into the configuration.
There are two problems with this approach.
The first and most obvious issue is that it requires one key to have a special function, one that isn't defined by a standard multimethod. It cannot be a module because it's side-effectful.
The second issue is that it introduces new side-effects after the configuration has been read. Ideally we want reading the configuration to happen at the same step.
In version 0.11 the :duct.core/include key is replaced with the
#duct/include reader tag. The tag is replaced by the contents of
the referenced resource. If we want to merge it into the
configuration, we place it in a profile:
{:duct.profile/example #duct/include "example"]}This ensures all the included configurations are read together by
read-config, and moves the complexities of merging into the
profiles.
This approach also allows smaller chunks of data to be included from external files, rather than full configurations.
The changes represent an overall simplification of the module and include system:
- Modules and normal components are separated.
- Modules no longer use their own dependency management.
- Merging is separated out into profiles.
- Including other configurations happens at read time.
- No keys with 'special' functionality.
In addition to the simplification, extra functionality has been added:
prep-keyremoves the need for modules in simple casesrefsetallows for more sophisticated dependencies