Skip to content

Commit

Permalink
feat(bib): structured and multilingual titles
Browse files Browse the repository at this point in the history
Add a Title enum to offer different title input options.

Signed-off-by: Bruce D'Arcus <bdarcus@gmail.com>
  • Loading branch information
bdarcus committed Jun 17, 2023
1 parent 7a1bf74 commit eec9f89
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 7 deletions.
73 changes: 72 additions & 1 deletion bibliography/src/reference.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
/*
SPDX-License-Identifier: MPL-2.0
SPDX-FileCopyrightText: © 2023 Bruce D'Arcus
*/

//! A reference is a bibliographic item, such as a book, article, or web page.
//! It is the basic unit of bibliographic data.
//!
//! The model includes the following core data types.
//! Each is designed to be as simple as possible, while also allowing more complex data structures.
//!
//! ## Title
//!
//! A title can be a single string, a structured title, or a multilingual title.
//!
//! ## Contributor
//!
//! A contributor can be a single string, a structured name, or a list of contributors.
//!
//! ## Date
//!
//! Dates can either be EDTF strings, for flexible dates and date-times, or literal strings.
//! Literal strings can be used for examples like "Han Dynasty".
use edtf::level_1::Edtf;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
Expand All @@ -9,7 +33,7 @@ use url::Url;
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonSchema, PartialEq)]
pub struct InputReference {
pub id: Option<String>,
pub title: Option<String>,
pub title: Option<Title>,
pub author: Option<Contributor>,
pub editor: Option<Contributor>,
pub translator: Option<Contributor>,
Expand All @@ -20,6 +44,8 @@ pub struct InputReference {
pub note: Option<String>,
}

pub type LangID = String;

#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonSchema, PartialEq)]
pub struct ContributorList(pub Vec<Contributor>);

Expand All @@ -30,6 +56,51 @@ pub struct StructuredName {
pub family_name: String,
}

/// A collection of formattable strings consisting of a title, a translated
/// title, and a shorthand.
#[derive(Debug, Deserialize, Serialize, Clone, JsonSchema, PartialEq)]
#[serde(untagged)]
#[non_exhaustive]
// REVIEW this needs a bit more work.
pub enum Title {
/// A title in a single language.
Single(String),
/// A structured title.
Structured(StructuredTitle),
/// A title in multiple languages.
Multi(Vec<(LangID, String)>),
/// A structured title in multiple languages.
MultiStructured(Vec<(LangID, StructuredTitle)>),
/// An abbreviated title.
// Borrowed from Hayagriva
Shorthand(String, String),
}

/// Where title parts are meaningful, use this struct; CSLN processors will not parse title strings.
#[derive(Debug, Deserialize, Serialize, Clone, JsonSchema, PartialEq)]
pub struct StructuredTitle {
pub full: String,
pub main: Option<String>,
pub sub: Option<Vec<String>>,
}

impl fmt::Display for Title {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Title::Single(s) => write!(f, "{}", s),
Title::Multi(_m) => todo!("multilingual title"),
Title::Structured(s) => write!(
f,
"{}: {}",
s.main.clone().unwrap(),
s.sub.clone().unwrap().join(", ")
),
Title::MultiStructured(_m) => todo!("multilingual structured title"),
Title::Shorthand(s, t) => write!(f, "{} ({})", s, t),
}
}
}

#[derive(Debug, Deserialize, Serialize, Clone, JsonSchema, PartialEq)]
pub struct EdtfString(pub String);

Expand Down
10 changes: 5 additions & 5 deletions processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,11 @@ impl RenderTitle for StyleTemplateTitle {
_hints: &ProcHints,
_options: &RenderOptions,
) -> String {
let title: &str = match &self.title {
Titles::Title => reference.title.as_ref().unwrap(),
let title: String = match &self.title {
Titles::Title => reference.title.as_ref().unwrap().to_string(),
Titles::ContainerTitle => todo!(),
};
title.to_string()
title
}
}

Expand Down Expand Up @@ -461,8 +461,8 @@ impl Processor {
}
SortGroupKey::Title => {
references.par_sort_by(|a, b| {
let a_title = a.title.as_ref().unwrap().to_lowercase();
let b_title = b.title.as_ref().unwrap().to_lowercase();
let a_title = a.title.as_ref().unwrap().to_string().to_lowercase();
let b_title = b.title.as_ref().unwrap().to_string().to_lowercase();
if sort.order == SortOrder::Ascending {
a_title.cmp(&b_title)
} else {
Expand Down
2 changes: 1 addition & 1 deletion processor/tests/processor_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod tests {
let refs = processor.get_references();
let sorted_refs = processor.sort_references(refs);
assert_eq!(sorted_refs.len(), 36);
assert_eq!(sorted_refs.last().unwrap().title.as_deref(), Some("Title 4"));
assert_eq!(sorted_refs.last().unwrap().title.as_ref().unwrap().to_string(), "Title 4");
}

#[test]
Expand Down

0 comments on commit eec9f89

Please sign in to comment.