Merge pull request #1359 from matthiasbeyer/doc-writing-modules
Add guide on how to write modules
This commit is contained in:
commit
13e6924047
1 changed files with 100 additions and 0 deletions
100
doc/src/03020-writing-modules.md
Normal file
100
doc/src/03020-writing-modules.md
Normal file
|
@ -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/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.
|
||||||
|
|
Loading…
Reference in a new issue