Skip to content

Commit

Permalink
improve API of JsonLdOptions related to document loader factories
Browse files Browse the repository at this point in the history
In most case, users should not have to worry about explicitly building
a LoaderFactory; they can rely on one of the following:

  * with_document_loader_closure(closure)
  * with_default_document_loader::<LoaderType>()
  * with_document_loader(clonable_document_loader)
  • Loading branch information
pchampin committed Dec 19, 2023
1 parent 54a84e6 commit e2d3df6
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 22 deletions.
1 change: 1 addition & 0 deletions jsonld/src/loader/chain_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use json_syntax::Value;
use locspan::Location;

/// * [`ChainLoader`]: loads document from the first loader, otherwise falls back to the second one.
#[derive(Clone, Debug, Default)]
pub struct ChainLoader<L1, L2>(L1, L2);

impl<L1, L2> ChainLoader<L1, L2> {
Expand Down
94 changes: 93 additions & 1 deletion jsonld/src/options.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
//! Defines types for configuring JSON-LD processing.
use std::fmt::Display;
use std::sync::Arc;

use json_ld::expansion::Policy;
pub use json_ld::rdf::RdfDirection;
use json_ld::syntax::context::Value;
use json_ld::Loader;
use json_ld::NoLoader;
pub use json_ld::Options;
pub use json_ld::ProcessingMode;
use locspan::Location;
use locspan::Span;
use sophia_iri::Iri;

use crate::loader_factory::ClosureLoaderFactory;
use crate::loader_factory::DefaultLoaderFactory;
use crate::loader_factory::LoaderFactory;
use crate::vocabulary::ArcIri;
Expand Down Expand Up @@ -191,7 +196,12 @@ impl<LF> JsonLdOptions<LF> {
self
}

/// Change the [`document_loader`](Self::document_loader)
/// Change the [`document_loader_factory`](Self::document_loader_factory)
///
/// See also
/// [`JsonLdOptions::with_default_document_loader`],
/// [`JsonLdOptions::with_document_loader_closure`],
/// [`JsonLdOptions::with_document_loader`],
pub fn with_document_loader_factory<LF2: LoaderFactory>(
self,
document_loader_factory: LF2,
Expand All @@ -206,6 +216,87 @@ impl<LF> JsonLdOptions<LF> {
}
}

/// Change the [`document_loader_factory`](Self::document_loader_factory)
/// to one that encapsulate the given closure.
///
/// See also
/// [`JsonLdOptions::with_document_loader_factory`],
/// [`JsonLdOptions::with_default_document_loader`],
/// [`JsonLdOptions::with_document_loader`],
pub fn with_document_loader_closure<L, F>(
self,
f: F,
) -> JsonLdOptions<ClosureLoaderFactory<L, F>>
where
L: Loader<ArcIri, Location<Iri<Arc<str>>>, Output = json_syntax::Value<Location<ArcIri>>>
+ Send
+ Sync,
L::Error: Display + Send,
F: Fn() -> L,
{
JsonLdOptions {
inner: self.inner,
loader_factory: ClosureLoaderFactory::new(f),
use_native_types: self.use_native_types,
use_rdf_type: self.use_native_types,
spaces: self.spaces,
compact_context: self.compact_context,
}
}

/// Change the [`document_loader_factory`](Self::document_loader_factory)
/// to one that produces default values for L.
///
/// See also
/// [`JsonLdOptions::with_document_loader_factory`],
/// [`JsonLdOptions::with_document_loader_closure`],
/// [`JsonLdOptions::with_document_loader`],
pub fn with_default_document_loader<L>(self) -> JsonLdOptions<DefaultLoaderFactory<L>>
where
L: Loader<ArcIri, Location<Iri<Arc<str>>>, Output = json_syntax::Value<Location<ArcIri>>>
+ Default
+ Send
+ Sync,
L::Error: Display + Send,
{
JsonLdOptions {
inner: self.inner,
loader_factory: DefaultLoaderFactory::new(),
use_native_types: self.use_native_types,
use_rdf_type: self.use_native_types,
spaces: self.spaces,
compact_context: self.compact_context,
}
}

/// Change the [`document_loader_factory`](Self::document_loader_factory)
/// to one that produces clones of `document_loader`.
///
/// See also
/// [`JsonLdOptions::with_document_loader_factory`],
/// [`JsonLdOptions::with_document_loader_closure`],
/// [`JsonLdOptions::with_default_document_loader`],
pub fn with_document_loader<L>(
self,
document_loader: L,
) -> JsonLdOptions<ClosureLoaderFactory<L, impl Fn() -> L>>
where
L: Loader<ArcIri, Location<Iri<Arc<str>>>, Output = json_syntax::Value<Location<ArcIri>>>
+ Clone
+ Send
+ Sync,
L::Error: Display + Send,
{
JsonLdOptions {
inner: self.inner,
loader_factory: ClosureLoaderFactory::new_cloning(document_loader),
use_native_types: self.use_native_types,
use_rdf_type: self.use_native_types,
spaces: self.spaces,
compact_context: self.compact_context,
}
}

/// Change the [`expand_context`](Self::expand_context)
///
/// See also [`with_no_expand_context`](Self::with_no_expand_context)
Expand Down Expand Up @@ -299,6 +390,7 @@ impl<LF> JsonLdOptions<LF> {

impl<LF: LoaderFactory> JsonLdOptions<LF> {
/// The [`documentLoader`] is used to retrieve remote documents and contexts.
///
/// [`documentLoader`]: https://www.w3.org/TR/json-ld11-api/#dom-jsonldoptions-documentloader
pub fn document_loader(&self) -> LF::Loader<'_> {
self.loader_factory.yield_loader()
Expand Down
27 changes: 13 additions & 14 deletions jsonld/src/parser/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use sophia_term::ArcTerm;
use sophia_turtle::parser::nq;

use crate::{
loader_factory::{ClosureLoaderFactory, DefaultLoaderFactory},
loader::{FsLoader, NoLoader, StaticLoader},
JsonLdOptions, JsonLdParser,
};

Expand All @@ -12,7 +12,7 @@ use crate::{
// NB: the goal is NOT to check the loader itself -- we actually don't use it.
#[test]
fn check_no_loader() {
let options = JsonLdOptions::<DefaultLoaderFactory<crate::loader::NoLoader>>::default();
let options = JsonLdOptions::new().with_default_document_loader::<NoLoader>();
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand All @@ -29,7 +29,7 @@ fn check_no_loader() {
// NB: the goal is NOT to check the loader itself -- we actually don't use it.
#[test]
fn check_fs_loader() {
let options = JsonLdOptions::<DefaultLoaderFactory<crate::loader::FsLoader>>::default();
let options = JsonLdOptions::new().with_default_document_loader::<FsLoader>();
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand All @@ -46,8 +46,7 @@ fn check_fs_loader() {
// NB: the goal is NOT to check the loader itself -- we actually don't use it.
#[test]
fn check_static_loader() {
let options =
JsonLdOptions::<DefaultLoaderFactory<crate::loader::StaticLoader<_, _>>>::default();
let options = JsonLdOptions::new().with_default_document_loader::<StaticLoader<_, _>>();
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand All @@ -65,7 +64,9 @@ fn check_static_loader() {
#[cfg(feature = "http_client")]
#[test]
fn check_http_loader() {
let options = JsonLdOptions::<DefaultLoaderFactory<crate::loader::HttpLoader>>::default();
use crate::loader::HttpLoader;

let options = JsonLdOptions::new().with_default_document_loader::<HttpLoader>();
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand All @@ -83,7 +84,9 @@ fn check_http_loader() {
// NB: the goal is NOT to check the loader itself -- we actually don't use it.
#[test]
fn check_file_url_loader() {
let options = JsonLdOptions::<DefaultLoaderFactory<crate::loader::FileUrlLoader>>::default();
use crate::loader::FileUrlLoader;

let options = JsonLdOptions::new().with_default_document_loader::<FileUrlLoader>();
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand All @@ -100,13 +103,9 @@ fn check_file_url_loader() {
// NB: the goal is NOT to check the loader itself -- we actually don't use it.
#[test]
fn check_chain_loader() {
let options =
JsonLdOptions::new().with_document_loader_factory(ClosureLoaderFactory::new(|| {
crate::loader::ChainLoader::new(
crate::loader::StaticLoader::default(),
crate::loader::FsLoader::default(),
)
}));
let options = JsonLdOptions::new().with_document_loader_closure(|| {
crate::loader::ChainLoader::new(StaticLoader::default(), FsLoader::default())
});
let p = JsonLdParser::new_with_options(options);
let got: TestDataset = p
.parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#)
Expand Down
12 changes: 5 additions & 7 deletions sophia/examples/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use sophia::turtle::parser::{
use sophia::turtle::serializer::{nq::NqSerializer, nt::NtSerializer};
#[cfg(feature = "xml")]
use sophia::xml::parser::RdfXmlParser;
use sophia_jsonld::loader_factory::{ClosureLoaderFactory, DefaultLoaderFactory, LoaderFactory};

fn main() {
let format = std::env::args()
Expand Down Expand Up @@ -65,16 +64,15 @@ fn main() {
"json-ld" | "jsonld" => {
let options = JsonLdOptions::new()
.with_base(base.clone().unwrap().map_unchecked(std::sync::Arc::from));
let loader_factory =
DefaultLoaderFactory::<sophia::jsonld::loader::FileUrlLoader>::default();
let loader_factory = sophia::jsonld::loader::FileUrlLoader::default;
#[cfg(feature = "http_client")]
let loader_factory = ClosureLoaderFactory::new(|| {
let loader_factory = || {
sophia::jsonld::loader::ChainLoader::new(
loader_factory.yield_loader(),
(loader_factory)(),
sophia::jsonld::loader::HttpLoader::default(),
)
});
let options = options.with_document_loader_factory(loader_factory);
};
let options = options.with_document_loader_closure(loader_factory);
dump_quads(input, JsonLdParser::new_with_options(options))
}
#[cfg(feature = "xml")]
Expand Down

0 comments on commit e2d3df6

Please sign in to comment.