cff 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3516244b4f8ca79e358adb6a561ea0d1007590b1fc34686eff2566444e465381
4
- data.tar.gz: 6ad965bc59a6acf7cfa1a0737ed97bbd994e4fabdb64551eb7bdef6d32411534
3
+ metadata.gz: aa0896639724d0e82551bf84fde9801a00974dac14e120dafa51b53bc07c33cb
4
+ data.tar.gz: 0ef577895dff069272703c4c063dc5a84e1e484be6c23ce696592803093c43f7
5
5
  SHA512:
6
- metadata.gz: 822d9b5f9e260d6bec6bbf9fa2891951b10319feca11f5c899431c86143fcdbde0b874ec9fcd598307ffd5b731578f8979d712375f65cfd7092617e5bd3dcf02
7
- data.tar.gz: 122e43d2a21f50b897204e15d4d497cd95cea23a0de1d25a6efc744ca4316e9c5c09fab681e572e8bf66900a4bd40bcbfdf34ecb19e42168c484ca3bbf852d66
6
+ metadata.gz: 63ae9c19849721bb92af374493b8930d75d7bb3bfbbc6e14a8f1fad0bbbf39064c635f5c03f5d2828bc507b33f65dea69d194a640f6be212bf6088fc3238b9f0
7
+ data.tar.gz: 5101768a4a0ab8de6176ba2506c98ad5efce62f517f34146feaa8a114939e2154f415ac1cdb4162e4b7407c7bdf3e3bdba1f8c7b06c4b5f714b68f620f402bc6
data/CHANGES.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changes log for the Ruby CFF Library
2
2
 
3
+ ## 1.3.0
4
+
5
+ * Abstract out parsing YAML.
6
+ * Turn on underlying support for YAML anchors/aliases.
7
+
8
+ ## 1.2.0
9
+
10
+ * Always treat dates as Ruby Date objects.
11
+ * BibTeX: escape special characters ($%&_#{}).
12
+
3
13
  ## 1.1.0
4
14
 
5
15
  * BibTeX: output months as three letter abbreviations.
data/CITATION.cff CHANGED
@@ -1,4 +1,4 @@
1
- # This CITATION.cff file was created by ruby-cff (v 1.1.0).
1
+ # This CITATION.cff file was created by ruby-cff (v 1.3.0).
2
2
  # Gem: https://rubygems.org/gems/cff
3
3
  # CFF: https://citation-file-format.github.io/
4
4
 
@@ -21,9 +21,9 @@ keywords:
21
21
  - metadata
22
22
  - citation file format
23
23
  - CFF
24
- version: 1.1.0
24
+ version: 1.3.0
25
25
  doi: 10.5281/zenodo.1184077
26
- date-released: 2023-04-10
26
+ date-released: 2024-10-26
27
27
  license: Apache-2.0
28
28
  repository-artifact: https://rubygems.org/gems/cff
29
29
  repository-code: https://github.com/citation-file-format/ruby-cff
data/LICENCE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
189
+ Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -122,6 +122,30 @@ CFF::File.open('CITATION.cff') do |cff|
122
122
  end
123
123
  ```
124
124
 
125
+ #### Notes on CFF files with YAML anchors and aliases
126
+
127
+ Ruby CFF can read files that use YAML anchors and aliases. An anchor (`&<label>`) identifies a section of your file for reuse elsewhere. An alias (`*<label>`) is then used to mark where you want that section to be repeated. In this example, the `&authors` anchor marks an author list for reuse wherever the `*authors` alias is used:
128
+
129
+ ```yaml
130
+ cff-version: 1.2.0
131
+ title: Ruby CFF Library
132
+ authors: &authors
133
+ - family-names: Haines
134
+ given-names: Robert
135
+ affiliation: The University of Manchester, UK
136
+
137
+ ...
138
+
139
+ references:
140
+ - type: software
141
+ title: Citation File Format
142
+ authors: *authors
143
+ ```
144
+
145
+ Ruby uses a single object to represent all aliases of an anchor. This means that once the above has been read in by Ruby CFF, if you add an author to either the top-level author list, or the author list in the reference, the new author will appear in both places. With this in mind, you should only use anchors and aliases where the relationship between sections is such that you are sure that exact repetition will always make sense.
146
+
147
+ When saving CFF files that use anchors and aliases the underlying YAML library will not preserve their names. For example, if the above is loaded into Ruby CFF and then immediately saved `&authors`/`*authors` will most likely become `&1`/`*1`.
148
+
125
149
  ### Validating CFF files
126
150
 
127
151
  To quickly validate a file and raise an error on failure, you can use `CFF::File` directly:
@@ -203,7 +227,7 @@ cff.to_apalike(preferred_citation: false)
203
227
 
204
228
  #### A note on citation formats
205
229
 
206
- Due to the different expectations of different publication venues, the citation text may need minor tweaking to be used in specific situations. If you spot a major, or general, error in the output do [let us know](https://github.com/citation-file-format/ruby-cff/issues), but please check against the [BibTex](https://www.bibtex.com/format/) and [APA](https://apastyle.apa.org/style-grammar-guidelines/references) standards first.
230
+ Due to the different expectations of different publication venues, the citation text may need minor tweaking to be used in specific situations. If you spot a major, or general, error in the output do [let us know](https://github.com/citation-file-format/ruby-cff/issues), but please check against the [BibTeX](https://www.bibtex.com/format/) and [APA](https://apastyle.apa.org/style-grammar-guidelines/references) standards first.
207
231
 
208
232
  ### Library versions
209
233
 
data/lib/cff/file.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ require_relative 'index'
19
19
  require_relative 'version'
20
20
 
21
21
  require 'date'
22
- require 'yaml'
23
22
 
24
23
  ##
25
24
  module CFF
@@ -71,9 +70,7 @@ module CFF
71
70
  content = ::File.read(file)
72
71
  comment = File.parse_comment(content)
73
72
 
74
- new(
75
- file, YAML.safe_load(content, permitted_classes: [Date, Time]), comment
76
- )
73
+ new(file, Util.parse_yaml(content), comment)
77
74
  end
78
75
 
79
76
  # :call-seq:
@@ -91,7 +88,7 @@ module CFF
91
88
  if ::File.exist?(file)
92
89
  content = ::File.read(file)
93
90
  comment = File.parse_comment(content)
94
- yaml = YAML.safe_load(content, permitted_classes: [Date, Time])
91
+ yaml = Util.parse_yaml(content)
95
92
  else
96
93
  comment = CFF_COMMENT
97
94
  yaml = ''
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -45,13 +45,17 @@ module CFF
45
45
  month.downcase unless month.nil?
46
46
  end.freeze
47
47
 
48
+ # We need to escape these characters in titles and names, as per
49
+ # https://tex.stackexchange.com/questions/34580/escape-character-in-latex
50
+ ESCAPE_CHARS = Regexp.new(/([&%$#_{}])/)
51
+
48
52
  def self.format(model:, preferred_citation: true) # rubocop:disable Metrics
49
53
  model = select_and_check_model(model, preferred_citation)
50
54
  return if model.nil?
51
55
 
52
56
  values = {}
53
57
  values['author'] = actor_list(model.authors)
54
- values['title'] = "{#{model.title}}"
58
+ values['title'] = "{#{l(model.title)}}"
55
59
 
56
60
  publication_type = bibtex_type(model)
57
61
  publication_data_from_model(model, publication_type, values)
@@ -79,7 +83,7 @@ module CFF
79
83
  def self.publication_data_from_model(model, type, fields)
80
84
  ENTRY_TYPE_MAP[type].each do |field|
81
85
  if model.respond_to?(field)
82
- fields[field] = model.send(field).to_s
86
+ fields[field] = l(model.send(field).to_s)
83
87
  else
84
88
  field = field.chomp('!')
85
89
  fields[field] = send("#{field}_from_model", model)
@@ -108,9 +112,9 @@ module CFF
108
112
  # BibTeX 'institution' could be grabbed from an author's affiliation, or
109
113
  # provided explicitly.
110
114
  def self.institution_from_model(model)
111
- return model.institution.name unless model.institution.empty?
115
+ return l(model.institution.name) unless model.institution.empty?
112
116
 
113
- model.authors.first.affiliation
117
+ l(model.authors.first.affiliation)
114
118
  end
115
119
 
116
120
  # BibTeX 'school' is CFF 'institution'.
@@ -125,7 +129,7 @@ module CFF
125
129
 
126
130
  # BibTeX 'booktitle' is CFF 'collection-title'.
127
131
  def self.booktitle_from_model(model)
128
- model.collection_title
132
+ l(model.collection_title)
129
133
  end
130
134
 
131
135
  # BibTeX 'editor' is CFF 'editors' or 'editors-series'.
@@ -138,11 +142,11 @@ module CFF
138
142
  end
139
143
 
140
144
  def self.publisher_from_model(model)
141
- model.publisher.empty? ? '' : model.publisher.name
145
+ model.publisher.empty? ? '' : l(model.publisher.name)
142
146
  end
143
147
 
144
148
  def self.series_from_model(model)
145
- model.conference.empty? ? '' : model.conference.name
149
+ model.conference.empty? ? '' : l(model.conference.name)
146
150
  end
147
151
 
148
152
  # If we're citing a conference paper, try and use the date of the
@@ -182,9 +186,9 @@ module CFF
182
186
  end
183
187
  end
184
188
 
185
- def self.format_actor(author)
186
- return "{#{author.name}}" if author.is_a?(Entity)
187
- return author.alias if author.family_names.empty? && author.given_names.empty?
189
+ def self.format_actor(author) # rubocop:disable Metrics/AbcSize
190
+ return "{#{l(author.name)}}" if author.is_a?(Entity)
191
+ return l(author.alias) if author.family_names.empty? && author.given_names.empty?
188
192
 
189
193
  particle =
190
194
  author.name_particle.empty? ? '' : "#{author.name_particle} "
@@ -209,6 +213,12 @@ module CFF
209
213
 
210
214
  Util.parameterize(reference)
211
215
  end
216
+
217
+ # Escape a string to preserve special characters in LaTeX output.
218
+ # Used in many places, so short method name to preserve reading flow.
219
+ def self.l(string)
220
+ string.gsub(ESCAPE_CHARS, '\\\\\1')
221
+ end
212
222
  end
213
223
  end
214
224
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2023 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -67,16 +67,9 @@ module CFF
67
67
  end
68
68
 
69
69
  def self.month_and_year_from_date(value)
70
- if value.is_a?(Date)
71
- [value.month, value.year].map(&:to_s)
72
- else
73
- begin
74
- date = Date.parse(value.to_s)
75
- [date.month, date.year].map(&:to_s)
76
- rescue ArgumentError
77
- ['', '']
78
- end
79
- end
70
+ return ['', ''] unless value.is_a?(Date)
71
+
72
+ [value.month, value.year].map(&:to_s)
80
73
  end
81
74
 
82
75
  # CFF 'pages' is the number of pages, which has no equivalent in BibTeX
data/lib/cff/index.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -25,8 +25,6 @@ require_relative 'schema'
25
25
  require_relative 'validatable'
26
26
  require_relative 'citable'
27
27
 
28
- require 'yaml'
29
-
30
28
  ##
31
29
  module CFF
32
30
  # Index is the core data structure for a CITATION.cff file. It can be
@@ -100,7 +98,7 @@ module CFF
100
98
  #
101
99
  # Read a CFF Index from a String and parse it for subsequent manipulation.
102
100
  def self.read(index)
103
- new(YAML.safe_load(index, permitted_classes: [Date, Time]))
101
+ new(Util.parse_yaml(index))
104
102
  end
105
103
 
106
104
  # :call-seq:
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2023 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -59,23 +59,57 @@ module CFF
59
59
  symbols.each do |symbol|
60
60
  field = symbol.to_s.tr('_', '-')
61
61
 
62
- class_eval(
63
- # def date_end=(date)
64
- # date = (date.is_a?(Date) ? date.dup : Date.parse(date))
65
- #
66
- # @fields['date-end'] = date
67
- # end
68
- <<-END_SETTER, __FILE__, __LINE__ + 1
69
- def #{symbol}=(date)
70
- date = (date.is_a?(Date) ? date.dup : Date.parse(date))
71
-
72
- @fields['#{field}'] = date
73
- end
74
- END_SETTER
75
- )
62
+ date_getter(symbol, field)
63
+ date_setter(symbol, field)
76
64
  end
77
65
  end
78
66
 
67
+ def self.date_getter(symbol, field)
68
+ class_eval(
69
+ # def date_end
70
+ # date = @fields['date-end']
71
+ # return date if date.is_a?(Date)
72
+ #
73
+ # begin
74
+ # Date.parse(date)
75
+ # rescue
76
+ # ''
77
+ # end
78
+ # end
79
+ <<-END_GETTER, __FILE__, __LINE__ + 1
80
+ def #{symbol}
81
+ date = @fields['#{field}']
82
+ return date if date.is_a?(Date)
83
+
84
+ begin
85
+ Date.parse(date)
86
+ rescue
87
+ ''
88
+ end
89
+ end
90
+ END_GETTER
91
+ )
92
+ end
93
+
94
+ def self.date_setter(symbol, field)
95
+ class_eval(
96
+ # def date_end=(date)
97
+ # date = (date.is_a?(Date) ? date.dup : Date.parse(date))
98
+ #
99
+ # @fields['date-end'] = date
100
+ # end
101
+ <<-END_SETTER, __FILE__, __LINE__ + 1
102
+ def #{symbol}=(date)
103
+ date = (date.is_a?(Date) ? date.dup : Date.parse(date))
104
+
105
+ @fields['#{field}'] = date
106
+ end
107
+ END_SETTER
108
+ )
109
+ end
110
+
111
+ private_class_method :date_getter, :date_setter
112
+
79
113
  private
80
114
 
81
115
  def method_to_field(name)
data/lib/cff/util.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
3
+ # Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ require_relative 'person'
19
19
  require_relative 'version'
20
20
 
21
21
  require 'rubygems'
22
+ require 'yaml'
22
23
 
23
24
  ##
24
25
  module CFF
@@ -30,6 +31,10 @@ module CFF
30
31
 
31
32
  module_function
32
33
 
34
+ def parse_yaml(string)
35
+ YAML.safe_load(string, aliases: true, permitted_classes: [Date, Time])
36
+ end
37
+
33
38
  def update_cff_version(version)
34
39
  return '' if version.nil? || version.empty?
35
40
 
@@ -44,6 +49,8 @@ module CFF
44
49
  # is a Person or Entity. This isn't perfect, but works 99.99% I think.
45
50
  def build_actor_collection!(source)
46
51
  source.map! do |s|
52
+ next s if s.is_a?(Person) || s.is_a?(Entity)
53
+
47
54
  s.has_key?('name') ? Entity.new(s) : Person.new(s)
48
55
  end
49
56
  end
data/lib/cff/version.rb CHANGED
@@ -17,7 +17,7 @@
17
17
  ##
18
18
  module CFF
19
19
  # :nodoc:
20
- VERSION = '1.1.0'
20
+ VERSION = '1.3.0'
21
21
  DEFAULT_SPEC_VERSION = '1.2.0'
22
22
  MIN_VALIDATABLE_VERSION = '1.2.0'
23
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cff
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Haines
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-04-10 00:00:00.000000000 Z
12
+ date: 2024-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json_schema
@@ -242,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
242
  - !ruby/object:Gem::Version
243
243
  version: '0'
244
244
  requirements: []
245
- rubygems_version: 3.3.23
245
+ rubygems_version: 3.4.1
246
246
  signing_key:
247
247
  specification_version: 4
248
248
  summary: A Ruby library for manipulating CITATION.cff files.