diff options
authorMatthias Beyer <>2018-04-18 14:35:10 +0200
committerGitHub <>2018-04-18 14:35:10 +0200
commit13e692404723574f62eb3ea0af6df0173e5c0a7f (patch)
parent88b57910dfa63c935f67ee3c0c94106f0f525749 (diff)
parent4e3101f5f3a6314e52e90da490b68cf6d487bcf6 (diff)
Merge pull request #1359 from matthiasbeyer/doc-writing-modules
Add guide on how to write modules
1 files changed, 100 insertions, 0 deletions
diff --git a/doc/src/ b/doc/src/
new file mode 100644
index 0000000..cc41a00
--- /dev/null
+++ b/doc/src/
@@ -0,0 +1,100 @@
+# Writing an imag module
+So you want to write a module for imag.
+That's nice.
+This guide helps you getting started.
+It also can help you understanding how imag modules work, so even if you do
+not want to write a full new module, but extend or alter one, this guide may
+help you.
+## Data layout
+First, you have to think about what data you want to store.
+What functionality do you want to provide and what data that creates.
+In this example, we're writing a module that stores numbers. We're writing the
+appropriate library for that as well as a commandline frontend.
+## libimagnumberstorage
+We're writing a `libimagnumberstorage` which provides the core functionality
+of our module: Storing numbers.
+That library can then be used by other library authors and by the commandline
+interface implementation.
+### Setup
+So what do we need to do to write this library:
+1. Create a new "lib" crate.
+ Because we're writing a "domain" library, we're doing this in the
+ `lib/domain` subdirectory:
+ `cd lib/domain; cargo new --lib libimagnumberstorage`.
+1. After creating the library, we have to add the new library to the
+ `/Cargo.toml` field and add the missing metadata in the new
+ `/lib/domain/libimagnumberstorage/Cargo.toml` file.
+That was the setup part.
+Now we can implement our functionality.
+For that, we need to _extend_ two types from `libimagstore`, so we have our
+first dependency here.
+### Dependencies to other libraries
+3. Put `libimagstore` as a dependency in the
+ `/lib/domain/libimagnumberstorage/Cargo.toml` file.
+ By using
+ `libimagstore = { version = "0.7.0", path = "../../../lib/core/libimagstore" }`
+ we automatically get all the goodness of Cargo, so that releases
+ automagically work as expected, but when developing locally, the local
+ version of `libimagstore` is used.
+ Of course, the `version` has to be the latest released version.
+4. For error handling, we also need to import `libimagerror`.
+5. For easy header-editing, we import `toml` and `toml-query`.
+6. For error-type creating, we import `error-chain`.
+### Interface
+7. Then, we have to _extend_ two types:
+ 1. `libimagstore::store::Store` has to be extended so we can implement a
+ CRUD interface for our special entries.
+ 1. `libimagstore::store::Entry` has to be extended so we can get our
+ stored numbers in a convenient way.
+Our interface should roughly look like this:
+store.get_stored_number("5") -> Result<FileLockEntry, _>
+store.store_number("5") -> Result<FileLockEntry, _>
+store.delete_number("5") -> Result<(), _>
+You notice that the `Store` returns `FileLockEntry` objects rather than
+`Entry` objects.
+And that's ok. A `FileLockEntry` is a `Entry`, but ensures that we are the
+only ones editing that entry.
+So, we have to implement our number-storing-interface on `Entry` as well:
+entry.get_number() -> Result<usize>
+entry.set_number(usize) -> Result<()>
+All those "extensions" are implemented as traits which are then implemented
+for `Store` and `Entry`.
+Normally, we create new files for that, as well as for the error types we need:
+* `/lib/domain/libimagnumberstorage/src/`
+* `/lib/domain/libimagnumberstorage/src/`
+* `/lib/domain/libimagnumberstorage/src/`
+where `` contains a trait `NumberStorage` and `` contains a
+trait `NumberEntry`.
+`` contains the invocation of the `error_chain!{}` macro.
+Error types from `libimagstore` and others are linked in.