Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
44f0f7e
Add patch for citeproc
kaysiz Apr 24, 2026
3103b12
update the patch
kaysiz Apr 24, 2026
227c66b
update the patch
kaysiz Apr 24, 2026
7a289ec
revert the patch
kaysiz Apr 24, 2026
76e8760
update the patch
kaysiz Apr 24, 2026
4a89803
update the patch
kaysiz Apr 24, 2026
aa15454
update the extension
kaysiz Apr 24, 2026
e509b7c
update the extension
kaysiz Apr 24, 2026
85c9e64
update the extension
kaysiz Apr 24, 2026
706289f
update the extension
kaysiz Apr 24, 2026
26b91ee
update the extension
kaysiz Apr 24, 2026
d058293
update the extension
kaysiz Apr 24, 2026
fdda72c
update the extension
kaysiz Apr 24, 2026
f49c940
update the extension
kaysiz Apr 24, 2026
30eb553
update the extension
kaysiz Apr 24, 2026
372bb15
update the extension
kaysiz Apr 24, 2026
90a2f3b
update the extension
kaysiz Apr 24, 2026
f77ecf9
test removal of contributor
kaysiz Apr 27, 2026
141e729
revert: test removal of contributor
kaysiz Apr 27, 2026
a905944
monkey patch citeproc variables to include contributor and accepted-date
kaysiz Apr 27, 2026
dbe97e6
monkey patch citeproc variables to include contributor and accepted-date
kaysiz Apr 27, 2026
fb0ade9
rebuild factories
kaysiz Apr 27, 2026
05660c5
rebuild factories
kaysiz Apr 27, 2026
055c24c
remove duplicate contributor display
kaysiz Apr 27, 2026
32e6ba0
Update citeproc type mapping for resourceTypeGeneral Software with ne…
codycooperross Apr 28, 2026
8ec4589
Add test for citeproc bug
codycooperross Apr 27, 2026
8d94a14
update spec expectation
kaysiz Apr 28, 2026
92fbbc7
fix formatting
kaysiz Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/bolognese.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
require 'csl/styles'
require 'edtf'

require "bolognese/citeproc_extensions"
require "bolognese/version"
require "bolognese/metadata"
require "bolognese/cli"
Expand Down
48 changes: 48 additions & 0 deletions lib/bolognese/citeproc_extensions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

# Minimal patch for csl-ruby and citeproc-ruby compatibility
# Root cause: 'contributor' is not recognized as a names variable in citeproc gem
# https://github.com/inukshuk/citeproc/blob/121fa4a950b9bd71960e42d20db96bcea1165201/lib/citeproc/variable.rb#L20-L24

module CiteProc
class Variable
# Unfreeze, modify, and refreeze the fields to add 'contributor' and 'accepted-date'
if @fields
# Unfreeze the fields hash temporarily
fields_dup = @fields.dup

# Add contributor to names (make a new unfrozen array)
fields_dup[:names] = (@fields[:names] + [:contributor]).uniq

# Add accepted-date to dates (make a new unfrozen array)
fields_dup[:date] = (@fields[:date] + [:'accepted-date']).uniq

# Rebuild the types mapping - only use actual type keys, not aliases like :all, :any, etc.
types_hash = Hash[*[:date, :names, :number, :text].map { |k| fields_dup[k].map { |n| [n, k] } }.flatten]

# Update the class instance variables
@fields = fields_dup
@types = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge(types_hash).freeze

# Rebuild @factories from the new @types
# This maps each field name to its Variable subclass (Names, Date, Text, Number)
@factories = Hash.new { |h,k| h.fetch(k.to_s.intern, CiteProc::Variable) }.merge(
Hash[*@types.map { |field_name, type|
[field_name, CiteProc.const_get(type.to_s.capitalize)]
}.flatten]
).freeze

# Recreate the aliases
@fields[:name] = @fields[:names]
@fields[:dates] = @fields[:date]
@fields[:numbers] = @fields[:number]

# Recreate :all and :any
@fields[:all] = @fields[:any] =
[:date, :names, :text, :number].reduce([]) { |s,a| s.concat(@fields[a]) }.sort

# Refreeze fields
@fields.freeze
end
end
end
15 changes: 12 additions & 3 deletions lib/bolognese/metadata_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,28 @@ def citeproc_hsh
author = to_citeproc(creators)
end

if types["resourceTypeGeneral"] == "Software" && version_info.present?
type = "book"
if types["resourceTypeGeneral"] == "Software"
type = "software"
else
type = types["citeproc"]
end

# Filter out contributors who are already creators, editors, or translators to avoid duplication
creator_names = Array.wrap(creators).map { |c| c["name"] || [c["givenName"], c["familyName"]].compact.join(" ") }.compact
unique_contributors = Array.wrap(contributors).reject do |c|
contributor_name = c["name"] || [c["givenName"], c["familyName"]].compact.join(" ")
creator_names.include?(contributor_name) ||
c["contributorType"] == "Editor" ||
c["contributorType"] == "Translator"
end

{
"type" => type,
"id" => normalize_doi(doi),
"categories" => Array.wrap(subjects).map { |k| parse_attributes(k, content: "subject", first: true) }.presence,
"language" => language,
"author" => author,
"contributor" => to_citeproc(contributors),
"contributor" => unique_contributors.presence ? to_citeproc(unique_contributors) : nil,
"editor" => contributors ? to_citeproc(contributors.select { |c| c["contributorType"] == "Editor" }) : nil,
"translator" => contributors ? to_citeproc(contributors.select { |c| c["contributorType"] == "Translator" }) : nil,
"issued" => get_date(dates, "Issued") ? get_date_parts(get_date(dates, "Issued")) : get_date_parts(publication_year.to_s),
Expand Down
58 changes: 58 additions & 0 deletions spec/fixtures/datacite_xml_csl_with_contributors_and_available.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://datacite.org/schema/kernel-4" xsi:schemaLocation="http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4/metadata.xsd">
<identifier identifierType="DOI">10.81360/BIFURCATED</identifier>
<creators>
<creator>
<creatorName>Toon, Geoffrey C.</creatorName>
<affiliation>Jet Propulsion Laboratory, California Institute of Technology, Pasadena, CA, USA</affiliation>
</creator>
<creator>
<creatorName>Wunch, Debra</creatorName>
<nameIdentifier nameIdentifierScheme="ORCID">0000-0002-4924-0377</nameIdentifier>
<affiliation>California Institute of Technology, Pasadena, CA, U.S.A.</affiliation>
</creator>
</creators>
<titles>
<title>A stand-alone a priori profile generation tool for GGG2014 release</title>
</titles>
<publisher>CaltechDATA</publisher>
<publicationYear>2015</publicationYear>
<subjects>
<subject>TCCON</subject>
</subjects>
<contributors>
<contributor contributorType="ContactPerson">
<contributorName>Toon, Geoffrey C.</contributorName>
<affiliation>Jet Propulsion Laboratory, California Institute of Technology, Pasadena, CA, USA</affiliation>
</contributor>
<contributor contributorType="ContactPerson">
<contributorName>Wunch, Debra</contributorName>
<affiliation>California Institute of Technology, Pasadena, CA, USA</affiliation>
</contributor>
<contributor contributorType="ResearchGroup">
<contributorName>TCCON</contributorName>
</contributor>
</contributors>
<dates>
<date dateType="Submitted">2017-07-24</date>
<date dateType="Available">2015-10-14</date>
</dates>
<language>eng</language>
<resourceType resourceTypeGeneral="Software"/>
<alternateIdentifiers>
<alternateIdentifier alternateIdentifierType="CaltechDATA_Identifier">250</alternateIdentifier>
<alternateIdentifier alternateIdentifierType="CaltechDATA_Identifier">250</alternateIdentifier>
</alternateIdentifiers>
<relatedIdentifiers>
<relatedIdentifier relatedIdentifierType="DOI" relationType="IsDocumentedBy">10.14291/tccon.ggg2014.documentation.R0/1221662</relatedIdentifier>
<relatedIdentifier relatedIdentifierType="URL" relationType="IsDocumentedBy">https://tccon-wiki.caltech.edu/</relatedIdentifier>
</relatedIdentifiers>
<version>GGG2014.R0</version>
<rightsList>
<rights rightsURI="https://data.caltech.edu/tindfiles/serve/8ff8bc09-cecd-468d-b219-3ea372f2ea95/">TCCON Data Use Policy</rights>
</rightsList>
<descriptions>
<description descriptionType="Other">The Total Carbon Column Observing Network (TCCON) is a network of ground-based Fourier Transform Spectrometers that record direct solar absorption spectra of the atmosphere in the near-infrared. From these spectra, accurate and precise column-averaged abundances of atmospheric constituents including CO2, CH4, N2O, HF, CO, H2O, and HDO, are retrieved. This is a stand-alone a priori profile generation tool for the GGG2014 data release.</description>
<description descriptionType="Other">&lt;br&gt;Cite this record as:&lt;br&gt;Toon, G. C., &amp;amp; Wunch, D. (2017). A stand-alone a priori profile generation tool for GGG2014 release. CaltechDATA. &lt;a href="https://doi.org/10.14291/tccon.ggg2014.priors.r0/1221661"&gt;https://doi.org/10.14291/tccon.ggg2014.priors.r0/1221661&lt;/a&gt;&lt;br&gt; or choose a &lt;a href="https://crosscite.org/?doi=10.14291/TCCON.GGG2014.PRIORS.R0/1221661"&gt; different citation style.&lt;/a&gt;&lt;br&gt;&lt;a href="https://data.datacite.org/application/x-bibtex/10.14291/TCCON.GGG2014.PRIORS.R0/1221661"&gt;Download Citation&lt;/a&gt;&lt;br&gt;</description>
</descriptions>
</resource>
8 changes: 7 additions & 1 deletion spec/writers/citation_writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
subject = Bolognese::Metadata.new(input: input, from: "datacite")
expect(subject.style).to eq("apa")
expect(subject.locale).to eq("en-US")
expect(subject.citation).to eq("Lab for Exosphere and Near Space Environment Studies. (2019). <i>lenses-lab/LYAO_RT-2018JA026426: Original Release</i> (Version 1.0.0). Zenodo. https://doi.org/10.5281/zenodo.2598836")
expect(subject.citation).to eq("Lab for Exosphere and Near Space Environment Studies. (2019). <i>lenses-lab/LYAO_RT-2018JA026426: Original Release</i> (Version 1.0.0) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.2598836")
end

it "interactive resource without dates" do
Expand Down Expand Up @@ -112,5 +112,11 @@
expect(subject.locale).to eq("en-US")
expect(subject.citation).to eq("M. Fenner, “Eating your own Dog Food,” <i>Understanding the fictional John Smith</i>, vol. 776, no. 1. DataCite, pp. 50–60, Dec. 20, 2016. doi: 10.5438/4k3m-nyvg.")
end

it "with contributors and available date" do
input = fixture_path + "datacite_xml_csl_with_contributors_and_available.xml"
subject = Bolognese::Metadata.new(input: input, from: "datacite")
expect(subject.citation).to eq("Toon, G. C., &amp; Wunch, D. (2015). <i>A stand-alone a priori profile generation tool for GGG2014 release</i> (Version GGG2014.R0) [Computer software]. CaltechDATA. https://doi.org/10.81360/bifurcated")
end
end
end
8 changes: 4 additions & 4 deletions spec/writers/citeproc_writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
input = "https://doi.org/10.6084/m9.figshare.4906367.v1"
subject = Bolognese::Metadata.new(input: input, from: "datacite")
json = JSON.parse(subject.citeproc)
expect(json["type"]).to eq("article")
expect(json["type"]).to eq("software")
expect(json["DOI"]).to eq("10.6084/m9.figshare.4906367.v1")
expect(json["title"]).to eq("Scimag catalogue of LibGen as of January 1st, 2014")
expect(json["copyright"]).to eq("Creative Commons Zero v1.0 Universal")
Expand All @@ -115,7 +115,7 @@
input = "https://doi.org/10.5281/zenodo.2598836"
subject = Bolognese::Metadata.new(input: input, from: "datacite")
json = JSON.parse(subject.citeproc)
expect(json["type"]).to eq("book")
expect(json["type"]).to eq("software")
expect(json["DOI"]).to eq("10.5281/zenodo.2598836")
expect(json["version"]).to eq("1.0.0")
expect(json["copyright"]).to eq("Open Access")
Expand All @@ -125,7 +125,7 @@
input = fixture_path + "datacite_software_version.json"
subject = Bolognese::Metadata.new(input: input, from: "datacite_json")
json = JSON.parse(subject.citeproc)
expect(json["type"]).to eq("book")
expect(json["type"]).to eq("software")
expect(json["DOI"]).to eq("10.5281/ZENODO.2598836")
expect(json["version"]).to eq("1.0.0")
expect(json["copyright"]).to eq("Open Access")
Expand Down Expand Up @@ -241,7 +241,7 @@
input = "https://github.com/datacite/maremma"
subject = Bolognese::Metadata.new(input: input, from: "codemeta")
json = JSON.parse(subject.citeproc)
expect(json["type"]).to eq("article-journal")
expect(json["type"]).to eq("software")
expect(json["id"]).to eq("https://doi.org/10.5438/qeg0-3gm3")
expect(json["DOI"]).to eq("10.5438/qeg0-3gm3")
expect(json["title"]).to eq("Maremma: a Ruby library for simplified network calls")
Expand Down
Loading