Skip to content

Commit

Permalink
Use citeproc to create citations
Browse files Browse the repository at this point in the history
  • Loading branch information
Genia Kazymova committed Jun 20, 2024
1 parent 144e7d5 commit 283b4a2
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 120 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Metrics/ModuleLength:
- 'lib/trln_argon/view_helpers/trln_argon_helper.rb'
- 'spec/lib/trln_argon/fields_spec.rb'
- 'lib/trln_argon/view_helpers/items_section_helper.rb'
- 'lib/trln_argon/solr_document/citation.rb'

Metrics/PerceivedComplexity:
Exclude:
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.3.2
2.4.0
21 changes: 10 additions & 11 deletions app/components/trln_argon/document/citation_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<% if @document.citable? %>
<div class="modal-header">
<h3 class="modal-title"><%= title %></h3>
</div>
<div class="modal-body">
<% @document.citations.each do |format, citation| %>
<h4><%= t("trln_argon.citation.#{format}") %></h4>
<%= citation %>
<% end %>
</div>
<% end %>
<div class="modal-header">
<h3 class="modal-title"><%= title %></h3>
</div>
<div class="modal-body">
<% @document.citations.each do |format, citation| %>
<h4><%= t("trln_argon.citation.#{format}") %></h4>
<%= citation.html_safe %>
<% end %>
</div>

11 changes: 1 addition & 10 deletions lib/trln_argon/controller_override.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ module ControllerOverride
path: :sms_path,
validator: :validate_sms_params)
config.add_show_tools_partial(:citation,
icon: 'fa fa-quote-left',
if: :render_citation_action?)
icon: 'fa fa-quote-left')
config.add_show_tools_partial(:ris,
icon: 'fa fa-download',
if: :render_ris_action?,
Expand Down Expand Up @@ -684,14 +683,6 @@ def render_sharebookmarks_action?(_config, _options)
true if request.path == bookmarks_path
end

def render_citation_action?
docs = [@document || (@document_list || [])].flatten
TrlnArgon::Engine.configuration.citation_formats.present? &&
TrlnArgon::Engine.configuration.worldcat_cite_base_url.present? &&
TrlnArgon::Engine.configuration.worldcat_cite_api_key.present? &&
docs.select { |doc| doc.oclc_number.present? }.any?
end

def log_params
params.permit(:lines)
end
Expand Down
8 changes: 5 additions & 3 deletions lib/trln_argon/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@ class Configuration
:solr_cache_exp_time,
:allow_open_search,
:open_search_q_min_length,
:worldcat_cite_base_url,
:worldcat_cite_api_key,
:enable_query_truncation,
:allow_tracebacks

# rubocop:disable Metrics/MethodLength
# rubocop:disable Layout/LineLength
def initialize
@local_institution_code = 'unc'
@application_name = 'TRLN Argon'
Expand All @@ -66,7 +65,9 @@ def initialize
'url=http://unc.summon.serialssolutions.com/search?'\
's.secure=f&s.ho=t&s.role=authenticated&s.ps=20&s.q='
@contact_url = 'https://library.unc.edu/ask/'
@citation_formats = 'apa, mla, chicago, harvard, turabian'
# citation formats are coming from the citation-style-language/styles repository on GitHub
# (https://github.com/citation-style-language/styles/tree/b2be5aeeee7f00fd2032ac1daad995bbe95398cf)
@citation_formats = 'apa, modern-language-association, chicago-fullnote-bibliography, harvard-cite-them-right, turabian-fullnote-bibliography'
@feedback_url = ''
@sort_order_in_holding_list = 'unc, duke, ncsu, nccu, trln'
@number_of_location_facets = '10'
Expand All @@ -82,6 +83,7 @@ def initialize
@allow_tracebacks = ''
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Layout/LineLength

private

Expand Down
190 changes: 160 additions & 30 deletions lib/trln_argon/solr_document/citation.rb
Original file line number Diff line number Diff line change
@@ -1,53 +1,183 @@
require 'citeproc'
require 'csl/styles'
require 'bibtex'
require 'citeproc/ruby'
require 'json'

module TrlnArgon
module SolrDocument
module Citation
def citable?
oclc_number.present? && citations.present?
end
MAPPING = {
'id' => 'id',
'title_main' => 'title',
'publication_year_sort' => 'year',
'names_a' => 'author',
'note_general_a' => 'note',
'isbn_number_a' => 'number',
'physical_description_a' => 'pages',
'publisher_a' => 'publisher',
'resource_type_a' => 'type',
'edition_a' => 'edition',
'publisher_location_a' => 'address',
'language_a' => 'language',
'issn_primary_a' => 'issn',
'url_a' => 'url'
}.freeze

def citations
@all_citations ||= begin
citation_hash = {}
desired_formats.each do |format|
citation = world_cat_api_response(format).html_safe
if citation != 'info:srw/diagnostic/1/65Record does not exist'
citation_hash[format] = citation
end
@all_citations ||= generate_citations
end

def generate_citations
citation_hash = {}
result = map_document_values
bibtex_string = convert_to_bibtex_format(result)
bibliography = BibTeX.parse(bibtex_string)
process_citations(bibliography, citation_hash)
citation_hash
end

private

def map_document_values
MAPPING.each_with_object([]) do |(key, value), output|
docvalue = fetch(key, [])
next if docvalue.empty?

case key
when 'url_a'
process_url(docvalue, value, output)
when 'names_a'
process_names(docvalue, output)
else
process_docvalue(output, value, docvalue)
end
citation_hash
end
end

private
def process_url(docvalue, value, output)
processed_value = parse_url(docvalue)
process_docvalue(output, value, processed_value)
end

def world_cat_api_response(format)
url = world_cat_uri(format)
def process_names(docvalue, output)
authors, editors = parse_authors_and_editors(docvalue)
process_docvalue(output, 'author', authors) unless authors.empty?
process_docvalue(output, 'editor', editors) unless editors.empty?
end

Net::HTTP.start(url.host, url.port) do |http|
request = Net::HTTP::Get.new url
response = http.request request
response.body
def parse_url(docvalue)
JSON.parse(docvalue.first)['href']
end

def parse_authors_and_editors(docvalue)
authors = []
editors = []
docvalue.each do |doc|
parsed_doc = JSON.parse(doc)
if parsed_doc['type'] != 'editor' && parsed_doc['rel'] != 'illustrator'
authors << parsed_doc['name']
elsif parsed_doc['type'] == 'editor'
editors << parsed_doc['name']
end
end
rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
Rails.logger.error { "#{e.message} #{e.backtrace.join("\n")}" }
'{}'
[authors.join(' and '), editors.join(' and ')]
end

def desired_formats
TrlnArgon::Engine.configuration.citation_formats.split(', ')
def convert_to_bibtex_format(input)
identifier = input.detect { |key, _| key == 'id' }[1]
entry_type = input.detect { |key, _| key == 'type' }[1].split(',').first.strip.downcase
entry_type = map_entry_type(entry_type)
# The bibtex string should look like this
# "@book{id, author = {Author, A.}, title = {Title}, journal = {Journal}, year = {2020}}"
formatted_pairs = input.reject { |key, _| ['id', 'type'].include?(key) }.map do |key, value|
"#{key} = {#{value}}"
end
"@#{entry_type}{#{identifier}, #{formatted_pairs.join(', ')}}"
end

def process_citations(bibliography, citation_hash)
desired_formats.each do |format|
style = CSL::Style.load(format)
processor = CiteProc::Processor.new(style: style, format: 'html')
processor.import(bibliography.to_citeproc)
citation = processor.render(:bibliography, id: bibliography.first.id).first
citation_hash[format_display_name(format)] = citation
end
end

def world_cat_uri(format)
URI([base_url, oclc_number, '?cformat=', format, '&wskey=', api_key].join)
def format_display_name(format)
case format
when 'apa'
'apa'
when 'modern-language-association'
'mla'
when 'chicago-fullnote-bibliography'
'chicago'
when 'harvard-cite-them-right'
'harvard'
when 'turabian-fullnote-bibliography'
'turabian'
else
format
end
end

def base_url
TrlnArgon::Engine.configuration.worldcat_cite_base_url
# rubocop:disable CyclomaticComplexity
# rubocop:disable Metrics/MethodLength
def map_entry_type(entry_type)
case entry_type
when 'Archival and manuscript material'
'manuscript'
when 'Audiobook'
'audio'
when 'Book'
'book'
when 'Database'
'database'
when 'Dataset -- Statistical'
'dataset'
when 'Dataset -- Geospatial'
'dataset'
when 'Game'
'game'
when 'Government publication'
'government'
when 'Image'
'image'
when 'Journal, Magazine, or Periodical'
'article-journal'
when 'Kit'
'kit'
when 'Map'
'map'
when 'Music recording'
'music'
when 'Music score'
'music'
when 'Newspaper'
'article-newspaper'
when 'Non-musical sound recording'
'audio'
when 'Object'
'object'
when 'Software/multimedia'
'software'
when 'Thesis/Dissertation'
'thesis'
when 'Video'
'video'
when 'Web page or site'
'webpage'
else
'book'
end
# rubocop:enable CyclomaticComplexity
# rubocop:enable Metrics/MethodLength
end

def api_key
TrlnArgon::Engine.configuration.worldcat_cite_api_key
def desired_formats
TrlnArgon::Engine.configuration.citation_formats.split(', ')
end
end
end
Expand Down
Loading

0 comments on commit 283b4a2

Please sign in to comment.