Skip to content

Commit 3fed159

Browse files
committed
add missing papers
1 parent c6e7885 commit 3fed159

6 files changed

Lines changed: 100 additions & 0 deletions

‎.githooks/pre-commit‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/sh
2+
# Blocks commits that touch _data/publications.yaml unless every
3+
# La-Cava-authored publication has a matching PDF in assets/papers/.
4+
# Installed via: git config core.hooksPath .githooks
5+
6+
if git diff --cached --name-only | grep -q '^_data/publications\.yaml$'; then
7+
ruby "$(git rev-parse --show-toplevel)/scripts/check_publication_pdfs.rb"
8+
status=$?
9+
if [ $status -ne 0 ]; then
10+
echo ""
11+
echo "Commit blocked: copy the missing PDF(s) into assets/papers/ (filename must"
12+
echo "match exactly, per Zotero's 'Rename Associated File' convention), then re-stage."
13+
echo "To bypass once (not recommended): git commit --no-verify"
14+
exit 1
15+
fi
16+
fi
17+
18+
exit 0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

‎scripts/check_publication_pdfs.rb‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# Verifies that every publication in _data/publications.yaml (that lists
5+
# La Cava as an author, matching the filter in _pages/papers.md) has a
6+
# matching PDF checked into assets/papers/. Filenames are derived with the
7+
# exact same logic as _includes/pub-single.html so this stays in sync with
8+
# what the site actually links to (and with Zotero's own "Rename Associated
9+
# File" convention: "{Author(s)} - {Year} - {Title, 50 chars}.pdf").
10+
#
11+
# Usage:
12+
# ruby scripts/check_publication_pdfs.rb # error on missing PDFs
13+
# ruby scripts/check_publication_pdfs.rb --list # just list, exit 0
14+
15+
require 'yaml'
16+
require 'pathname'
17+
18+
ROOT = Pathname.new(__dir__).parent
19+
DATA_FILE = ROOT / '_data' / 'publications.yaml'
20+
PAPERS_DIR = ROOT / 'assets' / 'papers'
21+
22+
def author_surname(author)
23+
return author['literal'] if author['literal']
24+
25+
particle = author['non-dropping-particle']
26+
family = author['family']
27+
[particle, family].compact.join(' ').strip
28+
end
29+
30+
def by_cava?(pub)
31+
Array(pub['author']).any? do |author|
32+
(author['family'] || '').include?('Cava') || (author['literal'] || '').include?('Cava')
33+
end
34+
end
35+
36+
def pdf_author(pub)
37+
authors = Array(pub['author'])
38+
first = author_surname(authors[0])
39+
case authors.size
40+
when 0 then ''
41+
when 1 then first
42+
when 2 then "#{first} and #{author_surname(authors[1])}"
43+
else "#{first} et al."
44+
end
45+
end
46+
47+
# Mirrors Liquid's `truncate: 50, ''` followed by `strip`.
48+
def pdf_title(pub)
49+
title = (pub['title'] || '').to_s
50+
truncated = title.length > 50 ? title[0, 50] : title
51+
truncated.strip
52+
end
53+
54+
def expected_filename(pub)
55+
year = pub.dig('issued', 0, 'year')
56+
base = "#{pdf_author(pub)} - #{year} - #{pdf_title(pub)}.pdf"
57+
base.delete(':').delete('?')
58+
end
59+
60+
data = YAML.load_file(DATA_FILE)
61+
refs = data['references'] || []
62+
cava_refs = refs.select { |pub| by_cava?(pub) }
63+
64+
missing = cava_refs.filter_map do |pub|
65+
filename = expected_filename(pub)
66+
path = PAPERS_DIR / filename
67+
[pub['id'], filename] unless path.exist?
68+
end
69+
70+
list_only = ARGV.include?('--list')
71+
72+
if missing.empty?
73+
puts "All #{cava_refs.size} publication PDFs are present in #{PAPERS_DIR.relative_path_from(ROOT)}."
74+
exit 0
75+
end
76+
77+
warn "#{missing.size} publication#{'s' if missing.size != 1} missing a PDF in #{PAPERS_DIR.relative_path_from(ROOT)}:"
78+
missing.each do |id, filename|
79+
warn " - [#{id}] #{filename}"
80+
end
81+
82+
exit(list_only ? 0 : 1)

0 commit comments

Comments
 (0)