From 44f0f7ee6b2efca9da3cf7b6d5c56be65b7956c3 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 09:06:13 +0200 Subject: [PATCH 01/28] Add patch for citeproc --- lib/bolognese.rb | 1 + lib/bolognese/citeproc_extensions.rb | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 lib/bolognese/citeproc_extensions.rb diff --git a/lib/bolognese.rb b/lib/bolognese.rb index 0a697b63..048d063e 100644 --- a/lib/bolognese.rb +++ b/lib/bolognese.rb @@ -13,6 +13,7 @@ require 'jsonlint' require 'gender_detector' require 'citeproc' +require 'bolognese/citeproc_extensions' require 'csl/styles' require 'edtf' diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb new file mode 100644 index 00000000..cca09e3d --- /dev/null +++ b/lib/bolognese/citeproc_extensions.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Ruby 4.0 compatibility patch for citeproc-ruby +module CiteProc + class Variable + # Delegate Enumerable methods that may not be properly forwarded in Ruby 4 + def take(n) + to_a.take(n) + end + + def method_missing(method, *args, &block) + if to_a.respond_to?(method) + to_a.send(method, *args, &block) + else + super + end + end + + def respond_to_missing?(method, include_private = false) + to_a.respond_to?(method, include_private) || super + end + end +end \ No newline at end of file From 3103b1230001da77af8d4b7b8448b8a9fd188cbb Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 09:22:22 +0200 Subject: [PATCH 02/28] update the patch --- lib/bolognese/citeproc_extensions.rb | 48 ++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index cca09e3d..bdde2929 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -3,21 +3,51 @@ # Ruby 4.0 compatibility patch for citeproc-ruby module CiteProc class Variable + # Add to_a method to convert Variable to array when needed + def to_a + val = @value + case val + when Array + val + when nil + [] + else + [val] + end + end + # Delegate Enumerable methods that may not be properly forwarded in Ruby 4 def take(n) to_a.take(n) end - def method_missing(method, *args, &block) - if to_a.respond_to?(method) - to_a.send(method, *args, &block) - else - super - end + def first + to_a.first + end + + def last + to_a.last + end + + def empty? + to_a.empty? + end + + def size + to_a.size + end + alias length size + + def each(&block) + to_a.each(&block) + end + + def map(&block) + to_a.map(&block) end - def respond_to_missing?(method, include_private = false) - to_a.respond_to?(method, include_private) || super + def select(&block) + to_a.select(&block) end end -end \ No newline at end of file +end From 227c66b91019693f475a05032719b50ba2318edf Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 09:38:52 +0200 Subject: [PATCH 03/28] update the patch --- lib/bolognese/citeproc_extensions.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index bdde2929..79e4f6ae 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -49,5 +49,26 @@ def map(&block) def select(&block) to_a.select(&block) end + + # CiteProc name type checking methods + def personal? + # Check if the value is a personal name (has family/given structure) + val = @value + return false if val.nil? + return val.personal? if val.respond_to?(:personal?) + # If it's a hash with family name, it's personal + return true if val.is_a?(Hash) && val.key?('family') + false + end + + def literal? + # Check if the value is a literal name (organization) + val = @value + return false if val.nil? + return val.literal? if val.respond_to?(:literal?) + # If it's a hash with literal key, it's literal + return true if val.is_a?(Hash) && val.key?('literal') + false + end end end From 7a289ec79a360dfedad1cb7223bf61597afe66dd Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 09:52:20 +0200 Subject: [PATCH 04/28] revert the patch --- lib/bolognese.rb | 1 - lib/bolognese/citeproc_extensions.rb | 74 ---------------------------- 2 files changed, 75 deletions(-) delete mode 100644 lib/bolognese/citeproc_extensions.rb diff --git a/lib/bolognese.rb b/lib/bolognese.rb index 048d063e..0a697b63 100644 --- a/lib/bolognese.rb +++ b/lib/bolognese.rb @@ -13,7 +13,6 @@ require 'jsonlint' require 'gender_detector' require 'citeproc' -require 'bolognese/citeproc_extensions' require 'csl/styles' require 'edtf' diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb deleted file mode 100644 index 79e4f6ae..00000000 --- a/lib/bolognese/citeproc_extensions.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -# Ruby 4.0 compatibility patch for citeproc-ruby -module CiteProc - class Variable - # Add to_a method to convert Variable to array when needed - def to_a - val = @value - case val - when Array - val - when nil - [] - else - [val] - end - end - - # Delegate Enumerable methods that may not be properly forwarded in Ruby 4 - def take(n) - to_a.take(n) - end - - def first - to_a.first - end - - def last - to_a.last - end - - def empty? - to_a.empty? - end - - def size - to_a.size - end - alias length size - - def each(&block) - to_a.each(&block) - end - - def map(&block) - to_a.map(&block) - end - - def select(&block) - to_a.select(&block) - end - - # CiteProc name type checking methods - def personal? - # Check if the value is a personal name (has family/given structure) - val = @value - return false if val.nil? - return val.personal? if val.respond_to?(:personal?) - # If it's a hash with family name, it's personal - return true if val.is_a?(Hash) && val.key?('family') - false - end - - def literal? - # Check if the value is a literal name (organization) - val = @value - return false if val.nil? - return val.literal? if val.respond_to?(:literal?) - # If it's a hash with literal key, it's literal - return true if val.is_a?(Hash) && val.key?('literal') - false - end - end -end From 76e87603d554b82fcfc687484ab1431ca41a4e99 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 10:15:53 +0200 Subject: [PATCH 05/28] update the patch --- lib/bolognese/citeproc_extensions.rb | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 lib/bolognese/citeproc_extensions.rb diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb new file mode 100644 index 00000000..9ce37c25 --- /dev/null +++ b/lib/bolognese/citeproc_extensions.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +# Minimal patch for csl-ruby compatibility +module CiteProc + class Variable + # Fix for: undefined method 'take' for an instance of CiteProc::Variable + # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 + def take(n) + val = @value + array = case val + when Array then val + when nil then [] + else [val] + end + array.take(n) + end + end +end +# frozen_string_literal: true + +# Ruby 4.0 compatibility patch for citeproc-ruby +module CiteProc + class Variable + # Add to_a method to convert Variable to array when needed + def to_a + val = @value + case val + when Array + val + when nil + [] + else + [val] + end + end + + # Delegate Enumerable methods that may not be properly forwarded in Ruby 4 + def take(n) + to_a.take(n) + end + + def first + to_a.first + end + + def last + to_a.last + end + + def empty? + to_a.empty? + end + + def size + to_a.size + end + alias length size + + def each(&block) + to_a.each(&block) + end + + def map(&block) + to_a.map(&block) + end + + def select(&block) + to_a.select(&block) + end + + # CiteProc name type checking methods + def personal? + # Check if the value is a personal name (has family/given structure) + val = @value + return false if val.nil? + return val.personal? if val.respond_to?(:personal?) + # If it's a hash with family name, it's personal + return true if val.is_a?(Hash) && val.key?('family') + false + end + + def literal? + # Check if the value is a literal name (organization) + val = @value + return false if val.nil? + return val.literal? if val.respond_to?(:literal?) + # If it's a hash with literal key, it's literal + return true if val.is_a?(Hash) && val.key?('literal') + false + end + end +end From 4a89803d5503a60c278252b454fb5ae2fc039986 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 10:16:23 +0200 Subject: [PATCH 06/28] update the patch --- lib/bolognese.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/bolognese.rb b/lib/bolognese.rb index 0a697b63..32dee151 100644 --- a/lib/bolognese.rb +++ b/lib/bolognese.rb @@ -16,6 +16,7 @@ require 'csl/styles' require 'edtf' +require "bolognese/citeproc_extensions" require "bolognese/version" require "bolognese/metadata" require "bolognese/cli" From aa154546e715de126a3b26268818821be3aaaea8 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 10:37:50 +0200 Subject: [PATCH 07/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 91 +++++----------------------- 1 file changed, 16 insertions(+), 75 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 9ce37c25..19c21d97 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true -# Minimal patch for csl-ruby compatibility +# Minimal patch for csl-ruby and citeproc-ruby compatibility module CiteProc class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 + # This ensures truncate returns an array of Name objects, not strings def take(n) val = @value array = case val @@ -12,81 +13,21 @@ def take(n) when nil then [] else [val] end - array.take(n) - end - end -end -# frozen_string_literal: true - -# Ruby 4.0 compatibility patch for citeproc-ruby -module CiteProc - class Variable - # Add to_a method to convert Variable to array when needed - def to_a - val = @value - case val - when Array - val - when nil - [] - else - [val] + + result = array.take(n) + + # Ensure all items are Name objects to fix: undefined method 'personal?' for String + # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L231 + result.map do |item| + if item.respond_to?(:personal?) && item.respond_to?(:literal?) + item + elsif item.is_a?(String) + CiteProc::Name.new(literal: item) + else + item + end end end - - # Delegate Enumerable methods that may not be properly forwarded in Ruby 4 - def take(n) - to_a.take(n) - end - - def first - to_a.first - end - - def last - to_a.last - end - - def empty? - to_a.empty? - end - - def size - to_a.size - end - alias length size - - def each(&block) - to_a.each(&block) - end - - def map(&block) - to_a.map(&block) - end - - def select(&block) - to_a.select(&block) - end - - # CiteProc name type checking methods - def personal? - # Check if the value is a personal name (has family/given structure) - val = @value - return false if val.nil? - return val.personal? if val.respond_to?(:personal?) - # If it's a hash with family name, it's personal - return true if val.is_a?(Hash) && val.key?('family') - false - end - - def literal? - # Check if the value is a literal name (organization) - val = @value - return false if val.nil? - return val.literal? if val.respond_to?(:literal?) - # If it's a hash with literal key, it's literal - return true if val.is_a?(Hash) && val.key?('literal') - false - end end end + From e509b7c489d0226c7f97a9fb400cddfb3c9a5959 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 10:45:05 +0200 Subject: [PATCH 08/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 19c21d97..9290dac1 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -5,7 +5,6 @@ module CiteProc class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 - # This ensures truncate returns an array of Name objects, not strings def take(n) val = @value array = case val @@ -13,21 +12,20 @@ def take(n) when nil then [] else [val] end - - result = array.take(n) - - # Ensure all items are Name objects to fix: undefined method 'personal?' for String - # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L231 - result.map do |item| - if item.respond_to?(:personal?) && item.respond_to?(:literal?) - item - elsif item.is_a?(String) - CiteProc::Name.new(literal: item) - else - item - end - end + array.take(n) end end end +# Fix for: undefined method 'personal?' for an instance of String +# https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L231 +class String + def personal? + false + end + + def literal? + true + end +end + From 85c9e64cc1bdbd511862d47d6dfca1f194f8bf18 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 11:00:46 +0200 Subject: [PATCH 09/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 9290dac1..9d408ba3 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -27,5 +27,11 @@ def personal? def literal? true end + + # Fix for: private method 'format' called for an instance of String + # When a String is used as a name, it needs to return itself as formatted output + def format + self + end end From 706289f63df72f4f9f7b9a98ec55ca433432327b Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:06:31 +0200 Subject: [PATCH 10/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 9d408ba3..5e0f255b 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -14,6 +14,30 @@ def take(n) end array.take(n) end + + # Fix for: undefined method '[]' for an instance of CiteProc::Variable + # Used in citeproc-ruby when accessing names[-1] or names[0...-1] + # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 + def [](index) + val = @value + array = case val + when Array then val + when nil then [] + else [val] + end + array[index] + end + + # Fix for: undefined method 'length' for an instance of CiteProc::Variable + # Used to check array size in citeproc-ruby + def length + val = @value + case val + when Array then val.length + when nil then 0 + else 1 + end + end end end From 26b91ee2f159a0ae1524d66f099d5810d52a3af2 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:13:42 +0200 Subject: [PATCH 11/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 5e0f255b..ec6de498 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -38,6 +38,18 @@ def length else 1 end end + + # Fix for: undefined method 'map' for an instance of CiteProc::Variable + # Used in citeproc-ruby when iterating over names + def map(&block) + val = @value + array = case val + when Array then val + when nil then [] + else [val] + end + array.map(&block) + end end end From d0582938ecc564fe686332193f23a41fda6aa54e Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:31:13 +0200 Subject: [PATCH 12/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 42 +++++++++++++++++++--------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index ec6de498..d63f4d34 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -6,6 +6,10 @@ class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 def take(n) + # If @value already responds to take (like CiteProc::Names), delegate to it + return @value.take(n) if @value.respond_to?(:take) + + # Otherwise treat as array-like val = @value array = case val when Array then val @@ -19,29 +23,41 @@ def take(n) # Used in citeproc-ruby when accessing names[-1] or names[0...-1] # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 def [](index) - val = @value - array = case val - when Array then val - when nil then [] - else [val] - end - array[index] + # If @value already responds to [], delegate to it + return @value[index] if @value.respond_to?(:[]) + + # Otherwise treat as array-like + val = @value + array = case val + when Array then val + when nil then [] + else [val] + end + array[index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable # Used to check array size in citeproc-ruby def length - val = @value - case val - when Array then val.length - when nil then 0 - else 1 - end + # If @value already responds to length, delegate to it + return @value.length if @value.respond_to?(:length) + + # Otherwise treat as array-like + val = @value + case val + when Array then val.length + when nil then 0 + else 1 + end end # Fix for: undefined method 'map' for an instance of CiteProc::Variable # Used in citeproc-ruby when iterating over names def map(&block) + # If @value already responds to map, delegate to it + return @value.map(&block) if @value.respond_to?(:map) + + # Otherwise treat as array-like val = @value array = case val when Array then val From fdda72c81818a29ecff63c84000f97e8bbfb48ea Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:39:13 +0200 Subject: [PATCH 13/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 53 ++++++++-------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index d63f4d34..97cf4caf 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -1,70 +1,47 @@ # frozen_string_literal: true -# Minimal patch for csl-ruby and citeproc-ruby compatibility +# Minimal patch for csl-ruby and citeproc-ruby compatibility module CiteProc class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 def take(n) - # If @value already responds to take (like CiteProc::Names), delegate to it - return @value.take(n) if @value.respond_to?(:take) + # If @value is Enumerable (like CiteProc::Names), use it directly + return @value.take(n) if @value.is_a?(Enumerable) - # Otherwise treat as array-like - val = @value - array = case val - when Array then val - when nil then [] - else [val] - end - array.take(n) + # Otherwise, @value should be a String; delegate to it via to_s + to_s.chars.take(n).join end # Fix for: undefined method '[]' for an instance of CiteProc::Variable # Used in citeproc-ruby when accessing names[-1] or names[0...-1] # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 def [](index) - # If @value already responds to [], delegate to it + # If @value responds to [] (like CiteProc::Names or Array), use it return @value[index] if @value.respond_to?(:[]) - # Otherwise treat as array-like - val = @value - array = case val - when Array then val - when nil then [] - else [val] - end - array[index] + # Otherwise treat as string + to_s[index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable # Used to check array size in citeproc-ruby def length - # If @value already responds to length, delegate to it + # If @value responds to length (like CiteProc::Names or Array), use it return @value.length if @value.respond_to?(:length) - # Otherwise treat as array-like - val = @value - case val - when Array then val.length - when nil then 0 - else 1 - end + # Otherwise return string length + to_s.length end # Fix for: undefined method 'map' for an instance of CiteProc::Variable # Used in citeproc-ruby when iterating over names def map(&block) - # If @value already responds to map, delegate to it - return @value.map(&block) if @value.respond_to?(:map) + # If @value is Enumerable (like CiteProc::Names), use it + return @value.map(&block) if @value.is_a?(Enumerable) - # Otherwise treat as array-like - val = @value - array = case val - when Array then val - when nil then [] - else [val] - end - array.map(&block) + # Otherwise treat as string and map over characters + to_s.chars.map(&block) end end end From f49c94027be76ba8561e2b7ca3a9d69ba0f31d3e Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:50:21 +0200 Subject: [PATCH 14/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 97cf4caf..77d3aae8 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -9,8 +9,8 @@ def take(n) # If @value is Enumerable (like CiteProc::Names), use it directly return @value.take(n) if @value.is_a?(Enumerable) - # Otherwise, @value should be a String; delegate to it via to_s - to_s.chars.take(n).join + # Otherwise wrap in array and take from that + [@value].take(n) end # Fix for: undefined method '[]' for an instance of CiteProc::Variable @@ -20,8 +20,8 @@ def [](index) # If @value responds to [] (like CiteProc::Names or Array), use it return @value[index] if @value.respond_to?(:[]) - # Otherwise treat as string - to_s[index] + # Otherwise wrap in array + [@value][index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable @@ -30,8 +30,8 @@ def length # If @value responds to length (like CiteProc::Names or Array), use it return @value.length if @value.respond_to?(:length) - # Otherwise return string length - to_s.length + # Otherwise return 1 (single element) + 1 end # Fix for: undefined method 'map' for an instance of CiteProc::Variable @@ -40,8 +40,8 @@ def map(&block) # If @value is Enumerable (like CiteProc::Names), use it return @value.map(&block) if @value.is_a?(Enumerable) - # Otherwise treat as string and map over characters - to_s.chars.map(&block) + # Otherwise wrap in array and map over that + [@value].map(&block) end end end From 30eb553d4f65556d65550cbb44ec50d47a7f0e97 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 12:59:35 +0200 Subject: [PATCH 15/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 77d3aae8..143dd14b 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -6,42 +6,30 @@ class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 def take(n) - # If @value is Enumerable (like CiteProc::Names), use it directly - return @value.take(n) if @value.is_a?(Enumerable) - - # Otherwise wrap in array and take from that - [@value].take(n) + # Delegate directly to @value (which is typically a CiteProc::Names or Array) + @value.take(n) end # Fix for: undefined method '[]' for an instance of CiteProc::Variable # Used in citeproc-ruby when accessing names[-1] or names[0...-1] # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 def [](index) - # If @value responds to [] (like CiteProc::Names or Array), use it - return @value[index] if @value.respond_to?(:[]) - - # Otherwise wrap in array - [@value][index] + # Delegate directly to @value + @value[index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable # Used to check array size in citeproc-ruby def length - # If @value responds to length (like CiteProc::Names or Array), use it - return @value.length if @value.respond_to?(:length) - - # Otherwise return 1 (single element) - 1 + # Delegate directly to @value + @value.length end # Fix for: undefined method 'map' for an instance of CiteProc::Variable # Used in citeproc-ruby when iterating over names def map(&block) - # If @value is Enumerable (like CiteProc::Names), use it - return @value.map(&block) if @value.is_a?(Enumerable) - - # Otherwise wrap in array and map over that - [@value].map(&block) + # Delegate directly to @value + @value.map(&block) end end end From 372bb15368ee4d22c5442f3fb48dc5f79abf8714 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 13:07:07 +0200 Subject: [PATCH 16/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 143dd14b..b0e22a19 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -6,30 +6,42 @@ class Variable # Fix for: undefined method 'take' for an instance of CiteProc::Variable # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 def take(n) - # Delegate directly to @value (which is typically a CiteProc::Names or Array) - @value.take(n) + # If @value has the take method (like CiteProc::Names), delegate to it + return @value.take(n) if @value.respond_to?(:take) + + # Otherwise @value is likely a String; treat as single element + [to_s].take(n) end # Fix for: undefined method '[]' for an instance of CiteProc::Variable # Used in citeproc-ruby when accessing names[-1] or names[0...-1] # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 def [](index) - # Delegate directly to @value - @value[index] + # If @value has the [] method (like CiteProc::Names), delegate to it + return @value[index] if @value.respond_to?(:[]) && !@value.is_a?(String) + + # Otherwise treat as single element array + [to_s][index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable # Used to check array size in citeproc-ruby def length - # Delegate directly to @value - @value.length + # If @value is a CiteProc::Names or similar array-like object, use its length + return @value.length if @value.respond_to?(:length) && !@value.is_a?(String) + + # Otherwise return 1 (single element) + 1 end # Fix for: undefined method 'map' for an instance of CiteProc::Variable # Used in citeproc-ruby when iterating over names def map(&block) - # Delegate directly to @value - @value.map(&block) + # If @value has the map method (like CiteProc::Names), delegate to it + return @value.map(&block) if @value.respond_to?(:map) && !@value.is_a?(String) + + # Otherwise treat as single element array + [to_s].map(&block) end end end From 90a2f3ba85454e750c7805d987bd3af0d8e5c181 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Fri, 24 Apr 2026 13:13:13 +0200 Subject: [PATCH 17/28] update the extension --- lib/bolognese/citeproc_extensions.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index b0e22a19..2050d35a 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -9,25 +9,25 @@ def take(n) # If @value has the take method (like CiteProc::Names), delegate to it return @value.take(n) if @value.respond_to?(:take) - # Otherwise @value is likely a String; treat as single element - [to_s].take(n) + # Otherwise @value is likely a String; wrap the value itself, not its string representation + [@value].take(n) end # Fix for: undefined method '[]' for an instance of CiteProc::Variable # Used in citeproc-ruby when accessing names[-1] or names[0...-1] # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 def [](index) - # If @value has the [] method (like CiteProc::Names), delegate to it + # If @value has the [] method and is not a String, delegate to it return @value[index] if @value.respond_to?(:[]) && !@value.is_a?(String) - # Otherwise treat as single element array - [to_s][index] + # Otherwise wrap the value itself + [@value][index] end # Fix for: undefined method 'length' for an instance of CiteProc::Variable # Used to check array size in citeproc-ruby def length - # If @value is a CiteProc::Names or similar array-like object, use its length + # If @value is not a String and has length, use it return @value.length if @value.respond_to?(:length) && !@value.is_a?(String) # Otherwise return 1 (single element) @@ -37,11 +37,11 @@ def length # Fix for: undefined method 'map' for an instance of CiteProc::Variable # Used in citeproc-ruby when iterating over names def map(&block) - # If @value has the map method (like CiteProc::Names), delegate to it + # If @value has the map method and is not a String, delegate to it return @value.map(&block) if @value.respond_to?(:map) && !@value.is_a?(String) - # Otherwise treat as single element array - [to_s].map(&block) + # Otherwise wrap the value itself + [@value].map(&block) end end end From f77ecf97f599d5199d7dfd884b3c5215f1ac1466 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 14:01:23 +0200 Subject: [PATCH 18/28] test removal of contributor --- lib/bolognese.rb | 2 +- lib/bolognese/metadata_utils.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bolognese.rb b/lib/bolognese.rb index 32dee151..9325021b 100644 --- a/lib/bolognese.rb +++ b/lib/bolognese.rb @@ -16,7 +16,7 @@ require 'csl/styles' require 'edtf' -require "bolognese/citeproc_extensions" +# require "bolognese/citeproc_extensions" require "bolognese/version" require "bolognese/metadata" require "bolognese/cli" diff --git a/lib/bolognese/metadata_utils.rb b/lib/bolognese/metadata_utils.rb index 718aa20d..13798742 100644 --- a/lib/bolognese/metadata_utils.rb +++ b/lib/bolognese/metadata_utils.rb @@ -151,7 +151,7 @@ def citeproc_hsh "categories" => Array.wrap(subjects).map { |k| parse_attributes(k, content: "subject", first: true) }.presence, "language" => language, "author" => author, - "contributor" => to_citeproc(contributors), + # "contributor" => to_citeproc(contributors), "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), From 141e7290d84639bbf8cc46723c18d1a2d0b26956 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 14:09:38 +0200 Subject: [PATCH 19/28] revert: test removal of contributor --- lib/bolognese/metadata_utils.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bolognese/metadata_utils.rb b/lib/bolognese/metadata_utils.rb index 13798742..718aa20d 100644 --- a/lib/bolognese/metadata_utils.rb +++ b/lib/bolognese/metadata_utils.rb @@ -151,7 +151,7 @@ def citeproc_hsh "categories" => Array.wrap(subjects).map { |k| parse_attributes(k, content: "subject", first: true) }.presence, "language" => language, "author" => author, - # "contributor" => to_citeproc(contributors), + "contributor" => to_citeproc(contributors), "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), From a9059447cb61563392989704063e68120dc254c3 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 14:17:05 +0200 Subject: [PATCH 20/28] monkey patch citeproc variables to include contributor and accepted-date --- lib/bolognese.rb | 2 +- lib/bolognese/citeproc_extensions.rb | 71 +++++----------------------- 2 files changed, 14 insertions(+), 59 deletions(-) diff --git a/lib/bolognese.rb b/lib/bolognese.rb index 9325021b..32dee151 100644 --- a/lib/bolognese.rb +++ b/lib/bolognese.rb @@ -16,7 +16,7 @@ require 'csl/styles' require 'edtf' -# require "bolognese/citeproc_extensions" +require "bolognese/citeproc_extensions" require "bolognese/version" require "bolognese/metadata" require "bolognese/cli" diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 2050d35a..7f6bf516 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -1,66 +1,21 @@ # frozen_string_literal: true -# Minimal patch for csl-ruby and citeproc-ruby compatibility +# 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 - # Fix for: undefined method 'take' for an instance of CiteProc::Variable - # https://github.com/inukshuk/csl-ruby/blob/b2131c0ce832f332c3db3c49fd2baf7e41ac0aa6/lib/csl/style/names.rb#L98 - def take(n) - # If @value has the take method (like CiteProc::Names), delegate to it - return @value.take(n) if @value.respond_to?(:take) - - # Otherwise @value is likely a String; wrap the value itself, not its string representation - [@value].take(n) - end - - # Fix for: undefined method '[]' for an instance of CiteProc::Variable - # Used in citeproc-ruby when accessing names[-1] or names[0...-1] - # https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L198 - def [](index) - # If @value has the [] method and is not a String, delegate to it - return @value[index] if @value.respond_to?(:[]) && !@value.is_a?(String) + # Add 'contributor' to the list of name variables + # Add 'accepted-date' to the list of date variables + if @fields[:names] + @fields[:names] << :contributor unless @fields[:names].include?(:contributor) + @fields[:date] << :'accepted-date' unless @fields[:date].include?(:'accepted-date') - # Otherwise wrap the value itself - [@value][index] - end - - # Fix for: undefined method 'length' for an instance of CiteProc::Variable - # Used to check array size in citeproc-ruby - def length - # If @value is not a String and has length, use it - return @value.length if @value.respond_to?(:length) && !@value.is_a?(String) - - # Otherwise return 1 (single element) - 1 - end - - # Fix for: undefined method 'map' for an instance of CiteProc::Variable - # Used in citeproc-ruby when iterating over names - def map(&block) - # If @value has the map method and is not a String, delegate to it - return @value.map(&block) if @value.respond_to?(:map) && !@value.is_a?(String) - - # Otherwise wrap the value itself - [@value].map(&block) + # Rebuild the types mapping to include the new fields + @types = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge( + Hash[*@fields.keys.map { |k| @fields[k].map { |n| [n,k] } }.flatten] + ).freeze end end end - -# Fix for: undefined method 'personal?' for an instance of String -# https://github.com/inukshuk/citeproc-ruby/blob/2d6313cbb58d884dbfbccfb6f4a169d8d7c1b6fa/lib/citeproc/ruby/renderer/names.rb#L231 -class String - def personal? - false - end - - def literal? - true - end - - # Fix for: private method 'format' called for an instance of String - # When a String is used as a name, it needs to return itself as formatted output - def format - self - end -end - From dbe97e6f56939f0442bb2f7fbd6fb6a7da1f8ce3 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 14:28:16 +0200 Subject: [PATCH 21/28] monkey patch citeproc variables to include contributor and accepted-date --- lib/bolognese/citeproc_extensions.rb | 37 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index 7f6bf516..e95c749f 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -6,16 +6,35 @@ module CiteProc class Variable - # Add 'contributor' to the list of name variables - # Add 'accepted-date' to the list of date variables - if @fields[:names] - @fields[:names] << :contributor unless @fields[:names].include?(:contributor) - @fields[:date] << :'accepted-date' unless @fields[:date].include?(:'accepted-date') + # Unfreeze, modify, and refreeze the fields to add 'contributor' and 'accepted-date' + if @fields + # Unfreeze the fields hash temporarily + fields_dup = @fields.dup - # Rebuild the types mapping to include the new fields - @types = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge( - Hash[*@fields.keys.map { |k| @fields[k].map { |n| [n,k] } }.flatten] - ).freeze + # 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 + types_hash = Hash[*fields_dup.keys.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 + + # 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 From fb0ade9c3738ff08c5750ae79b3b18afe49c8fb3 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 20:06:42 +0200 Subject: [PATCH 22/28] rebuild factories --- lib/bolognese/citeproc_extensions.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index e95c749f..f463b79f 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -24,6 +24,14 @@ class Variable @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] From 05660c53735512ac97127b0b3ef855abb909b15c Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 20:13:02 +0200 Subject: [PATCH 23/28] rebuild factories --- lib/bolognese/citeproc_extensions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bolognese/citeproc_extensions.rb b/lib/bolognese/citeproc_extensions.rb index f463b79f..f75d49cc 100644 --- a/lib/bolognese/citeproc_extensions.rb +++ b/lib/bolognese/citeproc_extensions.rb @@ -17,8 +17,8 @@ class Variable # Add accepted-date to dates (make a new unfrozen array) fields_dup[:date] = (@fields[:date] + [:'accepted-date']).uniq - # Rebuild the types mapping - types_hash = Hash[*fields_dup.keys.map { |k| fields_dup[k].map { |n| [n, k] } }.flatten] + # 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 From 055c24c58a9119c429a45ccc89d2ae5a7600f439 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Mon, 27 Apr 2026 20:52:57 +0200 Subject: [PATCH 24/28] remove duplicate contributor display --- lib/bolognese/metadata_utils.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/bolognese/metadata_utils.rb b/lib/bolognese/metadata_utils.rb index 718aa20d..00a9bfcb 100644 --- a/lib/bolognese/metadata_utils.rb +++ b/lib/bolognese/metadata_utils.rb @@ -145,13 +145,22 @@ def citeproc_hsh 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), From 32e6ba02c248b321b7d396c48d5f1f3c934d58a7 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:34:17 +0200 Subject: [PATCH 25/28] Update citeproc type mapping for resourceTypeGeneral Software with new CSL style support for software --- lib/bolognese/metadata_utils.rb | 4 ++-- spec/writers/citation_writer_spec.rb | 2 +- spec/writers/citeproc_writer_spec.rb | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/bolognese/metadata_utils.rb b/lib/bolognese/metadata_utils.rb index 00a9bfcb..7b2a2add 100644 --- a/lib/bolognese/metadata_utils.rb +++ b/lib/bolognese/metadata_utils.rb @@ -139,8 +139,8 @@ 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 diff --git a/spec/writers/citation_writer_spec.rb b/spec/writers/citation_writer_spec.rb index 4195d0d5..7e5268ff 100644 --- a/spec/writers/citation_writer_spec.rb +++ b/spec/writers/citation_writer_spec.rb @@ -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). lenses-lab/LYAO_RT-2018JA026426: Original Release (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). lenses-lab/LYAO_RT-2018JA026426: Original Release (Version 1.0.0) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.2598836") end it "interactive resource without dates" do diff --git a/spec/writers/citeproc_writer_spec.rb b/spec/writers/citeproc_writer_spec.rb index 81ef13bf..562bec6f 100644 --- a/spec/writers/citeproc_writer_spec.rb +++ b/spec/writers/citeproc_writer_spec.rb @@ -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") @@ -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") @@ -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") @@ -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") From 8ec4589740de2e25f61ccafaad1159c6f3f7b631 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:18:06 +0200 Subject: [PATCH 26/28] Add test for citeproc bug --- ...ml_csl_with_contributors_and_available.xml | 58 +++++++++++++++++++ spec/writers/citation_writer_spec.rb | 6 ++ 2 files changed, 64 insertions(+) create mode 100644 spec/fixtures/datacite_xml_csl_with_contributors_and_available.xml diff --git a/spec/fixtures/datacite_xml_csl_with_contributors_and_available.xml b/spec/fixtures/datacite_xml_csl_with_contributors_and_available.xml new file mode 100644 index 00000000..02a862fb --- /dev/null +++ b/spec/fixtures/datacite_xml_csl_with_contributors_and_available.xml @@ -0,0 +1,58 @@ + + + 10.81360/BIFURCATED + + + Toon, Geoffrey C. + Jet Propulsion Laboratory, California Institute of Technology, Pasadena, CA, USA + + + Wunch, Debra + 0000-0002-4924-0377 + California Institute of Technology, Pasadena, CA, U.S.A. + + + + A stand-alone a priori profile generation tool for GGG2014 release + + CaltechDATA + 2015 + + TCCON + + + + Toon, Geoffrey C. + Jet Propulsion Laboratory, California Institute of Technology, Pasadena, CA, USA + + + Wunch, Debra + California Institute of Technology, Pasadena, CA, USA + + + TCCON + + + + 2017-07-24 + 2015-10-14 + + eng + + + 250 + 250 + + + 10.14291/tccon.ggg2014.documentation.R0/1221662 + https://tccon-wiki.caltech.edu/ + + GGG2014.R0 + + TCCON Data Use Policy + + + 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. + <br>Cite this record as:<br>Toon, G. C., &amp; Wunch, D. (2017). A stand-alone a priori profile generation tool for GGG2014 release. CaltechDATA. <a href="https://doi.org/10.14291/tccon.ggg2014.priors.r0/1221661">https://doi.org/10.14291/tccon.ggg2014.priors.r0/1221661</a><br> or choose a <a href="https://crosscite.org/?doi=10.14291/TCCON.GGG2014.PRIORS.R0/1221661"> different citation style.</a><br><a href="https://data.datacite.org/application/x-bibtex/10.14291/TCCON.GGG2014.PRIORS.R0/1221661">Download Citation</a><br> + + \ No newline at end of file diff --git a/spec/writers/citation_writer_spec.rb b/spec/writers/citation_writer_spec.rb index 7e5268ff..2190176b 100644 --- a/spec/writers/citation_writer_spec.rb +++ b/spec/writers/citation_writer_spec.rb @@ -112,5 +112,11 @@ expect(subject.locale).to eq("en-US") expect(subject.citation).to eq("M. Fenner, “Eating your own Dog Food,” Understanding the fictional John Smith, 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("Fenner, M. (2016). Eating your own Dog Food. DataCite. https://doi.org/10.5438/4k3m-nyvg") + end end end From 8d94a1401195ff6bfe4f25e2ddc498e957b30836 Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Tue, 28 Apr 2026 11:30:52 +0200 Subject: [PATCH 27/28] update spec expectation --- spec/writers/citation_writer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/writers/citation_writer_spec.rb b/spec/writers/citation_writer_spec.rb index 2190176b..b521436d 100644 --- a/spec/writers/citation_writer_spec.rb +++ b/spec/writers/citation_writer_spec.rb @@ -116,7 +116,7 @@ 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("Fenner, M. (2016). Eating your own Dog Food. DataCite. https://doi.org/10.5438/4k3m-nyvg") + expect(subject.citation).to eq("Toon, G. C., & Wunch, D. (2015). A stand-alone a priori profile generation tool for GGG2014 release (Version GGG2014.R0) [Computer software]. CaltechDATA. https://doi.org/10.81360/bifurcated") end end end From 92fbbc753a65172d7436e6dfa501ab7d63710f1d Mon Sep 17 00:00:00 2001 From: kudakwashe SIziva Date: Tue, 28 Apr 2026 12:00:54 +0200 Subject: [PATCH 28/28] fix formatting --- spec/writers/citation_writer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/writers/citation_writer_spec.rb b/spec/writers/citation_writer_spec.rb index b521436d..9206cd12 100644 --- a/spec/writers/citation_writer_spec.rb +++ b/spec/writers/citation_writer_spec.rb @@ -117,6 +117,6 @@ 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., & Wunch, D. (2015). A stand-alone a priori profile generation tool for GGG2014 release (Version GGG2014.R0) [Computer software]. CaltechDATA. https://doi.org/10.81360/bifurcated") - end + end end end