cff 0.1.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGES.md +234 -0
- data/CITATION.cff +26 -0
- data/Gemfile +3 -1
- data/LICENCE +1 -1
- data/README.md +148 -17
- data/Rakefile +17 -12
- data/bin/console +4 -3
- data/cff.gemspec +43 -21
- data/lib/cff.rb +25 -9
- data/lib/cff/entity.rb +62 -7
- data/lib/cff/errors.rb +45 -0
- data/lib/cff/file.rb +140 -16
- data/lib/cff/formatter/apa_formatter.rb +77 -0
- data/lib/cff/formatter/bibtex_formatter.rb +122 -0
- data/lib/cff/formatter/formatter.rb +63 -0
- data/lib/cff/identifier.rb +71 -0
- data/lib/cff/licensable.rb +46 -0
- data/lib/cff/model.rb +222 -54
- data/lib/cff/model_part.rb +49 -0
- data/lib/cff/person.rb +51 -10
- data/lib/cff/reference.rb +541 -0
- data/lib/cff/util.rb +72 -0
- data/lib/cff/validatable.rb +55 -0
- data/lib/cff/version.rb +7 -4
- data/lib/schema/1.2.0.json +1882 -0
- metadata +127 -29
- data/.gitignore +0 -30
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -19
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
##
|
18
|
+
module CFF
|
19
|
+
# Generates an APALIKE citation string
|
20
|
+
class ApaFormatter < Formatter # :nodoc:
|
21
|
+
|
22
|
+
def self.format(model:, preferred_citation: true) # rubocop:disable Metrics/AbcSize
|
23
|
+
model = select_and_check_model(model, preferred_citation)
|
24
|
+
return if model.nil?
|
25
|
+
|
26
|
+
output = []
|
27
|
+
output << combine_authors(
|
28
|
+
model.authors.map { |author| format_author(author) }
|
29
|
+
)
|
30
|
+
|
31
|
+
_, year = month_and_year_from_model(model)
|
32
|
+
output << "(#{year})" unless year.empty?
|
33
|
+
|
34
|
+
version = " (Version #{model.version})" unless model.version.to_s.empty?
|
35
|
+
output << "#{model.title}#{version}#{software_label(model)}"
|
36
|
+
output << publication_data_from_model(model)
|
37
|
+
output << url(model)
|
38
|
+
|
39
|
+
output.reject(&:empty?).join('. ')
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.publication_data_from_model(model)
|
43
|
+
return '' unless model.respond_to?(:journal)
|
44
|
+
|
45
|
+
vol = "#{model.volume}(#{model.issue})" unless model.volume.to_s.empty?
|
46
|
+
|
47
|
+
[model.journal, vol, model.start.to_s].reject(&:empty?).join(', ')
|
48
|
+
end
|
49
|
+
|
50
|
+
# Prefer a DOI over the other URI options.
|
51
|
+
def self.url(model)
|
52
|
+
model.doi.empty? ? super : "https://doi.org/#{model.doi}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.software_label(model)
|
56
|
+
return '' if model.is_a?(Reference) && !model.type.include?('software')
|
57
|
+
|
58
|
+
' [Computer software]'
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.combine_authors(authors)
|
62
|
+
return authors[0].chomp('.') if authors.length == 1
|
63
|
+
|
64
|
+
"#{authors[0..-2].join(', ')}, & #{authors[-1]}".chomp('.')
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.format_author(author)
|
68
|
+
return author.name if author.is_a?(Entity)
|
69
|
+
|
70
|
+
particle =
|
71
|
+
author.name_particle.empty? ? '' : "#{author.name_particle} "
|
72
|
+
suffix = author.name_suffix.empty? ? '.' : "., #{author.name_suffix}"
|
73
|
+
|
74
|
+
"#{particle}#{author.family_names}, #{initials(author.given_names)}#{suffix}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
##
|
18
|
+
module CFF
|
19
|
+
# Generates an BibTex citation string
|
20
|
+
class BibtexFormatter < Formatter # :nodoc:
|
21
|
+
|
22
|
+
def self.format(model:, preferred_citation: true) # rubocop:disable Metrics/AbcSize
|
23
|
+
model = select_and_check_model(model, preferred_citation)
|
24
|
+
return if model.nil?
|
25
|
+
|
26
|
+
values = {}
|
27
|
+
values['author'] = combine_authors(
|
28
|
+
model.authors.map { |author| format_author(author) }
|
29
|
+
)
|
30
|
+
values['title'] = "{#{model.title}}"
|
31
|
+
|
32
|
+
publication_data_from_model(model, values)
|
33
|
+
|
34
|
+
month, year = month_and_year_from_model(model)
|
35
|
+
values['month'] = month
|
36
|
+
values['year'] = year
|
37
|
+
|
38
|
+
values['url'] = url(model)
|
39
|
+
|
40
|
+
values.reject! { |_, v| v.empty? }
|
41
|
+
sorted_values = values.sort.map do |key, value|
|
42
|
+
"#{key} = {#{value}}"
|
43
|
+
end
|
44
|
+
sorted_values.insert(0, generate_reference(values))
|
45
|
+
|
46
|
+
"@#{bibtex_type(model)}{#{sorted_values.join(",\n")}\n}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get various bits of information about the reference publication.
|
50
|
+
# Reference: https://www.bibtex.com/format/
|
51
|
+
def self.publication_data_from_model(model, fields)
|
52
|
+
%w[doi journal volume].each do |field|
|
53
|
+
fields[field] = model.send(field).to_s if model.respond_to?(field)
|
54
|
+
end
|
55
|
+
|
56
|
+
# BibTeX 'number' is CFF 'issue'.
|
57
|
+
fields['number'] = model.issue.to_s if model.respond_to?(:issue)
|
58
|
+
|
59
|
+
fields['pages'] = pages_from_model(model)
|
60
|
+
end
|
61
|
+
|
62
|
+
# CFF 'pages' is the number of pages, which has no equivalent in BibTeX.
|
63
|
+
# Reference: https://www.bibtex.com/f/pages-field/
|
64
|
+
def self.pages_from_model(model)
|
65
|
+
return '' if !model.respond_to?(:start) || model.start.to_s.empty?
|
66
|
+
|
67
|
+
start = model.start.to_s
|
68
|
+
finish = model.end.to_s
|
69
|
+
if finish.empty?
|
70
|
+
start
|
71
|
+
else
|
72
|
+
start == finish ? start : "#{start}--#{finish}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Do what we can to map between CFF reference types and bibtex types.
|
77
|
+
# Reference: https://www.bibtex.com/e/entry-types/
|
78
|
+
def self.bibtex_type(model)
|
79
|
+
return 'misc' unless model.is_a?(Reference)
|
80
|
+
|
81
|
+
case model.type
|
82
|
+
when 'article', 'book', 'manual', 'unpublished'
|
83
|
+
model.type
|
84
|
+
when 'conference', 'proceedings'
|
85
|
+
'proceedings'
|
86
|
+
when 'conference-paper'
|
87
|
+
'inproceedings'
|
88
|
+
when 'magazine-article', 'newspaper-article'
|
89
|
+
'article'
|
90
|
+
when 'pamphlet'
|
91
|
+
'booklet'
|
92
|
+
else
|
93
|
+
'misc'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.format_author(author)
|
98
|
+
return "{#{author.name}}" if author.is_a?(Entity)
|
99
|
+
|
100
|
+
particle =
|
101
|
+
author.name_particle.empty? ? '' : "#{author.name_particle} "
|
102
|
+
|
103
|
+
[
|
104
|
+
"#{particle}#{author.family_names}",
|
105
|
+
author.name_suffix,
|
106
|
+
author.given_names
|
107
|
+
].reject(&:empty?).join(', ')
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.combine_authors(authors)
|
111
|
+
authors.join(' and ')
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.generate_reference(fields)
|
115
|
+
[
|
116
|
+
fields['author'].split(',', 2)[0].tr(' -', '_'),
|
117
|
+
fields['title'].split[0..2],
|
118
|
+
fields['year']
|
119
|
+
].compact.join('_').tr('-$£%&(){}+!?/\\:;\'"~#', '')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
##
|
18
|
+
module CFF
|
19
|
+
# Formatter base class
|
20
|
+
class Formatter # :nodoc:
|
21
|
+
|
22
|
+
def self.select_and_check_model(model, preferred_citation)
|
23
|
+
if preferred_citation && model.preferred_citation.is_a?(Reference)
|
24
|
+
model = model.preferred_citation
|
25
|
+
end
|
26
|
+
|
27
|
+
# Safe to assume valid `Model`s and `Reference`s will have these fields.
|
28
|
+
model.authors.empty? || model.title.empty? ? nil : model
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.initials(name)
|
32
|
+
name.split.map { |part| part[0].capitalize }.join('. ')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Prefer `repository_code` over `url`
|
36
|
+
def self.url(model)
|
37
|
+
model.repository_code.empty? ? model.url : model.repository_code
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.month_and_year_from_model(model)
|
41
|
+
if model.respond_to?(:year)
|
42
|
+
result = [model.month, model.year].map(&:to_s)
|
43
|
+
|
44
|
+
return result unless result.any?(&:empty?)
|
45
|
+
end
|
46
|
+
|
47
|
+
month_and_year_from_date(model.date_released)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.month_and_year_from_date(value)
|
51
|
+
if value.is_a?(Date)
|
52
|
+
[value.month, value.year].map(&:to_s)
|
53
|
+
else
|
54
|
+
begin
|
55
|
+
date = Date.parse(value.to_s)
|
56
|
+
[date.month, date.year].map(&:to_s)
|
57
|
+
rescue ArgumentError
|
58
|
+
['', '']
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
##
|
18
|
+
module CFF
|
19
|
+
|
20
|
+
# An Identifier represents an identifier in a CITATION.cff file.
|
21
|
+
#
|
22
|
+
# Identifier implements all of the fields listed in the
|
23
|
+
# [CFF standard](https://citation-file-format.github.io/). All fields
|
24
|
+
# are simple strings and can be set as such. A field which has not been set
|
25
|
+
# will return the empty string. The simple fields are (with defaults in
|
26
|
+
# parentheses):
|
27
|
+
#
|
28
|
+
# * `type`
|
29
|
+
# * `value`
|
30
|
+
class Identifier < ModelPart
|
31
|
+
|
32
|
+
ALLOWED_FIELDS = ['type', 'value'].freeze # :nodoc:
|
33
|
+
|
34
|
+
# The [defined set of identifier types](https://github.com/citation-file-format/citation-file-format/blob/main/README.md#identifier-type-strings).
|
35
|
+
IDENTIFIER_TYPES = ['doi', 'url', 'swh', 'other'].freeze
|
36
|
+
|
37
|
+
# :call-seq:
|
38
|
+
# new -> Identifier
|
39
|
+
# new { |id| block } -> Identifier
|
40
|
+
# new(type, value) -> Identifier
|
41
|
+
# new(type, value) { |id| block } -> Identifier
|
42
|
+
#
|
43
|
+
# Create a new Identifier with the optionally supplied type and value.
|
44
|
+
# If the supplied type is invalid, then neither the type or value are set.
|
45
|
+
def initialize(param = nil, *more)
|
46
|
+
if param.is_a?(Hash)
|
47
|
+
@fields = param
|
48
|
+
@fields.default = ''
|
49
|
+
else
|
50
|
+
@fields = Hash.new('')
|
51
|
+
|
52
|
+
unless param.nil?
|
53
|
+
self.type = param
|
54
|
+
@fields['value'] = more[0] unless @fields['type'].empty?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
yield self if block_given?
|
59
|
+
end
|
60
|
+
|
61
|
+
# :call-seq:
|
62
|
+
# type = type
|
63
|
+
#
|
64
|
+
# Sets the type of this Identifier. The type is restricted to a
|
65
|
+
# [defined set of identifier types](https://github.com/citation-file-format/citation-file-format/blob/main/README.md#identifier-type-strings).
|
66
|
+
def type=(type)
|
67
|
+
type = type.downcase
|
68
|
+
@fields['type'] = type if IDENTIFIER_TYPES.include?(type)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
##
|
18
|
+
module CFF
|
19
|
+
|
20
|
+
# Functionality to add licence(s) to parts of the CFF model.
|
21
|
+
module Licensable
|
22
|
+
|
23
|
+
# :nodoc:
|
24
|
+
LICENSES = SCHEMA_FILE['definitions']['license-enum']['enum'].dup.freeze
|
25
|
+
|
26
|
+
# :call-seq:
|
27
|
+
# license = license
|
28
|
+
# license = Array
|
29
|
+
#
|
30
|
+
# Set the license, or licenses, of this work. Only licenses that conform
|
31
|
+
# to the [SPDX License List](https://spdx.org/licenses/) will be accepted.
|
32
|
+
# If you need specify a different license you should set `license-url`
|
33
|
+
# with a link to the license instead.
|
34
|
+
def license=(lic)
|
35
|
+
list = [*lic].select { |l| LICENSES.include?(l) }
|
36
|
+
@fields['license'] = case list.length
|
37
|
+
when 0
|
38
|
+
@fields['license']
|
39
|
+
when 1
|
40
|
+
list[0]
|
41
|
+
else
|
42
|
+
list
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/cff/model.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018-2021 The Ruby Citation File Format Developers.
|
2
4
|
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
@@ -12,33 +14,61 @@
|
|
12
14
|
# See the License for the specific language governing permissions and
|
13
15
|
# limitations under the License.
|
14
16
|
|
15
|
-
|
17
|
+
##
|
16
18
|
module CFF
|
17
19
|
|
18
20
|
# Model is the core data structure for a CITATION.cff file. It can be
|
19
21
|
# accessed direcly, or via File.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
#
|
23
|
+
# Model implements all of the fields listed in the
|
24
|
+
# [CFF standard](https://citation-file-format.github.io/). Complex
|
25
|
+
# fields - `authors`, `contact`, `identifiers`, `keywords`,
|
26
|
+
# `preferred-citation` and `references` - are documented below. All other
|
27
|
+
# fields are simple strings and can be set as such. A field which has not
|
28
|
+
# been set will return the empty string. The simple fields are (with defaults
|
29
|
+
# in parentheses):
|
30
|
+
#
|
31
|
+
# * `abstract`
|
32
|
+
# * `cff_version`
|
33
|
+
# * `commit`
|
34
|
+
# * `date_released` - *Note:* returns a `Date` object
|
35
|
+
# * `doi`
|
36
|
+
# * `license`
|
37
|
+
# * `license_url`
|
38
|
+
# * `message` (If you use this software in your work, please cite it using
|
39
|
+
# the following metadata)
|
40
|
+
# * `repository`
|
41
|
+
# * `repository_artifact`
|
42
|
+
# * `repository_code`
|
43
|
+
# * `title`
|
44
|
+
# * `url`
|
45
|
+
# * `version`
|
46
|
+
class Model < ModelPart
|
47
|
+
|
48
|
+
include Licensable
|
49
|
+
include Validatable
|
50
|
+
|
51
|
+
ALLOWED_FIELDS = [
|
52
|
+
'abstract', 'authors', 'cff-version', 'contact', 'commit',
|
53
|
+
'date-released', 'doi', 'identifiers', 'keywords', 'license',
|
54
|
+
'license-url', 'message', 'preferred-citation', 'references',
|
55
|
+
'repository', 'repository-artifact', 'repository-code', 'title',
|
56
|
+
'url', 'version'
|
57
|
+
].freeze # :nodoc:
|
31
58
|
|
32
59
|
# The default message to use if none is explicitly set.
|
33
|
-
DEFAULT_MESSAGE =
|
60
|
+
DEFAULT_MESSAGE = 'If you use this software in your work, please cite ' \
|
61
|
+
'it using the following metadata'
|
34
62
|
|
35
63
|
# :call-seq:
|
36
64
|
# new(title) -> Model
|
65
|
+
# new(title) { |model| block } -> Model
|
37
66
|
#
|
38
67
|
# Initialize a new Model with the supplied title.
|
39
68
|
def initialize(param)
|
40
|
-
if Hash
|
41
|
-
@fields = param
|
69
|
+
if param.is_a?(Hash)
|
70
|
+
@fields = build_model(param)
|
71
|
+
@fields.default = ''
|
42
72
|
else
|
43
73
|
@fields = Hash.new('')
|
44
74
|
@fields['cff-version'] = DEFAULT_SPEC_VERSION
|
@@ -46,9 +76,91 @@ module CFF
|
|
46
76
|
@fields['title'] = param
|
47
77
|
end
|
48
78
|
|
49
|
-
|
79
|
+
%w[authors contact identifiers keywords references].each do |field|
|
80
|
+
@fields[field] = [] if @fields[field].empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
yield self if block_given?
|
84
|
+
end
|
85
|
+
|
86
|
+
# :call-seq:
|
87
|
+
# date_released = date
|
88
|
+
#
|
89
|
+
# Set the `date-released` field. If a non-Date object is passed in it will
|
90
|
+
# be parsed into a Date.
|
91
|
+
def date_released=(date)
|
92
|
+
date = Date.parse(date) unless date.is_a?(Date)
|
93
|
+
|
94
|
+
@fields['date-released'] = date
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_yaml # :nodoc:
|
98
|
+
YAML.dump fields, line_width: -1, indentation: 2
|
99
|
+
end
|
100
|
+
|
101
|
+
# :call-seq:
|
102
|
+
# to_apalike(preferred_citation: true) -> String
|
103
|
+
#
|
104
|
+
# Output this Model in an APA-like format. Setting
|
105
|
+
# `preferred_citation: true` will honour the `preferred_citation` field in
|
106
|
+
# the model if one is present (default).
|
107
|
+
#
|
108
|
+
# *Note:* This method assumes that this Model is valid when called.
|
109
|
+
def to_apalike(preferred_citation: true)
|
110
|
+
CFF::ApaFormatter.format(
|
111
|
+
model: self, preferred_citation: preferred_citation
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
# :call-seq:
|
116
|
+
# to_bibtex(preferred_citation: true) -> String
|
117
|
+
#
|
118
|
+
# Output this Model in BibTeX format. Setting
|
119
|
+
# `preferred_citation: true` will honour the `preferred_citation` field in
|
120
|
+
# the model if one is present (default).
|
121
|
+
#
|
122
|
+
# *Note:* This method assumes that this Model is valid when called.
|
123
|
+
def to_bibtex(preferred_citation: true)
|
124
|
+
CFF::BibtexFormatter.format(
|
125
|
+
model: self, preferred_citation: preferred_citation
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def fields
|
132
|
+
%w[authors contact identifiers references].each do |field|
|
133
|
+
normalize_modelpart_array!(@fields[field])
|
134
|
+
end
|
135
|
+
|
136
|
+
fields_to_hash(@fields)
|
50
137
|
end
|
51
138
|
|
139
|
+
def build_model(fields) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
140
|
+
build_actor_collection!(fields['authors'] || [])
|
141
|
+
build_actor_collection!(fields['contact'] || [])
|
142
|
+
(fields['identifiers'] || []).map! do |i|
|
143
|
+
Identifier.new(i)
|
144
|
+
end
|
145
|
+
(fields['references'] || []).map! do |r|
|
146
|
+
Reference.new(r)
|
147
|
+
end
|
148
|
+
fields['preferred-citation'] &&=
|
149
|
+
Reference.new(fields['preferred-citation'])
|
150
|
+
|
151
|
+
# Only attempt an update of the `cff-version` field if it is present.
|
152
|
+
fields['cff-version'] &&= update_cff_version(fields['cff-version'])
|
153
|
+
|
154
|
+
fields
|
155
|
+
end
|
156
|
+
|
157
|
+
public
|
158
|
+
|
159
|
+
# Some documentation of "hidden" methods is provided here, out of the
|
160
|
+
# way of the main class code.
|
161
|
+
|
162
|
+
##
|
163
|
+
# :method: authors
|
52
164
|
# :call-seq:
|
53
165
|
# authors -> Array
|
54
166
|
#
|
@@ -60,56 +172,112 @@ module CFF
|
|
60
172
|
# ```
|
61
173
|
#
|
62
174
|
# Authors can be a Person or Entity.
|
63
|
-
def authors
|
64
|
-
@authors
|
65
|
-
end
|
66
175
|
|
176
|
+
##
|
177
|
+
# :method: authors=
|
67
178
|
# :call-seq:
|
68
|
-
#
|
179
|
+
# authors = array_of_authors -> Array
|
69
180
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
|
73
|
-
unless Date === date
|
74
|
-
date = Date.parse(date)
|
75
|
-
end
|
181
|
+
# Replace the list of authors for this citation.
|
182
|
+
#
|
183
|
+
# Authors can be a Person or Entity.
|
76
184
|
|
77
|
-
|
78
|
-
|
185
|
+
##
|
186
|
+
# :method: contact
|
187
|
+
# :call-seq:
|
188
|
+
# contact -> Array
|
189
|
+
#
|
190
|
+
# Return the list of contacts for this citation. To add a contact to the
|
191
|
+
# list, use:
|
192
|
+
#
|
193
|
+
# ```
|
194
|
+
# model.contact << contact
|
195
|
+
# ```
|
196
|
+
#
|
197
|
+
# Contacts can be a Person or Entity.
|
79
198
|
|
199
|
+
##
|
200
|
+
# :method: contact=
|
80
201
|
# :call-seq:
|
81
|
-
#
|
202
|
+
# contact = array_of_contacts -> Array
|
82
203
|
#
|
83
|
-
#
|
84
|
-
|
85
|
-
|
86
|
-
end
|
204
|
+
# Replace the list of contacts for this citation.
|
205
|
+
#
|
206
|
+
# Contacts can be a Person or Entity.
|
87
207
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
208
|
+
##
|
209
|
+
# :method: identifiers
|
210
|
+
# :call-seq:
|
211
|
+
# identifiers -> Array
|
212
|
+
#
|
213
|
+
# Return the list of identifiers for this citation. To add a identifier to
|
214
|
+
# the list, use:
|
215
|
+
#
|
216
|
+
# ```
|
217
|
+
# model.identifiers << identifier
|
218
|
+
# ```
|
93
219
|
|
94
|
-
|
95
|
-
|
220
|
+
##
|
221
|
+
# :method: identifiers=
|
222
|
+
# :call-seq:
|
223
|
+
# identifiers = array_of_identifiers -> Array
|
224
|
+
#
|
225
|
+
# Replace the list of identifiers for this citation.
|
96
226
|
|
97
|
-
|
98
|
-
|
227
|
+
##
|
228
|
+
# :method: keywords
|
229
|
+
# :call-seq:
|
230
|
+
# keywords -> Array
|
231
|
+
#
|
232
|
+
# Return the list of keywords for this citation. To add a keyword to the
|
233
|
+
# list, use:
|
234
|
+
#
|
235
|
+
# ```
|
236
|
+
# model.keywords << keyword
|
237
|
+
# ```
|
238
|
+
#
|
239
|
+
# Keywords will be converted to Strings on output.
|
99
240
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
241
|
+
##
|
242
|
+
# :method: keywords=
|
243
|
+
# :call-seq:
|
244
|
+
# keywords = array_of_keywords -> Array
|
245
|
+
#
|
246
|
+
# Replace the list of keywords for this citation.
|
247
|
+
#
|
248
|
+
# Keywords will be converted to Strings on output.
|
107
249
|
|
108
|
-
|
250
|
+
##
|
251
|
+
# :method: preferred_citation
|
252
|
+
# :call-seq:
|
253
|
+
# preferred_citation -> Reference
|
254
|
+
#
|
255
|
+
# Return the preferred citation for this citation.
|
109
256
|
|
110
|
-
|
111
|
-
|
112
|
-
|
257
|
+
##
|
258
|
+
# :method: preferred_citation=
|
259
|
+
# :call-seq:
|
260
|
+
# preferred_citation = Reference
|
261
|
+
#
|
262
|
+
# Replace the preferred citation for this citation.
|
263
|
+
|
264
|
+
##
|
265
|
+
# :method: references
|
266
|
+
# :call-seq:
|
267
|
+
# references -> Array
|
268
|
+
#
|
269
|
+
# Return the list of references for this citation. To add a reference to the
|
270
|
+
# list, use:
|
271
|
+
#
|
272
|
+
# ```
|
273
|
+
# model.references << reference
|
274
|
+
# ```
|
113
275
|
|
276
|
+
##
|
277
|
+
# :method: references=
|
278
|
+
# :call-seq:
|
279
|
+
# references = array_of_references -> Array
|
280
|
+
#
|
281
|
+
# Replace the list of references for this citation.
|
114
282
|
end
|
115
283
|
end
|