mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-23 03:07:13 +00:00
vocabmerge: a subject scheme, supplied rather than compiled in
This commit is contained in:
@@ -251,7 +251,7 @@ One heading per line — an `id`, a `name`, and the `count` of works under it:
|
|||||||
| `--rules <FILE>` | Vocabulary specific to this collection |
|
| `--rules <FILE>` | Vocabulary specific to this collection |
|
||||||
| `--man` | Write this page as a manual page, in roff |
|
| `--man` | Write this page as a manual page, in roff |
|
||||||
|
|
||||||
The rules file is JSON, and today holds one thing:
|
The rules file is JSON and holds two things.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{"device_prefixes": ["alexskobo"]}
|
{"device_prefixes": ["alexskobo"]}
|
||||||
@@ -261,6 +261,57 @@ An e-reader stamps its own name onto every book it touches. The generic device
|
|||||||
names are built in; one named after its owner is a fact about a single
|
names are built in; one named after its owner is a fact about a single
|
||||||
collection, so it is supplied rather than compiled in.
|
collection, so it is supplied rather than compiled in.
|
||||||
|
|
||||||
|
### A subject scheme
|
||||||
|
|
||||||
|
The other thing is a closed list of subjects to file under. A catalogue that
|
||||||
|
lets anything be a subject ends up with forty thousand of them and no way to
|
||||||
|
browse; a scheme is the other approach.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scheme": {
|
||||||
|
"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Fiction"],
|
||||||
|
"aliases": {"Philosophie": "Philosophy", "Church History": "History"},
|
||||||
|
"drop": ["General", "Humanities", "Non-Fiction"],
|
||||||
|
"parents": {"Phenomenology": "Philosophy"},
|
||||||
|
"blocks_fiction": ["Biography"],
|
||||||
|
"fiction_genres": ["Fiction"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which subjects a collection uses is the most collection-specific thing there
|
||||||
|
is — a theology library and a science library agree on none of them — so it
|
||||||
|
arrives in the file rather than compiled in.
|
||||||
|
|
||||||
|
With one, every heading nothing else has already claimed gets an answer: a
|
||||||
|
spelling the scheme knows is a merge onto the spelling it uses, and a heading
|
||||||
|
the scheme does not have at all is a delete.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ vocabmerge --kind tag --rules scheme.json tags.ndjson
|
||||||
|
{"kind":"tag","action":"merge","keep":"Philosophy","drop":"Philosophie",…,"method":"scheme_alias","confidence":0.95,"evidence":"the scheme files \"Philosophie\" under \"Philosophy\""}
|
||||||
|
{"kind":"tag","action":"delete","keep":null,"drop":"General",…,"method":"scheme_absent","confidence":0.8,"evidence":"\"General\" is not in the scheme, on 88 books"}
|
||||||
|
{"kind":"tag","action":"delete","keep":null,"drop":"Underwater Basketry",…,"method":"scheme_absent","confidence":0.8,"evidence":"\"Underwater Basketry\" is not in the scheme, on 1 books"}
|
||||||
|
{"kind":"tag","action":"merge","keep":"History","drop":"Church History",…,"method":"scheme_alias","confidence":0.95,"evidence":"the scheme files \"Church History\" under \"History\""}
|
||||||
|
```
|
||||||
|
|
||||||
|
The deletes are the lower confidence of the two on purpose: an alias is a
|
||||||
|
statement the scheme makes, while an absence only says the scheme does not
|
||||||
|
list it — which may equally mean the scheme is short a heading.
|
||||||
|
|
||||||
|
Four rules the scheme applies, for anything using it as a library:
|
||||||
|
|
||||||
|
- **Parents come along.** Phenomenology files under Philosophy and
|
||||||
|
Phenomenology, so a shelf browsed by the parent still finds the child.
|
||||||
|
- **Order is scheme order**, not the order the headings arrived in.
|
||||||
|
- **A study is not a novel.** A work already under a heading in
|
||||||
|
`blocks_fiction` — or whose title says "Companion to", "A Life of", "Diary",
|
||||||
|
"Very Short Introduction" — loses the `fiction_genres`. A historical novel
|
||||||
|
may still be both.
|
||||||
|
- **A book tagged only with headings the scheme rejects has no subject yet**,
|
||||||
|
which is what a catalogue built from filenames looks like.
|
||||||
|
|
||||||
### Exit codes
|
### Exit codes
|
||||||
|
|
||||||
| Code | Meaning |
|
| Code | Meaning |
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub mod fix;
|
|||||||
pub mod isbn;
|
pub mod isbn;
|
||||||
pub mod matching;
|
pub mod matching;
|
||||||
pub mod reasons;
|
pub mod reasons;
|
||||||
|
pub mod scheme;
|
||||||
pub mod slug;
|
pub mod slug;
|
||||||
pub mod vocab;
|
pub mod vocab;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,304 @@
|
|||||||
|
//! A closed subject scheme, and what it says about a heading.
|
||||||
|
//!
|
||||||
|
//! A catalogue that lets anything be a subject ends up with forty thousand of
|
||||||
|
//! them and no way to browse. A scheme is the other approach: a fixed list of
|
||||||
|
//! headings, everything else mapped onto one or dropped.
|
||||||
|
//!
|
||||||
|
//! The scheme itself is supplied rather than compiled in. Which subjects a
|
||||||
|
//! collection uses, and what its parents are, is the most collection-specific
|
||||||
|
//! thing there is — a theology library and a science library agree on nothing
|
||||||
|
//! here — so it arrives as a file and this only knows what to do with one.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use fancy_regex::Regex;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Titles that say the book is *about* somebody rather than by them, or is a
|
||||||
|
/// study rather than a story.
|
||||||
|
///
|
||||||
|
/// General reference rather than collection-specific: a Companion is a
|
||||||
|
/// Companion on any shelf.
|
||||||
|
static STUDY_TITLE: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
Regex::new(r"(?i)\b(companion to|guidebook to|very short introduction|letters of|collected letters|memoirs?\b|autobiograph|\bdiary\b|\bessays\b|\blectures\b|\bspeeches\b|a life of|biography of)\b")
|
||||||
|
.expect("a valid pattern")
|
||||||
|
});
|
||||||
|
|
||||||
|
/// A subject scheme: what the headings are, and how they relate.
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct Scheme {
|
||||||
|
/// Every heading the scheme allows, in the order they should be listed.
|
||||||
|
#[serde(default)]
|
||||||
|
pub subjects: Vec<String>,
|
||||||
|
/// Spellings that mean one of the subjects: alias to subject.
|
||||||
|
#[serde(default)]
|
||||||
|
pub aliases: HashMap<String, String>,
|
||||||
|
/// Headings too broad or too incidental to keep, whatever they say.
|
||||||
|
#[serde(default)]
|
||||||
|
pub drop: Vec<String>,
|
||||||
|
/// Which subject each subject sits under, child to parent.
|
||||||
|
#[serde(default)]
|
||||||
|
pub parents: HashMap<String, String>,
|
||||||
|
/// Subjects that mean the work is a study, so it cannot also be fiction.
|
||||||
|
#[serde(default)]
|
||||||
|
pub blocks_fiction: Vec<String>,
|
||||||
|
/// The genres a study blocks.
|
||||||
|
#[serde(default)]
|
||||||
|
pub fiction_genres: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scheme {
|
||||||
|
/// Whether the scheme says anything at all.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.subjects.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The subject a heading means, or `None` if it is not one.
|
||||||
|
///
|
||||||
|
/// Exact first, then an alias. A heading on the drop list is not a
|
||||||
|
/// subject however it is spelled, and the brackets a catalogue wraps its
|
||||||
|
/// own annotations in are stripped before the comparison.
|
||||||
|
pub fn canonical(&self, name: &str) -> Option<&str> {
|
||||||
|
let name = name.trim();
|
||||||
|
if name.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let lower = name.to_lowercase();
|
||||||
|
let bare = lower.trim_matches(|c: char| "*[]".contains(c));
|
||||||
|
|
||||||
|
if self.drop.iter().any(|drop| {
|
||||||
|
let drop = drop.to_lowercase();
|
||||||
|
let drop = drop.trim_matches(|c: char| "*[]".contains(c));
|
||||||
|
drop == lower || drop == bare
|
||||||
|
}) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(found) = self.subjects.iter().find(|s| s.to_lowercase() == lower) {
|
||||||
|
return Some(found);
|
||||||
|
}
|
||||||
|
self.aliases
|
||||||
|
.iter()
|
||||||
|
.find(|(alias, _)| alias.to_lowercase() == lower)
|
||||||
|
.map(|(_, subject)| subject.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every chosen subject, with the parent of each carried alongside it.
|
||||||
|
///
|
||||||
|
/// Phenomenology becomes Philosophy and Phenomenology, so a shelf browsed
|
||||||
|
/// by the parent still finds the child. Returned in scheme order, which
|
||||||
|
/// is the order a reader expects to see them listed.
|
||||||
|
pub fn with_parents(&self, subjects: &[String]) -> Vec<String> {
|
||||||
|
let mut chosen: Vec<&str> = Vec::new();
|
||||||
|
for subject in subjects {
|
||||||
|
if !self.subjects.iter().any(|s| s == subject) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chosen.push(subject);
|
||||||
|
if let Some(parent) = self.parents.get(subject) {
|
||||||
|
chosen.push(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.in_order(&chosen)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drop the fiction genres where the work is plainly a study.
|
||||||
|
///
|
||||||
|
/// A historical novel may be fiction and history at once. A life of
|
||||||
|
/// somebody, a Companion, or a writer's diary may not be a novel.
|
||||||
|
pub fn without_impossible_fiction(
|
||||||
|
&self,
|
||||||
|
subjects: &[String],
|
||||||
|
title: Option<&str>,
|
||||||
|
) -> Vec<String> {
|
||||||
|
let study = title.is_some_and(|title| STUDY_TITLE.is_match(title).unwrap_or(false));
|
||||||
|
let blocked = subjects
|
||||||
|
.iter()
|
||||||
|
.any(|s| self.blocks_fiction.iter().any(|block| block == s));
|
||||||
|
|
||||||
|
let kept: Vec<&str> = subjects
|
||||||
|
.iter()
|
||||||
|
.map(String::as_str)
|
||||||
|
.filter(|subject| {
|
||||||
|
!(study || blocked) || !self.fiction_genres.iter().any(|genre| genre == subject)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.in_order(&kept)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The subjects a book should carry: the chosen ones, their parents, and
|
||||||
|
/// nothing the title rules out.
|
||||||
|
pub fn compose(&self, subjects: &[String], title: Option<&str>) -> Vec<String> {
|
||||||
|
self.without_impossible_fiction(&self.with_parents(subjects), title)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether a book has no real subject yet.
|
||||||
|
///
|
||||||
|
/// Untagged, or tagged only with headings the scheme does not recognise —
|
||||||
|
/// which is what a catalogue built from filenames looks like.
|
||||||
|
pub fn needs_subject(&self, existing: &[String]) -> bool {
|
||||||
|
!existing.iter().any(|tag| self.canonical(tag).is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The given headings, deduplicated and in scheme order.
|
||||||
|
fn in_order(&self, chosen: &[&str]) -> Vec<String> {
|
||||||
|
self.subjects
|
||||||
|
.iter()
|
||||||
|
.filter(|subject| chosen.contains(&subject.as_str()))
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn scheme() -> Scheme {
|
||||||
|
Scheme {
|
||||||
|
subjects: [
|
||||||
|
"Philosophy",
|
||||||
|
"Phenomenology",
|
||||||
|
"History",
|
||||||
|
"Biography",
|
||||||
|
"Fiction",
|
||||||
|
"Science Fiction",
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect(),
|
||||||
|
aliases: [("Philosophie", "Philosophy"), ("SF", "Science Fiction")]
|
||||||
|
.iter()
|
||||||
|
.map(|(a, b)| (a.to_string(), b.to_string()))
|
||||||
|
.collect(),
|
||||||
|
drop: ["General", "Humanities", "Non-Fiction"]
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect(),
|
||||||
|
parents: [("Phenomenology", "Philosophy")]
|
||||||
|
.iter()
|
||||||
|
.map(|(a, b)| (a.to_string(), b.to_string()))
|
||||||
|
.collect(),
|
||||||
|
blocks_fiction: vec!["Biography".into()],
|
||||||
|
fiction_genres: vec!["Fiction".into(), "Science Fiction".into()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subjects(names: &[&str]) -> Vec<String> {
|
||||||
|
names.iter().map(|s| s.to_string()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_heading_in_the_scheme_is_itself() {
|
||||||
|
assert_eq!(scheme().canonical("Philosophy"), Some("Philosophy"));
|
||||||
|
assert_eq!(scheme().canonical("philosophy"), Some("Philosophy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn an_alias_is_the_subject_it_means() {
|
||||||
|
assert_eq!(scheme().canonical("Philosophie"), Some("Philosophy"));
|
||||||
|
assert_eq!(scheme().canonical("sf"), Some("Science Fiction"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_heading_on_the_drop_list_is_not_a_subject() {
|
||||||
|
assert_eq!(scheme().canonical("General"), None);
|
||||||
|
// Including inside the brackets a catalogue wraps its own notes in.
|
||||||
|
assert_eq!(scheme().canonical("[General]"), None);
|
||||||
|
assert_eq!(scheme().canonical("*Humanities*"), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_heading_the_scheme_never_heard_of_is_not_a_subject() {
|
||||||
|
assert_eq!(scheme().canonical("Underwater Basketry"), None);
|
||||||
|
assert_eq!(scheme().canonical(""), None);
|
||||||
|
assert_eq!(scheme().canonical(" "), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_child_carries_its_parent() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().with_parents(&subjects(&["Phenomenology"])),
|
||||||
|
["Philosophy", "Phenomenology"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subjects_come_back_in_scheme_order_however_they_went_in() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().with_parents(&subjects(&["History", "Philosophy"])),
|
||||||
|
["Philosophy", "History"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_heading_outside_the_scheme_is_dropped_rather_than_carried() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().with_parents(&subjects(&["Basketry"])),
|
||||||
|
Vec::<String>::new()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_biography_is_not_also_a_novel() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().without_impossible_fiction(&subjects(&["Biography", "Fiction"]), None),
|
||||||
|
["Biography"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_title_that_says_study_rules_out_fiction_on_its_own() {
|
||||||
|
for title in [
|
||||||
|
"The Cambridge Companion to Nietzsche",
|
||||||
|
"Logic: A Very Short Introduction",
|
||||||
|
"A Life of Wrangel",
|
||||||
|
"The Diary of a Writer",
|
||||||
|
] {
|
||||||
|
assert_eq!(
|
||||||
|
scheme()
|
||||||
|
.without_impossible_fiction(&subjects(&["Fiction", "History"]), Some(title)),
|
||||||
|
["History"],
|
||||||
|
"{title}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_historical_novel_may_still_be_both() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().without_impossible_fiction(
|
||||||
|
&subjects(&["Fiction", "History"]),
|
||||||
|
Some("War and Peace")
|
||||||
|
),
|
||||||
|
["History", "Fiction"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn composing_does_the_parents_and_the_fiction_rule_at_once() {
|
||||||
|
assert_eq!(
|
||||||
|
scheme().compose(
|
||||||
|
&subjects(&["Phenomenology", "Fiction"]),
|
||||||
|
Some("A Life of Husserl")
|
||||||
|
),
|
||||||
|
["Philosophy", "Phenomenology"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_book_tagged_only_with_rubbish_still_needs_a_subject() {
|
||||||
|
assert!(scheme().needs_subject(&[]));
|
||||||
|
assert!(scheme().needs_subject(&subjects(&["General", "ebook"])));
|
||||||
|
assert!(!scheme().needs_subject(&subjects(&["General", "Philosophy"])));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn an_empty_scheme_says_nothing_about_anything() {
|
||||||
|
let empty = Scheme::default();
|
||||||
|
assert!(empty.is_empty());
|
||||||
|
assert_eq!(empty.canonical("Philosophy"), None);
|
||||||
|
assert!(empty.needs_subject(&subjects(&["Philosophy"])));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -163,6 +163,13 @@ pub struct Rules {
|
|||||||
/// A device named after its owner belongs here and not in the program.
|
/// A device named after its owner belongs here and not in the program.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub device_prefixes: Vec<String>,
|
pub device_prefixes: Vec<String>,
|
||||||
|
/// The closed subject scheme this collection files under, if it has one.
|
||||||
|
///
|
||||||
|
/// Which subjects a collection uses is the most collection-specific thing
|
||||||
|
/// there is — a theology library and a science library agree on none of
|
||||||
|
/// them — so it arrives here rather than being compiled in.
|
||||||
|
#[serde(default)]
|
||||||
|
pub scheme: crate::scheme::Scheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every proposal a list of headings suggests.
|
/// Every proposal a list of headings suggests.
|
||||||
@@ -179,6 +186,68 @@ pub fn cluster(kind: Kind, items: &[Item], rules: &Rules) -> Vec<Proposal> {
|
|||||||
}
|
}
|
||||||
if kind == Kind::Tag {
|
if kind == Kind::Tag {
|
||||||
out.extend(junk_deletes(items, &grouped, rules));
|
out.extend(junk_deletes(items, &grouped, rules));
|
||||||
|
out.extend(scheme_proposals(items, &out, &rules.scheme));
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What a subject scheme says about the headings nothing else has claimed.
|
||||||
|
///
|
||||||
|
/// A heading the scheme spells differently is a merge onto the spelling it
|
||||||
|
/// uses; a heading the scheme does not have at all is a delete. Headings
|
||||||
|
/// already spoken for by a near-duplicate group or by the junk rules are left
|
||||||
|
/// alone, so nothing gets two proposals.
|
||||||
|
fn scheme_proposals(
|
||||||
|
items: &[Item],
|
||||||
|
already: &[Proposal],
|
||||||
|
scheme: &crate::scheme::Scheme,
|
||||||
|
) -> Vec<Proposal> {
|
||||||
|
if scheme.is_empty() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let spoken_for: Vec<i64> = already.iter().map(|proposal| proposal.drop_id).collect();
|
||||||
|
let mut out = Vec::new();
|
||||||
|
|
||||||
|
for item in items {
|
||||||
|
if spoken_for.contains(&item.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match scheme.canonical(&item.name) {
|
||||||
|
// Already the scheme's own spelling: nothing to say.
|
||||||
|
Some(subject) if subject == item.name => {}
|
||||||
|
Some(subject) => {
|
||||||
|
let keep = items.iter().find(|other| other.name == subject);
|
||||||
|
out.push(Proposal {
|
||||||
|
kind: Kind::Tag.name().to_string(),
|
||||||
|
action: "merge".to_string(),
|
||||||
|
keep: Some(subject.to_string()),
|
||||||
|
drop: item.name.clone(),
|
||||||
|
keep_id: keep.map(|keep| keep.id),
|
||||||
|
drop_id: item.id,
|
||||||
|
keep_count: keep.map_or(0, |keep| keep.count),
|
||||||
|
drop_count: item.count,
|
||||||
|
method: "scheme_alias".to_string(),
|
||||||
|
confidence: 0.95,
|
||||||
|
evidence: format!("the scheme files {:?} under {subject:?}", item.name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => out.push(Proposal {
|
||||||
|
kind: Kind::Tag.name().to_string(),
|
||||||
|
action: "delete".to_string(),
|
||||||
|
keep: None,
|
||||||
|
drop: item.name.clone(),
|
||||||
|
keep_id: None,
|
||||||
|
drop_id: item.id,
|
||||||
|
keep_count: 0,
|
||||||
|
drop_count: item.count,
|
||||||
|
method: "scheme_absent".to_string(),
|
||||||
|
confidence: 0.8,
|
||||||
|
evidence: format!(
|
||||||
|
"{:?} is not in the scheme, on {} books",
|
||||||
|
item.name, item.count
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
@@ -730,6 +799,7 @@ mod tests {
|
|||||||
fn a_device_named_after_its_owner_comes_from_the_rules() {
|
fn a_device_named_after_its_owner_comes_from_the_rules() {
|
||||||
let rules = Rules {
|
let rules = Rules {
|
||||||
device_prefixes: vec!["alexskobo".into()],
|
device_prefixes: vec!["alexskobo".into()],
|
||||||
|
..Rules::default()
|
||||||
};
|
};
|
||||||
assert_eq!(junk_reason("[alexskobo] to read", &Rules::default()), None);
|
assert_eq!(junk_reason("[alexskobo] to read", &Rules::default()), None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-0", "kind": "canonical", "tag": "Philosophy"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-1", "kind": "canonical", "tag": "philosophy"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-2", "kind": "canonical", "tag": "PHILOSOPHY"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-3", "kind": "canonical", "tag": " Philosophy "}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-4", "kind": "canonical", "tag": "Philosophie"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-5", "kind": "canonical", "tag": "SF"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-6", "kind": "canonical", "tag": "sf"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-7", "kind": "canonical", "tag": "Sci-Fi"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-8", "kind": "canonical", "tag": "General"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-9", "kind": "canonical", "tag": "general"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-10", "kind": "canonical", "tag": "[General]"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-11", "kind": "canonical", "tag": "*Misc*"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-12", "kind": "canonical", "tag": "Humanities"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-13", "kind": "canonical", "tag": "ebook"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-14", "kind": "canonical", "tag": "Underwater Basketry"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-15", "kind": "canonical", "tag": ""}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-16", "kind": "canonical", "tag": " "}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-17", "kind": "canonical", "tag": "Church History"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-18", "kind": "canonical", "tag": "Lit Crit"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-19", "kind": "canonical", "tag": "[Philosophy]"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-20", "kind": "canonical", "tag": "*Philosophy*"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-21", "kind": "canonical", "tag": "Non-Fiction"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-22", "kind": "canonical", "tag": "nonfiction"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-23", "kind": "canonical", "tag": "Theology."}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "canonical-24", "kind": "canonical", "tag": "Fiction"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-25", "kind": "parents", "subjects": ["Phenomenology"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-26", "kind": "parents", "subjects": ["Philosophy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-27", "kind": "parents", "subjects": ["History", "Philosophy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-28", "kind": "parents", "subjects": ["Basketry"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-29", "kind": "parents", "subjects": ["Literary Criticism"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-30", "kind": "parents", "subjects": ["Phenomenology", "Literary Criticism"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-31", "kind": "parents", "subjects": []}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-32", "kind": "parents", "subjects": ["Fiction", "Science Fiction"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-33", "kind": "parents", "subjects": ["Philosophy", "Philosophy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "parents-34", "kind": "parents", "subjects": ["Fantasy", "Phenomenology"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-35", "kind": "fiction", "subjects": ["Biography", "Fiction"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-36", "kind": "fiction", "subjects": ["Fiction", "History"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-37", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "War and Peace"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-38", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "The Cambridge Companion to Nietzsche"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-39", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "Logic: A Very Short Introduction"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-40", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "A Life of Wrangel"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-41", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "The Diary of a Writer"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-42", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "Collected Letters of Paul"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-43", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "Memoirs of a Geisha"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-44", "kind": "fiction", "subjects": ["Fiction", "History"], "title": "Essays in Idleness"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-45", "kind": "fiction", "subjects": ["Science Fiction", "Fantasy", "Biography"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-46", "kind": "fiction", "subjects": ["Literary Criticism", "Fantasy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-47", "kind": "fiction", "subjects": ["Fiction"], "title": "An Autobiography"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-48", "kind": "fiction", "subjects": ["Fiction"], "title": "Lectures on Ethics"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-49", "kind": "fiction", "subjects": ["Fiction"], "title": "Speeches"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-50", "kind": "fiction", "subjects": ["Fiction"], "title": "The Guidebook to Kant"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "fiction-51", "kind": "fiction", "subjects": ["Fiction"], "title": "Ordinary Title"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "compose-52", "kind": "compose", "subjects": ["Phenomenology", "Fiction"], "title": "A Life of Husserl"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "compose-53", "kind": "compose", "subjects": ["Phenomenology", "Fiction"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "compose-54", "kind": "compose", "subjects": ["Literary Criticism", "Fiction"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "compose-55", "kind": "compose", "subjects": ["Basketry", "Fiction"], "title": "A Life of Someone"}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "compose-56", "kind": "compose", "subjects": []}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-57", "kind": "needs", "existing": []}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-58", "kind": "needs", "existing": ["General"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-59", "kind": "needs", "existing": ["General", "ebook"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-60", "kind": "needs", "existing": ["Philosophy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-61", "kind": "needs", "existing": ["General", "Philosophy"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-62", "kind": "needs", "existing": ["Underwater Basketry"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-63", "kind": "needs", "existing": ["SF"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-64", "kind": "needs", "existing": ["sf", "General"]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-65", "kind": "needs", "existing": [""]}
|
||||||
|
{"scheme": {"subjects": ["Philosophy", "Phenomenology", "Theology", "History", "Biography", "Literary Criticism", "Fiction", "Science Fiction", "Fantasy"], "aliases": {"Philosophie": "Philosophy", "SF": "Science Fiction", "Sci-Fi": "Science Fiction", "Church History": "History", "Lit Crit": "Literary Criticism"}, "drop": ["General", "Humanities", "Non-Fiction", "Nonfiction", "ebook", "book", "[General]", "*Misc*"], "parents": {"Phenomenology": "Philosophy", "Literary Criticism": "History"}, "blocks_fiction": ["Biography", "Literary Criticism"], "fiction_genres": ["Fiction", "Science Fiction", "Fantasy"]}, "name": "needs-66", "kind": "needs", "existing": ["[General]"]}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
{"kind": "canonical", "name": "canonical-0", "subject": "Philosophy"}
|
||||||
|
{"kind": "canonical", "name": "canonical-1", "subject": "Philosophy"}
|
||||||
|
{"kind": "canonical", "name": "canonical-2", "subject": "Philosophy"}
|
||||||
|
{"kind": "canonical", "name": "canonical-3", "subject": "Philosophy"}
|
||||||
|
{"kind": "canonical", "name": "canonical-4", "subject": "Philosophy"}
|
||||||
|
{"kind": "canonical", "name": "canonical-5", "subject": "Science Fiction"}
|
||||||
|
{"kind": "canonical", "name": "canonical-6", "subject": "Science Fiction"}
|
||||||
|
{"kind": "canonical", "name": "canonical-7", "subject": "Science Fiction"}
|
||||||
|
{"kind": "canonical", "name": "canonical-8", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-9", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-10", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-11", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-12", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-13", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-14", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-15", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-16", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-17", "subject": "History"}
|
||||||
|
{"kind": "canonical", "name": "canonical-18", "subject": "Literary Criticism"}
|
||||||
|
{"kind": "canonical", "name": "canonical-19", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-20", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-21", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-22", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-23", "subject": null}
|
||||||
|
{"kind": "canonical", "name": "canonical-24", "subject": "Fiction"}
|
||||||
|
{"kind": "parents", "name": "parents-25", "subjects": ["Philosophy", "Phenomenology"]}
|
||||||
|
{"kind": "parents", "name": "parents-26", "subjects": ["Philosophy"]}
|
||||||
|
{"kind": "parents", "name": "parents-27", "subjects": ["Philosophy", "History"]}
|
||||||
|
{"kind": "parents", "name": "parents-28", "subjects": []}
|
||||||
|
{"kind": "parents", "name": "parents-29", "subjects": ["History", "Literary Criticism"]}
|
||||||
|
{"kind": "parents", "name": "parents-30", "subjects": ["Philosophy", "Phenomenology", "History", "Literary Criticism"]}
|
||||||
|
{"kind": "parents", "name": "parents-31", "subjects": []}
|
||||||
|
{"kind": "parents", "name": "parents-32", "subjects": ["Fiction", "Science Fiction"]}
|
||||||
|
{"kind": "parents", "name": "parents-33", "subjects": ["Philosophy"]}
|
||||||
|
{"kind": "parents", "name": "parents-34", "subjects": ["Philosophy", "Phenomenology", "Fantasy"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-35", "subjects": ["Biography"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-36", "subjects": ["History", "Fiction"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-37", "subjects": ["History", "Fiction"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-38", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-39", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-40", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-41", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-42", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-43", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-44", "subjects": ["History"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-45", "subjects": ["Biography"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-46", "subjects": ["Literary Criticism"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-47", "subjects": ["Fiction"]}
|
||||||
|
{"kind": "fiction", "name": "fiction-48", "subjects": []}
|
||||||
|
{"kind": "fiction", "name": "fiction-49", "subjects": []}
|
||||||
|
{"kind": "fiction", "name": "fiction-50", "subjects": []}
|
||||||
|
{"kind": "fiction", "name": "fiction-51", "subjects": ["Fiction"]}
|
||||||
|
{"kind": "compose", "name": "compose-52", "subjects": ["Philosophy", "Phenomenology"]}
|
||||||
|
{"kind": "compose", "name": "compose-53", "subjects": ["Philosophy", "Phenomenology", "Fiction"]}
|
||||||
|
{"kind": "compose", "name": "compose-54", "subjects": ["History", "Literary Criticism"]}
|
||||||
|
{"kind": "compose", "name": "compose-55", "subjects": []}
|
||||||
|
{"kind": "compose", "name": "compose-56", "subjects": []}
|
||||||
|
{"kind": "needs", "name": "needs-57", "needs": true}
|
||||||
|
{"kind": "needs", "name": "needs-58", "needs": true}
|
||||||
|
{"kind": "needs", "name": "needs-59", "needs": true}
|
||||||
|
{"kind": "needs", "name": "needs-60", "needs": false}
|
||||||
|
{"kind": "needs", "name": "needs-61", "needs": false}
|
||||||
|
{"kind": "needs", "name": "needs-62", "needs": true}
|
||||||
|
{"kind": "needs", "name": "needs-63", "needs": false}
|
||||||
|
{"kind": "needs", "name": "needs-64", "needs": false}
|
||||||
|
{"kind": "needs", "name": "needs-65", "needs": true}
|
||||||
|
{"kind": "needs", "name": "needs-66", "needs": true}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
"""Apply a subject scheme the way the book pipeline did, for comparison.
|
||||||
|
|
||||||
|
The four functions below are the originals, copied out of the subjects module
|
||||||
|
verbatim and with the module-level scheme lifted into an argument — importing
|
||||||
|
it opens a database connection and loads a chat client, and neither decides
|
||||||
|
anything. What decides is the arithmetic of the scheme, which is what this
|
||||||
|
compares.
|
||||||
|
|
||||||
|
python3 oracle/subjects.py < cases.ndjson
|
||||||
|
|
||||||
|
One case per line, carrying its own scheme. Writes one JSON answer per line.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_STUDY_TITLE_RE = re.compile(
|
||||||
|
r"\b(companion to|guidebook to|very short introduction|"
|
||||||
|
r"letters of|collected letters|memoirs?\b|autobiograph|"
|
||||||
|
r"\bdiary\b|\bessays\b|\blectures\b|\bspeeches\b|"
|
||||||
|
r"a life of|biography of)\b",
|
||||||
|
re.IGNORECASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def canonical_tag(name, scheme):
|
||||||
|
subject_lower = {s.lower(): s for s in scheme["subjects"]}
|
||||||
|
alias_lower = {k.lower(): v for k, v in scheme["aliases"].items()}
|
||||||
|
drop_lower = {d.lower().strip("*[]") for d in scheme["drop"]}
|
||||||
|
t = (name or "").strip()
|
||||||
|
if not t:
|
||||||
|
return None
|
||||||
|
low = t.lower()
|
||||||
|
if low in drop_lower or low.strip("*[]") in drop_lower:
|
||||||
|
return None
|
||||||
|
if low in subject_lower:
|
||||||
|
return subject_lower[low]
|
||||||
|
if low in alias_lower:
|
||||||
|
return alias_lower[low]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def expand_parents(subjects, scheme):
|
||||||
|
subject_set = frozenset(scheme["subjects"])
|
||||||
|
chosen = set()
|
||||||
|
for s in subjects:
|
||||||
|
if s not in subject_set:
|
||||||
|
continue
|
||||||
|
chosen.add(s)
|
||||||
|
parent = scheme["parents"].get(s)
|
||||||
|
if parent:
|
||||||
|
chosen.add(parent)
|
||||||
|
return [s for s in scheme["subjects"] if s in chosen]
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_subjects(subjects, scheme, title=None):
|
||||||
|
blocks = frozenset(scheme["blocks_fiction"])
|
||||||
|
genres = frozenset(scheme["fiction_genres"])
|
||||||
|
chosen = set(subjects)
|
||||||
|
study = bool(title and _STUDY_TITLE_RE.search(title))
|
||||||
|
if chosen & blocks or study:
|
||||||
|
chosen -= genres
|
||||||
|
return [s for s in scheme["subjects"] if s in chosen]
|
||||||
|
|
||||||
|
|
||||||
|
def compose_tags(subjects, scheme, title=None):
|
||||||
|
return sanitize_subjects(expand_parents(subjects, scheme), scheme, title=title)
|
||||||
|
|
||||||
|
|
||||||
|
def needs_classify(existing, scheme):
|
||||||
|
subject_set = frozenset(scheme["subjects"])
|
||||||
|
for raw in existing:
|
||||||
|
c = canonical_tag(raw, scheme)
|
||||||
|
if c and c in subject_set:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def answer(case):
|
||||||
|
scheme, kind = case["scheme"], case["kind"]
|
||||||
|
if kind == "canonical":
|
||||||
|
return {"subject": canonical_tag(case["tag"], scheme)}
|
||||||
|
if kind == "parents":
|
||||||
|
return {"subjects": expand_parents(case["subjects"], scheme)}
|
||||||
|
if kind == "fiction":
|
||||||
|
return {"subjects": sanitize_subjects(case["subjects"], scheme, title=case.get("title"))}
|
||||||
|
if kind == "compose":
|
||||||
|
return {"subjects": compose_tags(case["subjects"], scheme, title=case.get("title"))}
|
||||||
|
if kind == "needs":
|
||||||
|
return {"needs": needs_classify(case["existing"], scheme)}
|
||||||
|
raise SystemExit(f"no such case: {kind}")
|
||||||
|
|
||||||
|
|
||||||
|
for line in sys.stdin:
|
||||||
|
if not line.strip():
|
||||||
|
continue
|
||||||
|
case = json.loads(line)
|
||||||
|
out = {"name": case["name"], "kind": case["kind"]}
|
||||||
|
out.update(answer(case))
|
||||||
|
sys.stdout.write(json.dumps(out, sort_keys=True) + "\n")
|
||||||
+14
-1
@@ -19,7 +19,7 @@ type Written = Result<Vec<String>, String>;
|
|||||||
type Job = (&'static str, fn() -> Written);
|
type Job = (&'static str, fn() -> Written);
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let jobs: [Job; 18] = [
|
let jobs: [Job; 19] = [
|
||||||
("tokens", tokens),
|
("tokens", tokens),
|
||||||
("unescape", unescape),
|
("unescape", unescape),
|
||||||
("chunkmd", chunkmd),
|
("chunkmd", chunkmd),
|
||||||
@@ -38,6 +38,7 @@ fn main() -> ExitCode {
|
|||||||
("avplan", avplan),
|
("avplan", avplan),
|
||||||
("pdfgutter", pdfgutter),
|
("pdfgutter", pdfgutter),
|
||||||
("seriesof", seriesof),
|
("seriesof", seriesof),
|
||||||
|
("subjects", subjects),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (name, job) in jobs {
|
for (name, job) in jobs {
|
||||||
@@ -220,6 +221,18 @@ fn cueseg() -> Written {
|
|||||||
Ok(written)
|
Ok(written)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn subjects() -> Written {
|
||||||
|
let dir = parity::golden("subjects");
|
||||||
|
std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let cases = parity::dir().join("cases/subjects/cases.ndjson");
|
||||||
|
let text = std::fs::read_to_string(&cases).map_err(|e| e.to_string())?;
|
||||||
|
let answers = parity::run_oracle("subjects.py", &text)?;
|
||||||
|
let path = dir.join("cases.ndjson");
|
||||||
|
std::fs::write(&path, answers).map_err(|e| e.to_string())?;
|
||||||
|
Ok(vec![path.display().to_string()])
|
||||||
|
}
|
||||||
|
|
||||||
fn seriesof() -> Written {
|
fn seriesof() -> Written {
|
||||||
let dir = parity::golden("seriesof");
|
let dir = parity::golden("seriesof");
|
||||||
std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
|
std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
//! Every judgement a subject scheme makes must match the Python exactly.
|
||||||
|
//!
|
||||||
|
//! A scheme decides what a shelf can be browsed by. A heading mapped onto the
|
||||||
|
//! wrong subject files a book where nobody will look for it, and a fiction
|
||||||
|
//! genre left on a biography puts a life of somebody in among the novels.
|
||||||
|
|
||||||
|
use bibclean::scheme::Scheme;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
fn records(text: &str) -> Vec<Value> {
|
||||||
|
text.lines()
|
||||||
|
.filter(|line| !line.trim().is_empty())
|
||||||
|
.map(|line| serde_json::from_str(line).expect("valid JSON"))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cases() -> Vec<Value> {
|
||||||
|
let text = std::fs::read_to_string(parity::dir().join("cases/subjects/cases.ndjson"))
|
||||||
|
.expect("a readable case file");
|
||||||
|
records(&text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strings(value: &Value) -> Vec<String> {
|
||||||
|
value
|
||||||
|
.as_array()
|
||||||
|
.expect("an array")
|
||||||
|
.iter()
|
||||||
|
.map(|item| item.as_str().expect("a string").to_string())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_judgement_matches_python() {
|
||||||
|
let golden = records(&parity::read_golden_text("subjects/cases.ndjson"));
|
||||||
|
let cases = cases();
|
||||||
|
assert_eq!(cases.len(), golden.len(), "case count moved — regenerate");
|
||||||
|
|
||||||
|
let mut wrong: Vec<String> = Vec::new();
|
||||||
|
for (case, theirs) in cases.iter().zip(&golden) {
|
||||||
|
let name = case["name"].as_str().expect("a name");
|
||||||
|
let kind = case["kind"].as_str().expect("a kind");
|
||||||
|
assert_eq!(theirs["name"].as_str(), Some(name), "cases out of order");
|
||||||
|
|
||||||
|
// The scheme travels with the case, because a scheme is exactly the
|
||||||
|
// thing that is not compiled in.
|
||||||
|
let scheme: Scheme =
|
||||||
|
serde_json::from_value(case["scheme"].clone()).expect("a readable scheme");
|
||||||
|
let title = case["title"].as_str();
|
||||||
|
|
||||||
|
let mut note = |field: &str, ours: String, theirs: &Value| {
|
||||||
|
wrong.push(format!("{name}.{field}: python {theirs}, rust {ours}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
"canonical" => {
|
||||||
|
let ours = scheme.canonical(case["tag"].as_str().expect("a tag"));
|
||||||
|
if ours != theirs["subject"].as_str() {
|
||||||
|
note("subject", format!("{ours:?}"), &theirs["subject"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"parents" => {
|
||||||
|
let ours = scheme.with_parents(&strings(&case["subjects"]));
|
||||||
|
if ours != strings(&theirs["subjects"]) {
|
||||||
|
note("subjects", format!("{ours:?}"), &theirs["subjects"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"fiction" => {
|
||||||
|
let ours = scheme.without_impossible_fiction(&strings(&case["subjects"]), title);
|
||||||
|
if ours != strings(&theirs["subjects"]) {
|
||||||
|
note("subjects", format!("{ours:?}"), &theirs["subjects"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"compose" => {
|
||||||
|
let ours = scheme.compose(&strings(&case["subjects"]), title);
|
||||||
|
if ours != strings(&theirs["subjects"]) {
|
||||||
|
note("subjects", format!("{ours:?}"), &theirs["subjects"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"needs" => {
|
||||||
|
let ours = scheme.needs_subject(&strings(&case["existing"]));
|
||||||
|
if Some(ours) != theirs["needs"].as_bool() {
|
||||||
|
note("needs", ours.to_string(), &theirs["needs"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => panic!("nothing answers a {other} case"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
wrong.is_empty(),
|
||||||
|
"{} judgements differ:\n{}",
|
||||||
|
wrong.len(),
|
||||||
|
wrong
|
||||||
|
.iter()
|
||||||
|
.take(20)
|
||||||
|
.map(|line| line.chars().take(200).collect::<String>())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every question has to be asked, or the file proves less than it looks like
|
||||||
|
/// it does.
|
||||||
|
#[test]
|
||||||
|
fn every_kind_of_case_is_present() {
|
||||||
|
let cases = cases();
|
||||||
|
for kind in ["canonical", "parents", "fiction", "compose", "needs"] {
|
||||||
|
assert!(
|
||||||
|
cases.iter().any(|case| case["kind"] == kind),
|
||||||
|
"no {kind} case"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Catches a golden file drifting away from a Python that has moved on.
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "python")]
|
||||||
|
fn the_golden_file_still_matches_live_python() {
|
||||||
|
let cases = std::fs::read_to_string(parity::dir().join("cases/subjects/cases.ndjson"))
|
||||||
|
.expect("a readable case file");
|
||||||
|
let live = parity::run_oracle("subjects.py", &cases).expect("the oracle runs");
|
||||||
|
assert_eq!(live, parity::read_golden_text("subjects/cases.ndjson"));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user