Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the chameleon Reference Manual, version 1.0.1, generated automatically by Declt version 3.0 "Montgomery Scott" on Sun May 15 03:31:16 2022 GMT+0.
• Introduction | What chameleon is all about | |
• Systems | The systems documentation | |
• Modules | The modules documentation | |
• Files | The files documentation | |
• Packages | The packages documentation | |
• Definitions | The symbols documentation | |
• Indexes | Concepts, functions, variables and data types |
* Chameleon ** Introduction Chameleon is a configuration management library shipped with profile support. It can help you: 1. Define configuration items with default value. 2. Define profiles reflecting different scenarios, e.g. development, testing, production etc. 3. Switch between several profiles just like a chameleon switching its colors! 4. Access configuration item via functions (instead of bare-bone keywords or strings) to avoid invalid names. 5. Extend its behavior by providing ~:before~, ~:around~ or ~:after~ methods. *Compatibility Note* - Since version 2.0, Chameleon no longer defines ~active-profile~ or ~profiles~. Use ~*profile*~ as the "current" profile and ~*config*~ holds the "current" configuration instance. Also, there will be no default ~NIL~ profile. You cannot access any configuration value without first defining a profile. - Since version 1.2, Chameleon no longer exports generated symbols (including those configuration accessors) by default. This is to avoid compiler complaints when a configuration item is removed. Make it explicit! ** Installation #+BEGIN_SRC lisp ;; Install Chameleon. (ql:quickload :chameleon) ;; Test if it works on your machine. (asdf:test-system :chameleon) #+END_SRC ** Usage The main entry points of Chameleon are 2 macros: ~defconfig~ and ~defprofile~, which defines the configuration set schema and profiles. *** Defining a Configuration Set with ~defconfig~ The following example demonstrates a real-world scenario taken from my [[https://github.com/sheepduke/silver-brain][Silver Brain]] repository. #+BEGIN_SRC lisp (defpackage config (:use #:cl) (:export #:*profile* #:switch-profile #:server-port)) (in-package config) (defconfig (data-dir) (log-level :info) (server-port 5000 "The port of running server.") #+END_SRC The code above defines a configuration set with 3 items. Each item briefly follows the pattern of ~defvar~, i.e. ~(name [initial-value [documentation]])~: - ~name~ is a symbol not evaluated. - ~initial-value~ is a form and always evaluated. Unlike ~defvar~, it is evaluated during every macro expansion. - ~documentation~ is a string, not evaluated. It will generate: - A variable ~*profile*~ indicating current profile name. Defaults to ~NIL~. - A class ~config~ containing configuration items as slots. - A variable ~*config*~ indicating current configuration instance. Defaults to ~NIL~. - A generic function ~switch-profile~ that is used to switch the profile. - 3 zero-arity access functions ~data-dir~, ~log-leve~ and ~server-port~ and their ~setf~ version. You need to manually export these symbols in order to use them outside the current package. **Note** The access functions will check the value of configuration item. If the value is a function, i.e. ~functionp~ returns ~T~, it will be invoked and the value is returned. Otherwise, the value is directly returned. It is useful in scenarios where you want to dynamically compute the value of a configuration item. *** Defining Some Profiles with ~defprofile~ A profile consists of values for each configuration item. If an item is missing, the default value will be used. Profiles are isolated. Switching to a profile does not *modify* anything, it just sets the "current profile" to it. Also changing values defined in one profile does not affect other profiles. Given the ~defconfig~ code above, we may write: #+BEGIN_SRC lisp ;; Define a profile with default values. (defprofile :default) ;; Define a profile with name :DEV. (defprofile :dev (server-port 5001) (data-dir (truename "~/temp/silver-brain/")) (log-level (lambda () (print "Evaluated on every access") (print "Definitely useless for simply T") :debug)))) ;; Port equals to the default value, i.e. 5000. (defprofile :prod (data-dir (truename "~/.silver-brain/"))) ;; When running integration tests, the port is randomly picked. ;; ;; Macro EVAL-ONCE is no more than a let-over-lambda that caches the ;; evaluation result. The function FIND-PORT:FIND-PORT is invoked only ;; once. (defprofile :test (server-port (eval-once (find-port:find-port)))) #+END_SRC #+BEGIN_SRC lisp (defpackage config-user (:use #:cl)) (in-package config-user) ;; Set profile to :DEFAULT. (config:switch-profile :default) (config:server-port) ; => 5000 (13 bits, #x1388) #+END_SRC *** Generated Helper Functions/Macros These helper functions and/or macros will be generated into the caller package. The following example assumes that these has been exported. #+BEGIN_SRC lisp ;; Temporally set profile to :DEFAULT and evaluate body. (config:with-profile :default (server-port)) ; => 5000 (13 bits, #x1388) #+END_SRC *** Extending Behavior with ~defmethod~ The ~switch-profile~ generated by ~defconfig~ is a generic function. Each ~defprofile~ generates a implementation method that sets ~*profile*~ and ~*config*~. You may implement your own method to extend its behavior. #+BEGIN_SRC lisp (in-package config-user) (defmethod switch-profile :after (profile) "Reset the log level of log4cl." (log4cl:configure (log-level))) #+END_SRC Then, every time you call ~switch-profile~ to change the current profile, this method is called *after* the profile is set, thus the log4cl get reconfigured by picking up value ~log-level~ defined in target profile.
Next: Modules, Previous: Introduction, Up: Top [Contents][Index]
The main system appears first, followed by any subsystem dependency.
• The chameleon system |
YUE Daian
MIT
Configuration management facilities for Common Lisp with multiple profile support.
1.0.1
alexandria
chameleon.asd (file)
src (module)
Modules are listed depth-first from the system components tree.
• The chameleon/src module |
chameleon (system)
src/
chameleon.lisp (file)
Files are sorted by type and then listed depth-first from the systems components trees.
• Lisp files |
• The chameleon.asd file | ||
• The chameleon/src/chameleon.lisp file |
Next: The chameleon/src/chameleon․lisp file, Previous: Lisp files, Up: Lisp files [Contents][Index]
chameleon.asd
chameleon (system)
Previous: The chameleon․asd file, Up: Lisp files [Contents][Index]
src (module)
src/chameleon.lisp
Next: Definitions, Previous: Files, Up: Top [Contents][Index]
Packages are listed by definition order.
• The chameleon package |
chameleon.lisp (file)
common-lisp
Definitions are sorted by export status, category, package, and then by lexicographic order.
• Exported definitions | ||
• Internal definitions |
Next: Internal definitions, Previous: Definitions, Up: Definitions [Contents][Index]
• Exported macros |
Previous: Exported definitions, Up: Exported definitions [Contents][Index]
Defines a configuration. The body CONFIGS contains multiple items,
with each following this pattern:
(name initial-value &optional docstring)
While calling this macro, all the given names, initial-values and
docstrings are evaluated during macro expansion.
Beneath the surface, DEFCONFIG actually generates the following stuff:
1. A variable *PROFILE*. It stores the current profile which is
desired to be a keyword.
2. A variable *CONFIG*. It stores the current configuration instance.
3. A class named CONFIG. Each item maps to a slot definition:
- name maps to slot name.
- initial-value maps to :initform argument.
- docstring maps to :documentation property of the slot.
4. A zero-arity inline function (and its setf version) for each
name. The function returns configuration value of current
profile. When the value itself is a function, it is called every
time and the value is returned. Otherwise, the value is directly
returned.
5. Some other helper functions and macros:
- with-profile
A typical example is:
(defconfig
(server-port 5001 "The server port.")
(app-dir "/tmp"))
chameleon.lisp (file)
Defines a profile with given NAME. CONFIGS is one or more lists,
with each following this pattern: (name value).
The evaluation rule of value follows DEFCONFIG.
It generates a variable *CONFIG-<NAME>* and a method SWITCH-PROFILE.
You may provide :before, :around or :after methods to SWITCH-PROFILE to insert some code.
chameleon.lisp (file)
Defines a closure to evaluate BODY for only once.
chameleon.lisp (file)
Previous: Exported definitions, Up: Definitions [Contents][Index]
• Internal functions | ||
• Internal conditions |
Next: Internal conditions, Previous: Internal definitions, Up: Internal definitions [Contents][Index]
Convert given ITEM to CLOS slot. ITEM should be the a 2 or 3 length pair in config definition.
chameleon.lisp (file)
chameleon.lisp (file)
chameleon.lisp (file)
Make a keyword out of given string THING. The keyword is guaranteed to be upper case.
chameleon.lisp (file)
Previous: Internal functions, Up: Internal definitions [Contents][Index]
chameleon.lisp (file)
error (condition)
Previous: Definitions, Up: Top [Contents][Index]
• Concept index | ||
• Function index | ||
• Variable index | ||
• Data type index |
Next: Function index, Previous: Indexes, Up: Indexes [Contents][Index]
Jump to: | C F L M |
---|
Jump to: | C F L M |
---|
Next: Variable index, Previous: Concept index, Up: Indexes [Contents][Index]
Jump to: | C D E F M |
---|
Jump to: | C D E F M |
---|
Next: Data type index, Previous: Function index, Up: Indexes [Contents][Index]
Previous: Variable index, Up: Indexes [Contents][Index]
Jump to: | C N P S |
---|
Jump to: | C N P S |
---|