...for the next release, which will be imag 0.10.0! Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
3.4 KiB
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:
- 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
. - 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
- Put
libimagstore
as a dependency in the/lib/domain/libimagnumberstorage/Cargo.toml
file. By usinglibimagstore = { version = "0.10.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 oflibimagstore
is used. Of course, theversion
has to be the latest released version. - For error handling, we also need to import
libimagerror
. - For easy header-editing, we import
toml
andtoml-query
. - For error-type creating, we import
error-chain
.
Interface
- Then, we have to extend two types:
libimagstore::store::Store
has to be extended so we can implement a CRUD interface for our special entries.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.