Merge pull request #1181 from matthiasbeyer/libimagentryutil/init

libimagentryutil: init
This commit is contained in:
Matthias Beyer 2018-01-09 10:59:07 +01:00 committed by GitHub
commit 4d00554d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 316 additions and 50 deletions

View File

@ -44,6 +44,7 @@ members = [
"lib/entry/libimagentrymarkdown",
"lib/entry/libimagentryref",
"lib/entry/libimagentrytag",
"lib/entry/libimagentryutil",
"lib/entry/libimagentryview",
"lib/etc/libimaginteraction",
"lib/etc/libimagnotification",

View File

@ -0,0 +1,6 @@
## libimagentryutil
This library contains utilities for working with
`libimagstore::store::Entry` objects where the functionality does not
necessarily belong into `libimagstore`.

View File

@ -29,6 +29,8 @@ This section contains the changelog from the last release to the next release.
* `libimagstore::store::Store::retrieve_copy` was renamed to
`libimagstore::store::Store::get_copy`, which describes the semantics of
the function way better.
* `libimagentryutil` was introduced, a library for helpers for
`libimagstore::store::Entry` handling and writing extension-writing.
* Minor changes
* Internals were refactored from `match`ing all the things into function
chaining

View File

@ -23,4 +23,5 @@ vobject = "0.4"
libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }
libimagentryref = { version = "0.6.0", path = "../../../lib/entry/libimagentryref/" }
libimagentryutil = { version = "0.6.0", path = "../../../lib/entry/libimagentryutil/" }

View File

@ -20,14 +20,12 @@
use std::ops::Deref;
use vobject::Component;
use toml::Value;
use toml_query::read::TomlValueReadExt;
use libimagstore::store::Entry;
use libimagentryref::reference::Ref;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
use error::ContactError as CE;
use error::ContactErrorKind as CEK;
use error::Result;
use util;
@ -46,15 +44,12 @@ pub trait Contact : Ref {
}
provide_kindflag_path!(pub IsContact, "contact.is_contact");
impl Contact for Entry {
fn is_contact(&self) -> Result<bool> {
let location = "contact.marker";
match self.get_header().read(location)? {
Some(&Value::Boolean(b)) => Ok(b),
Some(_) => Err(CE::from_kind(CEK::HeaderTypeError("boolean", location))),
None => Ok(false)
}
self.is::<IsContact>().map_err(From::from)
}
fn get_contact_data(&self) -> Result<ContactData> {

View File

@ -28,6 +28,7 @@ error_chain! {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
VObjectError(::vobject::error::VObjectError, ::vobject::error::VObjectErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {

View File

@ -42,6 +42,7 @@ extern crate toml_query;
#[macro_use] extern crate libimagstore;
extern crate libimagerror;
extern crate libimagentryref;
#[macro_use] extern crate libimagentryutil;
module_entry_path_mod!("contact");

View File

@ -20,15 +20,15 @@
use std::path::PathBuf;
use vobject::parse_component;
use toml::Value;
use toml_query::insert::TomlValueInsertExt;
use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator;
use libimagentryref::refstore::RefStore;
use libimagentryref::flags::RefFlags;
use libimagentryutil::isa::Is;
use contact::IsContact;
use error::Result;
use util;
@ -71,8 +71,7 @@ impl<'a> ContactStore<'a> for Store {
RefStore::create(self, p.clone(), flags)
.map_err(From::from)
.and_then(|mut entry| {
entry.get_header_mut()
.insert("contact.marker", Value::Boolean(true))
entry.set_isflag::<IsContact>()
.map_err(From::from)
.map(|_| entry)
})

View File

@ -19,10 +19,10 @@ log = "0.3"
toml = "0.4"
toml-query = "0.4.0"
error-chain = "0.11"
is-match = "0.1"
kairos = "0.1.0-beta-2"
libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }
libimagentryedit = { version = "0.6.0", path = "../../../lib/entry/libimagentryedit" }
libimagentrylink = { version = "0.6.0", path = "../../../lib/entry/libimagentrylink" }
libimagentryutil = { version = "0.6.0", path = "../../../lib/entry/libimagentryutil" }

View File

@ -26,6 +26,7 @@ error_chain! {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind);
KairosError(::kairos::error::KairosError, ::kairos::error::KairosErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {

View File

@ -31,6 +31,7 @@ use iter::HabitInstanceStoreIdIterator;
use util::date_to_string;
use util::IsHabitCheck;
use util::get_string_header_from_entry;
use instance::IsHabitInstance;
use libimagentrylink::internal::InternalLinker;
use libimagstore::store::Store;
@ -39,6 +40,8 @@ use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
/// A HabitTemplate is a "template" of a habit. A user may define a habit "Eat vegetable".
/// If the user ate a vegetable, she should create a HabitInstance from the Habit with the
@ -81,6 +84,8 @@ pub trait HabitTemplate : Sized {
fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId>;
}
provide_kindflag_path!(pub IsHabitTemplate, "habit.template.is_habit_template");
impl HabitTemplate for Entry {
fn create_instance_with_date<'a>(&self, store: &'a Store, date: &NaiveDate) -> Result<FileLockEntry<'a>> {
@ -93,10 +98,11 @@ impl HabitTemplate for Entry {
.map_err(From::from)
.and_then(|mut entry| {
{
let _ = entry.set_isflag::<IsHabitInstance>()?;
let hdr = entry.get_header_mut();
hdr.insert("habit.instance.name", Value::String(name))?;
hdr.insert("habit.instance.date", Value::String(date))?;
hdr.insert("habit.instance.comment", Value::String(comment))?;
let _ = hdr.insert("habit.instance.name", Value::String(name))?;
let _ = hdr.insert("habit.instance.date", Value::String(date))?;
let _ = hdr.insert("habit.instance.comment", Value::String(comment))?;
}
Ok(entry)
})
@ -190,16 +196,7 @@ impl HabitTemplate for Entry {
/// Check whether the instance is a habit by checking its headers for the habit data
fn is_habit_template(&self) -> Result<bool> {
[
"habit.template.name",
"habit.template.basedate",
"habit.template.comment",
].iter().fold(Ok(true), |acc, path| acc.and_then(|_| {
self.get_header()
.read(path)
.map(|o| is_match!(o, Some(&Value::String(_))))
.map_err(From::from)
}))
self.is::<IsHabitTemplate>().map_err(From::from)
}
fn habit_name(&self) -> Result<String> {
@ -248,11 +245,13 @@ pub mod builder {
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentryutil::isa::Is;
use error::HabitError as HE;
use error::HabitErrorKind as HEK;
use error::*;
use util::date_to_string;
use habit::IsHabitTemplate;
pub struct HabitBuilder {
name: Option<String>,
@ -324,10 +323,15 @@ pub mod builder {
debug!("Creating entry in store for: {:?}", sid);
let mut entry = try!(store.create(sid));
try!(entry.get_header_mut().insert("habit.template.name", Value::String(name)));
try!(entry.get_header_mut().insert("habit.template.basedate", Value::String(date)));
try!(entry.get_header_mut().insert("habit.template.recurspec", Value::String(recur)));
try!(entry.get_header_mut().insert("habit.template.comment", Value::String(comment)));
let _ = entry.set_isflag::<IsHabitTemplate>()?;
{
let h = entry.get_header_mut();
let _ = h.insert("habit.template.name", Value::String(name))?;
let _ = h.insert("habit.template.basedate", Value::String(date))?;
let _ = h.insert("habit.template.recurspec", Value::String(recur))?;
let _ = h.insert("habit.template.comment", Value::String(comment))?;
}
if let Some(until) = self.untildate {
let until = date_to_string(&until);
try!(entry.get_header_mut().insert("habit.template.until", Value::String(until)));

View File

@ -26,6 +26,8 @@ use error::*;
use util::*;
use libimagstore::store::Entry;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
/// An instance of a habit is created for each time a habit is done.
///
@ -45,18 +47,11 @@ pub trait HabitInstance {
fn get_template_name(&self) -> Result<String>;
}
provide_kindflag_path!(pub IsHabitInstance, "habit.instance.is_habit_instance");
impl HabitInstance for Entry {
fn is_habit_instance(&self) -> Result<bool> {
[
"habit.instance.name",
"habit.instance.date",
"habit.instance.comment",
].iter().fold(Ok(true), |acc, path| acc.and_then(|_| {
self.get_header()
.read(path)
.map(|o| is_match!(o, Some(&Value::String(_))))
.map_err(From::from)
}))
self.is::<IsHabitInstance>().map_err(From::from)
}
fn get_date(&self) -> Result<NaiveDate> {

View File

@ -23,12 +23,12 @@ extern crate toml_query;
extern crate kairos;
#[macro_use] extern crate log;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate is_match;
#[macro_use] extern crate libimagstore;
extern crate libimagerror;
extern crate libimagentryedit;
extern crate libimagentrylink;
#[macro_use] extern crate libimagentryutil;
module_entry_path_mod!("habit");

View File

@ -24,3 +24,4 @@ error-chain = "0.11"
libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }
libimagentrylink = { version = "0.6.0", path = "../../../lib/entry/libimagentrylink" }
libimagentryutil = { version = "0.6.0", path = "../../../lib/entry/libimagentryutil" }

View File

@ -25,6 +25,8 @@ use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagentrylink::internal::InternalLinker;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;
@ -43,6 +45,8 @@ pub trait Annotateable {
fn is_annotation(&self) -> Result<bool>;
}
provide_kindflag_path!(IsAnnotation, "annotation.is_annotation");
impl Annotateable for Entry {
/// Annotate an entry, returns the new entry which is used to annotate
@ -52,9 +56,10 @@ impl Annotateable for Entry {
.map_err(From::from)
.and_then(|mut anno| {
{
let header = anno.get_header_mut();
header.insert("annotation.is_annotation", Value::Boolean(true))?;
header.insert("annotation.name", Value::String(String::from(ann_name)))?;
let _ = anno.set_isflag::<IsAnnotation>()?;
let _ = anno
.get_header_mut()
.insert("annotation.name", Value::String(String::from(ann_name)))?;
}
Ok(anno)
})
@ -96,10 +101,7 @@ impl Annotateable for Entry {
}
fn is_annotation(&self) -> Result<bool> {
self.get_header()
.read("annotation.is_annotation")?
.map(|val| val.as_bool().unwrap_or(false))
.ok_or(AE::from_kind(AEK::HeaderTypeError))
self.is::<IsAnnotation>().map_err(From::from)
}
}

View File

@ -25,6 +25,7 @@ error_chain! {
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {

View File

@ -42,6 +42,7 @@ extern crate toml_query;
#[macro_use] extern crate libimagstore;
extern crate libimagerror;
extern crate libimagentrylink;
#[macro_use] extern crate libimagentryutil;
module_entry_path_mod!("annotations");

View File

@ -31,3 +31,4 @@ walkdir = "1"
libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }
libimagentrylist = { version = "0.6.0", path = "../../../lib/entry/libimagentrylist" }
libimagentryutil = { version = "0.6.0", path = "../../../lib/entry/libimagentryutil" }

View File

@ -26,6 +26,7 @@ error_chain! {
ListError(::libimagentrylist::error::ListError, ::libimagentrylist::error::ListErrorKind);
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
TomlQueryError(::toml_query::error::Error, ::toml_query::error::ErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {

View File

@ -45,6 +45,7 @@ extern crate walkdir;
#[macro_use] extern crate libimagstore;
extern crate libimagerror;
extern crate libimagentrylist;
#[macro_use] extern crate libimagentryutil;
#[macro_use] extern crate error_chain;
module_entry_path_mod!("ref");

View File

@ -25,6 +25,8 @@ use std::fs::File;
use std::fs::Permissions;
use libimagstore::store::Entry;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
use toml::Value;
use toml_query::read::TomlValueReadExt;
@ -38,6 +40,9 @@ use hasher::*;
pub trait Ref {
/// Check whether the underlying object is actually a ref
fn is_ref(&self) -> Result<bool>;
/// Get the hash from the path of the ref
fn get_path_hash(&self) -> Result<String>;
@ -113,9 +118,15 @@ pub trait Ref {
fn get_current_permissions(&self) -> Result<Permissions>;
}
provide_kindflag_path!(pub IsRef, "ref.is_ref");
impl Ref for Entry {
/// Check whether the underlying object is actually a ref
fn is_ref(&self) -> Result<bool> {
self.is::<IsRef>().map_err(From::from)
}
/// Get the hash from the path of the ref
fn get_path_hash(&self) -> Result<String> {
self.get_location()

View File

@ -26,6 +26,7 @@ use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::Store;
use libimagentryutil::isa::Is;
use toml::Value;
@ -34,6 +35,7 @@ use error::RefError as RE;
use error::ResultExt;
use error::Result;
use flags::RefFlags;
use reference::IsRef;
use hasher::*;
use module_path::ModuleEntryPath;
use util::*;
@ -282,6 +284,8 @@ impl RefStore for Store {
}
}
let _ = fle.set_isflag::<IsRef>()?;
Ok(fle)
}

View File

@ -0,0 +1,28 @@
[package]
name = "libimagentryutil"
version = "0.6.0"
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
description = "Library for the imag core distribution"
keywords = ["imag", "PIM", "personal", "information", "management"]
readme = "../../../README.md"
license = "LGPL-2.1"
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
repository = "https://github.com/matthiasbeyer/imag"
homepage = "http://imag-pim.org"
[badges]
travis-ci = { repository = "matthiasbeyer/imag" }
is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" }
is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
maintenance = { status = "actively-developed" }
[dependencies]
toml = "0.4"
toml-query = "0.4"
error-chain = "0.11"
libimagstore = { version = "0.6.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.6.0", path = "../../../lib/core/libimagerror" }

View File

@ -0,0 +1 @@
../../../doc/src/05100-lib-entryutil.md

View File

@ -0,0 +1,32 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
error_chain! {
types {
EntryUtilError, EntryUtilErrorKind, ResultExt, Result;
}
foreign_links {
TomlQueryError(::toml_query::error::Error);
}
errors {
}
}

View File

@ -0,0 +1,129 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
use error::EntryUtilError as EUE;
use error::Result;
use toml::Value;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;
/// Trait to check whether an entry is a certain kind of entry
///
/// If an entry is marked with a `bool` flag in the header to contain a certain amount of data (for
/// example a "wiki" entry may provide some meta information in the `[wiki]` section of its header),
/// this trait provides a check whether the entry has set the flag to `true` or `false`.
///
/// # Note
///
/// This trait is solely for library implementations, as convenience functionality for implementing
/// some function like this:
///
/// # Example
///
/// ```
/// # extern crate libimagstore;
/// # #[macro_use]
/// # extern crate libimagentryutil;
///
/// # use libimagentryutil::error::Result as Result;
/// use libimagentryutil::isa::IsKindHeaderPathProvider;
/// use libimagentryutil::isa::Is;
///
/// trait WikiArticle {
/// fn is_wiki_article(&self) -> Result<bool>;
/// // ...
/// }
///
/// provide_kindflag_path!(IsWikiEntry, "wiki.is_entry");
///
/// impl WikiArticle for ::libimagstore::store::Entry {
/// fn is_wiki_article(&self) -> Result<bool> {
/// self.is::<IsWikiEntry>()
/// }
/// }
///
/// # fn main() { }
/// ```
///
/// # See also
///
/// * Documentation for `IsKindHeaderPathProvider`
/// * Helper macro `provide_kindflag_path!()`
///
pub trait Is {
fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool>;
fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()>;
}
impl Is for ::libimagstore::store::Entry {
fn is<T: IsKindHeaderPathProvider>(&self) -> Result<bool> {
let field = T::kindflag_header_location();
match self.get_header().read(field) {
Ok(Some(&Value::Boolean(b))) => Ok(b),
Ok(Some(_)) => Err(format!("Field {} has not a boolean type", field)).map_err(EUE::from),
Ok(None) => Err(format!("Field {} not available", field)).map_err(EUE::from),
Err(e) => Err(EUE::from(e))
}
}
fn set_isflag<T: IsKindHeaderPathProvider>(&mut self) -> Result<()> {
self.get_header_mut()
.insert(T::kindflag_header_location(), Value::Boolean(true))
.map_err(EUE::from)
.map(|_| ())
}
}
/// The IsKindHeaderPathProvider trait provides a function `typeflag_header_location()` which
/// returns a `toml-query` path.
///
/// This path points to a `bool` entry in the header of an entry which marks the entry to be an
/// entry of a certain kind.
///
/// For example, an "Wiki" entry might contain a `true` at `"wiki.is_entry"` in the header.
/// This trait provides `"wiki.is_entry"`.
pub trait IsKindHeaderPathProvider {
fn kindflag_header_location() -> &'static str;
}
/// Create (pub/non-pub) type for providing a `kindflag_header_location()` implementation.
#[macro_export]
macro_rules! provide_kindflag_path {
(pub $entry_header_path_provider_type:ident, $path:expr) => {
pub struct $entry_header_path_provider_type;
provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
};
($entry_header_path_provider_type:ident, $path:expr) => {
struct $entry_header_path_provider_type;
provide_kindflag_path!(impl for $entry_header_path_provider_type, $path);
};
(impl for $entry_header_path_provider_type:ident, $path:expr) => {
impl IsKindHeaderPathProvider for $entry_header_path_provider_type {
fn kindflag_header_location() -> &'static str {
$path
}
}
};
}

View File

@ -0,0 +1,47 @@
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#![recursion_limit="256"]
#![deny(
dead_code,
non_camel_case_types,
non_snake_case,
path_statements,
trivial_numeric_casts,
unstable_features,
unused_allocation,
unused_import_braces,
unused_imports,
unused_must_use,
unused_mut,
unused_qualifications,
while_true,
)]
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate error_chain;
extern crate libimagstore;
extern crate libimagerror;
pub mod error;
pub mod isa;