From 4e3101f5f3a6314e52e90da490b68cf6d487bcf6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 9 Mar 2018 12:34:07 +0100 Subject: Add guide on how to write modules --- doc/src/03020-writing-modules.md | 100 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 doc/src/03020-writing-modules.md (limited to 'doc') diff --git a/doc/src/03020-writing-modules.md b/doc/src/03020-writing-modules.md new file mode 100644 index 00000000..cc41a008 --- /dev/null +++ b/doc/src/03020-writing-modules.md @@ -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 +store.store_number("5") -> Result +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 +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/store.rs` +* `/lib/domain/libimagnumberstorage/src/entry.rs` +* `/lib/domain/libimagnumberstorage/src/error.rs` + +where `store.rs` contains a trait `NumberStorage` and `entry.rs` contains a +trait `NumberEntry`. +`error.rs` contains the invocation of the `error_chain!{}` macro. +Error types from `libimagstore` and others are linked in. + -- cgit v1.2.3