Skip to content

Commit

Permalink
Separate sophia_term as an autonomous crate
Browse files Browse the repository at this point in the history
This is a first step towards #26.

This change required a few minor adjustments,
mostly to remove cyclic dependencies,
between sophia_term and some other parts of sophia.

Apart from those, the API is unchanged,
and the sophia crate re-exports all public entities from sophia_term,
so that projects using sophia should not be impacted by this refactoring.
  • Loading branch information
pchampin committed Mar 19, 2020
1 parent 77976a5 commit 10f14c3
Show file tree
Hide file tree
Showing 22 changed files with 174 additions and 112 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@

members = [
"sophia",
"term",
]

[patch.crates-io]
sophia_term = { path = "term" }
16 changes: 8 additions & 8 deletions sophia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ all-features = true

[features]
default = []
xml = ["quick-xml", "percent-encoding"]
xml = ["lazy_static", "percent-encoding", "quick-xml", "regex", "url"]

[dependencies]
language-tag = "0.9.0"
lazy_static = "1.4.0"
regex = "1.3.4"
sophia_term = "0.4"
resiter = "0.4.0"
rio_api = { version = "0.4.0", features = ["generalized"] }
rio_api = { version = "0.4.1", features = ["generalized"] }
rio_turtle = { version = "0.4.0", features = ["generalized"] }
url = "2.1.1"
weak-table = "0.2.3"
thiserror = "1.0.11"

quick-xml = { version = "0.17.2", optional = true }
lazy_static = { version = "1.4.0", optional = true }
percent-encoding = { version = "2.1.0", optional = true }
quick-xml = { version = "0.17.2", optional = true }
regex = { version = "1.3.5", optional = true }
url = { version = "2.1.1", optional = true }

[dev-dependencies]
test-case = "1.0.0"
lazy_static = "1.4.0"
34 changes: 34 additions & 0 deletions sophia/src/graph/_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,25 @@ pub trait Graph {
/// An iterator visiting all triples matching the given subject, predicate and object.
///
/// See also [`triples`](#tymethod.triples).
///
/// # Usage
///
/// ```
/// # use sophia::graph::{*, inmem::LightGraph};
/// # use sophia::triple::Triple;
/// use sophia_term::ns::{Namespace, rdf};
/// use sophia_term::matcher::{ANY, TermMatcher};
///
/// # let mut graph = LightGraph::new();
/// let s = Namespace::new("http://schema.org/").unwrap();
/// let city = s.get("City").unwrap();
/// let country = s.get("Country").unwrap();
///
/// for t in graph.triples_matching(&ANY, &rdf::type_, &[city, country]) {
/// let t = t.unwrap();
/// println!("{} was found", t.s());
/// }
/// ```
fn triples_matching<'s, S, P, O>(
&'s self,
ms: &'s S,
Expand Down Expand Up @@ -378,6 +397,21 @@ pub trait MutableGraph: Graph {
/// a return value of `true` does *not* mean that the triple was not already in the graph,
/// only that the graph now has one more occurrence of it.
///
/// # Usage
/// ```
/// # use sophia_term::BoxTerm;
/// # use sophia_term::ns::{Namespace, rdf, rdfs, xsd};
/// # use sophia::graph::MutableGraph;
/// # use std::collections::HashSet;
///
/// fn populate<G: MutableGraph>(graph: &mut G) {
/// let schema = Namespace::new("http://schema.org/").unwrap();
/// let s_name = schema.get("name").unwrap();
///
/// graph.insert(&s_name, &rdf::type_, &rdf::Property);
/// graph.insert(&s_name, &rdfs::range, &xsd::string);
/// }
/// ```
fn insert<T, U, V>(&mut self, s: &Term<T>, p: &Term<U>, o: &Term<V>) -> MGResult<Self, bool>
where
T: TermData,
Expand Down
22 changes: 9 additions & 13 deletions sophia/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,19 @@
//! println!("The resulting graph\n{}", example2);
//! ```
extern crate language_tag;
#[cfg(feature = "xml")]
extern crate quick_xml;
extern crate resiter;
#[cfg(feature = "rio")]
extern crate rio_api;
#[cfg(feature = "rio")]
extern crate rio_turtle;
extern crate url;
extern crate weak_table;

pub mod dataset;
pub mod graph;
pub mod ns;
pub mod parser;
pub mod quad;
pub mod query;
pub mod serializer;
pub mod term;
pub mod triple;

/// See [`sophia_term::ns`](https://docs.rs/sophia_term/latest/sophia_term/ns/index.html)
pub mod ns {
pub use sophia_term::ns::*;
}
/// See [`sophia_term`](https://docs.rs/sophia_term/latest/sophia_term/)
pub mod term {
pub use sophia_term::*;
}
13 changes: 9 additions & 4 deletions sophia/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use std::collections::HashMap;
use std::iter::once;

use resiter::map::*;
use sophia_term::matcher::AnyOrExactly;
use sophia_term::*;

use crate::graph::*;
use crate::term::*;
use crate::triple::*;

/// A map associating variable names to [`term`](../term/enum.Term.html)s.
Expand Down Expand Up @@ -151,12 +152,16 @@ where
g.triples_matching(s, p, o)
}

type Binding = crate::term::matcher::AnyOrExactly<RcTerm>;
type Binding = AnyOrExactly<RcTerm>;

impl Binding {
trait BindingExt {
fn is_free(&self) -> bool;
}

impl BindingExt for Binding {
fn is_free(&self) -> bool {
match self {
Binding::Any => true,
AnyOrExactly::Any => true,
_ => false,
}
}
Expand Down
24 changes: 24 additions & 0 deletions term/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "sophia_term"
version = "0.4.0"
authors = ["Pierre-Antoine Champin <pchampin@liris.cnrs.fr>"]
edition = "2018"
description = "A Rust toolkit for RDF and Linked Data - Types for RDF terms"
repository = "https://github.com/pchampin/sophia_rs"
documentation = "https://docs.rs/sophia_term"
readme = "../README.md"
license = "CECILL-B"
keywords = ["rdf", "linked-data", "semantic-web"]


# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
language-tag = "0.9.0"
lazy_static = "1.4.0"
regex = "1.3.5"
weak-table = "0.2.3"
thiserror = "1.0.11"

[dev-dependencies]
test-case = "1.0.0"
6 changes: 3 additions & 3 deletions sophia/src/term/_display.rs → term/src/_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use std::fmt;

use crate::term::*;
use crate::*;

impl<T> fmt::Display for Term<T>
where
Expand Down Expand Up @@ -41,9 +41,9 @@ where

#[cfg(test)]
pub(crate) mod test {
use crate::literal::AsLiteral;
use crate::ns::*;
use crate::term::literal::AsLiteral;
use crate::term::*;
use crate::*;
use lazy_static::lazy_static;

lazy_static! {
Expand Down
10 changes: 10 additions & 0 deletions sophia/src/term/_error.rs → term/src/_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ pub enum TermError {
/// What is wrong with `tag`.
err: String,
},
/// The lexical value of a literal can not be interpreted accortding to its datatype
#[error("The given lexical value '{lex}' is invalid for datatype {dt}")]
InvalidLexicalValue {
/// The faulty lexical value.
lex: String,
/// The literal datatype IRI.
dt: String,
/// The underlying error.
source: Box<dyn std::error::Error>,
},
/// Names of variables must apply to SPARQL's [production rules](https://www.w3.org/TR/sparql11-query/#rVARNAME).
#[error("The name '{0}' is not valid for a variable according to the SPARQL specification")]
InvalidVariableName(String),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// this module is transparently re-exported by its sibling `matcher`

use crate::term::matcher::{AnyOrExactly, AnyTerm};
use crate::term::*;
use crate::matcher::{AnyOrExactly, AnyTerm};
use crate::*;

/// Generic trait for matching graph names, *i.e.* optional [term]s.
///
Expand Down Expand Up @@ -217,7 +217,7 @@ mod test {

use super::*;

use crate::term::matcher::{AnyOrExactly, ANY};
use crate::matcher::{AnyOrExactly, ANY};
#[test]
fn test_option_ref_term_as_matcher() {
let m = Some(BoxTerm::new_iri("http://champin.net/#pa").unwrap());
Expand Down
12 changes: 6 additions & 6 deletions sophia/src/term/blank_node.rs → term/src/blank_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ lazy_static! {
/// # Rule
///
/// `BLANK_NODE_LABEL ::= (PN_CHARS_U | [0-9]) ((PN_CHARS | '.')* PN_CHARS)?`
pub static ref BLANK_NODE_LABEL: Regex = Regex::new(r"(?x)
static ref BLANK_NODE_LABEL: Regex = Regex::new(r"(?x)
^
[A-Za-z\u{c0}-\u{d6}\u{d8}-\u{f6}\u{f8}-\u{2ff}\u{370}-\u{37D}\u{37F}-\u{1FFF}\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}_0-9]
(
Expand All @@ -42,15 +42,15 @@ lazy_static! {

/// Internal representation of a blank node identifier.
///
/// May be encountered when pattern-matching on [`Term`](enum.Term.html)s
/// of the [`BNode`](enum.Term.html#variant.BNode) variant.
/// May be encountered when pattern-matching on [`Term`](../enum.Term.html)s
/// of the [`BNode`](../enum.Term.html#variant.BNode) variant.
/// For that purpose, note that `BlankNode`
/// - derefs implicitly to its internal type `T`;
/// - can be directly compared to a `&str` with the `==` operator.
///
/// Example :
/// ```
/// use sophia::term::*;
/// use sophia_term::*;
///
/// fn is_foobar(t: BoxTerm) -> bool {
/// match t {
Expand All @@ -74,7 +74,7 @@ where
/// Return a new blank node with the given identifier.
///
/// May fail if `id` is not a valid identifier according to
/// [`BLANK_NODE_LABEL`](struct.BLANK_NODE_LABEL.html). This means that it
/// [`BLANK_NODE_LABEL`](https://www.w3.org/TR/n-triples/#grammar-production-BLANK_NODE_LABEL). This means that it
/// must not include the typical leading `_:`.
pub fn new<U>(id: U) -> Result<Self>
where
Expand Down Expand Up @@ -302,5 +302,5 @@ mod test {
}
}

// further tests are executed in `crate::term::test`
// further tests are executed in `crate::test`
}
File renamed without changes.
8 changes: 5 additions & 3 deletions sophia/src/term/index_map.rs → term/src/index_map.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! A trait for bidirectional mappings between terms and *indexes* of a smaller type.
use crate::term::factory::{FTerm, TermFactory};
use crate::term::RefTerm;
use crate::factory::{FTerm, TermFactory};
use crate::RefTerm;

/// A bidirectionnal mapping between [`Term`]s and *indexes* of a smaller type.
///
Expand Down Expand Up @@ -69,8 +69,10 @@ pub trait TermIndexMap: Default {
}
}

#[cfg(test)]
#[allow(clippy::cognitive_complexity)]
/// Takes an empty TermIndexMap, and checks that it behaves as expected.
///
/// This function is provided to test TermIndexMap implementations.
pub fn assert_term_index_map_works<T: TermIndexMap>(ti: &mut T) {
let t = RefTerm::new_iri("http://example.org/").unwrap();
assert!(ti.get_index(&t).is_none());
Expand Down
10 changes: 5 additions & 5 deletions sophia/src/term/iri.rs → term/src/iri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@ pub const GEN_DELIMS: &[char] = &[':', '/', '?', '#', '[', ']', '@'];
/// IRIs are represented in a given format.
///
/// They are applied by copying terms with
/// [`Term::normalized`](enum.Term.html#method.normalized_with).
/// [`Term::normalized`](../enum.Term.html#method.normalized_with).
#[derive(Clone, Copy)]
pub enum Normalization {
/// IRIs are represented as a single string (`ns`) with an empty `suffix`.
NoSuffix,
/// IRIs are represented with a prefix `ns` extending to the last
/// [`gen-delim`](./const.GEN_DELIMS.html) and a `suffix` containing the
/// [`gen-delim`](./constant.GEN_DELIMS.html) and a `suffix` containing the
/// remaining characters.
LastGenDelim,
}

/// Representation of an IRI.
///
/// May be encountered when pattern-matching on [`Term`](enum.Term.html)s
/// of the [`Iri`](enum.Term.html#variant.Iri) variant.
/// May be encountered when pattern-matching on [`Term`](../enum.Term.html)s
/// of the [`Iri`](../enum.Term.html#variant.Iri) variant.
/// For that purpose, note that `Iri`
/// - can be directly compared to a `&str` with the `==` operator;
/// - can be directly compared to a [`Term`](enum.Term.html) with the `==` operator;
/// - can be directly compared to a [`Term`](../enum.Term.html) with the `==` operator;
/// - provides some identical methods to what `&str` provides (see below);
/// - can otherwise be converted to a `String` with `to_string`;
///
Expand Down
6 changes: 3 additions & 3 deletions sophia/src/term/iri/_join.rs → term/src/iri/_join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
//!
use super::{Iri, IRELATIVE_REF_REGEX, IRI_REGEX};
use crate::quad::{Quad, TupleQuad};
use crate::term::{Literal, Result, Term, TermData, TermError};
use crate::triple::Triple;
use crate::{Literal, Result, Term, TermData, TermError};
use std::fmt;

/// Resolve some kind of IRI with `self` as the base.
Expand Down Expand Up @@ -234,6 +232,7 @@ where
}
}

/*
impl<'a, T, TD> Resolve<T, [Term<TD>; 3]> for IriParsed<'a>
where
T: Triple,
Expand Down Expand Up @@ -279,6 +278,7 @@ where
))
}
}
*/

impl fmt::Display for IriParsed<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down
4 changes: 2 additions & 2 deletions sophia/src/term/iri/_regex.rs → term/src/iri/_regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn is_relative_iri_ref(txt: &str) -> bool {

lazy_static! {
/// Match an absolute IRI reference.
pub static ref IRI_REGEX: Regex = Regex::new(r"(?x)^
pub(crate) static ref IRI_REGEX: Regex = Regex::new(r"(?x)^
#scheme
( # CAPTURE scheme
[A-Za-z] [-A-Za-z0-9+.]*
Expand Down Expand Up @@ -155,7 +155,7 @@ lazy_static! {
$").unwrap();

/// Match a relative IRI.
pub static ref IRELATIVE_REF_REGEX: Regex = Regex::new(r"(?x)^
pub(crate) static ref IRELATIVE_REF_REGEX: Regex = Regex::new(r"(?x)^
#irelative_part
(?: #iauthority + ipath_abempty
//
Expand Down
Loading

0 comments on commit 10f14c3

Please sign in to comment.