Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 cff.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 2.6'

spec.add_runtime_dependency 'citeproc-ruby', '~> 1.1', '>= 1.1.14'
spec.add_runtime_dependency 'json_schema', '~> 0.21.0'
spec.add_runtime_dependency 'language_list', '~> 1.2'

Expand Down
42 changes: 42 additions & 0 deletions lib/array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

##
class Array

# Implementing the ActiveRecord method Array.wrap
# Wraps its argument in an array unless it is already an array (or array-like).
#
# Specifically:
#
# * If the argument is +nil+ an empty array is returned.
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
# * Otherwise, returns an array with the argument as its single element.
#
# Array.wrap(nil) # => []
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
# Array.wrap(0) # => [0]

def self.wrap(object)
if object.nil?
[]
elsif object.respond_to?(:to_ary)
object.to_ary || [object]
else
[object]
end
end
end
4 changes: 4 additions & 0 deletions lib/cff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module CFF
SCHEMA = JsonSchema.parse!(SCHEMA_FILE) # :nodoc:
end

require 'array'
require 'cff/version'
require 'cff/errors'
require 'cff/util'
Expand All @@ -47,3 +48,6 @@ module CFF
require 'cff/formatter/formatter'
require 'cff/formatter/apa_formatter'
require 'cff/formatter/bibtex_formatter'
require 'cff/formatter/csl_formatter'
require 'citeproc'
require 'csl'
94 changes: 94 additions & 0 deletions lib/cff/formatter/csl_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

##
module CFF
# initial set of preferred citation styles, based on the list used by
# Crossref and DataCite Search:

# apa
# chicago-fullnote-bibliography
# harvard-cite-them-right
# ieee
# university-of-york-mla
# vancouver

# Generates a formatted citation using citation style language (CSL)
# and the Ruby Citeproc processor
class CslFormatter < Formatter # :nodoc:

def self.format(model:, style: 'apa', locale: 'en-US') # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
# only support built-in styles
return nil unless ['apa', 'harvard-cite-them-right', 'ieee'].include? style

return nil unless required_fields?(model)

CSL::Style.root = ::File.expand_path('../../../lib/styles', __dir__)
CSL::Locale.root = ::File.expand_path('../../../lib/locales', __dir__)

id = present?(model.doi) ? "https://doi.org/#{model.doi}" : nil

# citeproc_hsh is input format for citeproc-ruby
citeproc_hsh = {
# using type book is workaround for software for current CSL version
'type' => 'book',
'id' => present?(model.doi) ? "https://doi.org/#{model.doi}" : nil,
'categories' => Array.wrap(model.keywords),
'language' => 'eng', # Array.wrap(model.languages).first,
'author' => to_citeproc(model.authors),
'issued' => get_date_parts(model.date_released.to_s),
'abstract' => model.abstract,
# 'container-title' => container_title,
'DOI' => model.doi,
# 'publisher' => publisher,
'title' => model.title,
'URL' => present?(model.repository_code) ? model.repository_code : model.url,
# 'copyright' => model.copyright,
'version' => model.version
}.compact.symbolize_keys

cp = CiteProc::Processor.new style: style, locale: locale, format: 'html'
cp.import Array.wrap(citeproc_hsh)
bibliography = cp.render :bibliography, id: id
bibliography.first
end

# change authors into a format citeproc understands
def self.to_citeproc(element)
Array.wrap(element).map do |a|
{
'given' => a.fields['given-names'],
'non-dropping-particle' => a.fields['name-particle'],
'family' => a.fields['family-names'],
'suffix' => a.fields['name-suffix'],
'literal' => a.fields['name']
}.compact
end
end

# citeproc uses dates formatted as date parts
def self.get_date_parts(iso8601_time)
return { 'date-parts' => [[]] } unless present?(iso8601_time)

year = iso8601_time[0..3].to_i
month = iso8601_time[5..6].to_i
day = iso8601_time[8..9].to_i
{ 'date-parts' => [[year, month, day].reject(&:zero?)] }
rescue TypeError, NoMethodError
nil
end
end
end
24 changes: 24 additions & 0 deletions lib/cff/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ def to_apalike
CFF::ApaFormatter.format(model: self)
end

# :call-seq:
# to_apa -> String
#
# Output this Model in APA format, using CSL.
def to_apa
CFF::CslFormatter.format(model: self, style: 'apa')
end

# :call-seq:
# to_harvard -> String
#
# Output this Model in Harvard format, using CSL.
def to_harvard
CFF::CslFormatter.format(model: self, style: 'harvard-cite-them-right')
end

# :call-seq:
# to_ieee -> String
#
# Output this Model in APA format, using CSL.
def to_ieee
CFF::CslFormatter.format(model: self, style: 'ieee')
end

# :call-seq:
# to_bibtex -> String
#
Expand Down
Loading