From e2d3df6cd0540c9c4e601ead07688469a9b8ee3a Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Tue, 19 Dec 2023 20:03:18 +0100 Subject: [PATCH] improve API of JsonLdOptions related to document loader factories 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::() * with_document_loader(clonable_document_loader) --- jsonld/src/loader/chain_loader.rs | 1 + jsonld/src/options.rs | 94 ++++++++++++++++++++++++++++++- jsonld/src/parser/test.rs | 27 +++++---- sophia/examples/parse.rs | 12 ++-- 4 files changed, 112 insertions(+), 22 deletions(-) diff --git a/jsonld/src/loader/chain_loader.rs b/jsonld/src/loader/chain_loader.rs index d7d321f4..dad2ac64 100644 --- a/jsonld/src/loader/chain_loader.rs +++ b/jsonld/src/loader/chain_loader.rs @@ -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); impl ChainLoader { diff --git a/jsonld/src/options.rs b/jsonld/src/options.rs index 49dd511a..018ff593 100644 --- a/jsonld/src/options.rs +++ b/jsonld/src/options.rs @@ -1,8 +1,12 @@ //! 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; @@ -10,6 +14,7 @@ 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; @@ -191,7 +196,12 @@ impl JsonLdOptions { 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( self, document_loader_factory: LF2, @@ -206,6 +216,87 @@ impl JsonLdOptions { } } + /// 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( + self, + f: F, + ) -> JsonLdOptions> + where + L: Loader>>, Output = json_syntax::Value>> + + 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(self) -> JsonLdOptions> + where + L: Loader>>, Output = json_syntax::Value>> + + 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( + self, + document_loader: L, + ) -> JsonLdOptions L>> + where + L: Loader>>, Output = json_syntax::Value>> + + 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) @@ -299,6 +390,7 @@ impl JsonLdOptions { impl JsonLdOptions { /// 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() diff --git a/jsonld/src/parser/test.rs b/jsonld/src/parser/test.rs index d2cb5fa6..85eb5646 100644 --- a/jsonld/src/parser/test.rs +++ b/jsonld/src/parser/test.rs @@ -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, }; @@ -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::>::default(); + let options = JsonLdOptions::new().with_default_document_loader::(); let p = JsonLdParser::new_with_options(options); let got: TestDataset = p .parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#) @@ -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::>::default(); + let options = JsonLdOptions::new().with_default_document_loader::(); let p = JsonLdParser::new_with_options(options); let got: TestDataset = p .parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#) @@ -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::>>::default(); + let options = JsonLdOptions::new().with_default_document_loader::>(); let p = JsonLdParser::new_with_options(options); let got: TestDataset = p .parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#) @@ -65,7 +64,9 @@ fn check_static_loader() { #[cfg(feature = "http_client")] #[test] fn check_http_loader() { - let options = JsonLdOptions::>::default(); + use crate::loader::HttpLoader; + + let options = JsonLdOptions::new().with_default_document_loader::(); let p = JsonLdParser::new_with_options(options); let got: TestDataset = p .parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#) @@ -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::>::default(); + use crate::loader::FileUrlLoader; + + let options = JsonLdOptions::new().with_default_document_loader::(); let p = JsonLdParser::new_with_options(options); let got: TestDataset = p .parse_str(r#"{"@id": "tag:foo", "tag:bar": "BAZ"}"#) @@ -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"}"#) diff --git a/sophia/examples/parse.rs b/sophia/examples/parse.rs index ccfd59cd..6251bdfb 100644 --- a/sophia/examples/parse.rs +++ b/sophia/examples/parse.rs @@ -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() @@ -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::::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")]