briard 2.4.1 → 2.6.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql-analysis.yml +72 -0
  3. data/.github/workflows/rubocop.yml +50 -0
  4. data/.rubocop.yml +144 -620
  5. data/.rubocop_todo.yml +76 -0
  6. data/CHANGELOG.md +22 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +43 -6
  9. data/Rakefile +1 -1
  10. data/{bolognese.gemspec → briard.gemspec} +46 -38
  11. data/lib/briard/array.rb +2 -2
  12. data/lib/briard/author_utils.rb +79 -71
  13. data/lib/briard/cli.rb +12 -13
  14. data/lib/briard/crossref_utils.rb +73 -61
  15. data/lib/briard/datacite_utils.rb +132 -106
  16. data/lib/briard/doi_utils.rb +10 -10
  17. data/lib/briard/metadata.rb +96 -106
  18. data/lib/briard/metadata_utils.rb +87 -78
  19. data/lib/briard/readers/bibtex_reader.rb +65 -65
  20. data/lib/briard/readers/cff_reader.rb +88 -70
  21. data/lib/briard/readers/citeproc_reader.rb +90 -84
  22. data/lib/briard/readers/codemeta_reader.rb +68 -50
  23. data/lib/briard/readers/crosscite_reader.rb +2 -2
  24. data/lib/briard/readers/crossref_reader.rb +249 -210
  25. data/lib/briard/readers/datacite_json_reader.rb +3 -3
  26. data/lib/briard/readers/datacite_reader.rb +225 -189
  27. data/lib/briard/readers/npm_reader.rb +49 -42
  28. data/lib/briard/readers/ris_reader.rb +82 -80
  29. data/lib/briard/readers/schema_org_reader.rb +182 -159
  30. data/lib/briard/string.rb +1 -1
  31. data/lib/briard/utils.rb +4 -4
  32. data/lib/briard/version.rb +3 -1
  33. data/lib/briard/whitelist_scrubber.rb +11 -4
  34. data/lib/briard/writers/bibtex_writer.rb +14 -8
  35. data/lib/briard/writers/cff_writer.rb +33 -26
  36. data/lib/briard/writers/codemeta_writer.rb +19 -15
  37. data/lib/briard/writers/csv_writer.rb +6 -4
  38. data/lib/briard/writers/datacite_json_writer.rb +8 -2
  39. data/lib/briard/writers/jats_writer.rb +33 -28
  40. data/lib/briard/writers/rdf_xml_writer.rb +1 -1
  41. data/lib/briard/writers/ris_writer.rb +30 -18
  42. data/lib/briard/writers/turtle_writer.rb +1 -1
  43. data/lib/briard.rb +6 -6
  44. data/rubocop.sarif +0 -0
  45. data/spec/array_spec.rb +5 -5
  46. data/spec/author_utils_spec.rb +151 -132
  47. data/spec/datacite_utils_spec.rb +135 -83
  48. data/spec/doi_utils_spec.rb +168 -164
  49. data/spec/find_from_format_spec.rb +69 -69
  50. data/spec/fixtures/vcr_cassettes/Briard_Metadata/sanitize/onlies_keep_specific_tags.yml +65 -0
  51. data/spec/fixtures/vcr_cassettes/Briard_Metadata/sanitize/removes_a_tags.yml +65 -0
  52. data/spec/metadata_spec.rb +91 -90
  53. data/spec/readers/bibtex_reader_spec.rb +43 -38
  54. data/spec/readers/cff_reader_spec.rb +165 -153
  55. data/spec/readers/citeproc_reader_spec.rb +45 -40
  56. data/spec/readers/codemeta_reader_spec.rb +128 -115
  57. data/spec/readers/crosscite_reader_spec.rb +34 -24
  58. data/spec/readers/crossref_reader_spec.rb +1098 -939
  59. data/spec/readers/datacite_json_reader_spec.rb +53 -40
  60. data/spec/readers/datacite_reader_spec.rb +1541 -1337
  61. data/spec/readers/npm_reader_spec.rb +48 -43
  62. data/spec/readers/ris_reader_spec.rb +53 -47
  63. data/spec/readers/schema_org_reader_spec.rb +329 -267
  64. data/spec/spec_helper.rb +6 -5
  65. data/spec/utils_spec.rb +371 -347
  66. data/spec/writers/bibtex_writer_spec.rb +143 -143
  67. data/spec/writers/cff_writer_spec.rb +96 -90
  68. data/spec/writers/citation_writer_spec.rb +34 -33
  69. data/spec/writers/citeproc_writer_spec.rb +226 -224
  70. data/spec/writers/codemeta_writer_spec.rb +18 -16
  71. data/spec/writers/crosscite_writer_spec.rb +91 -73
  72. data/spec/writers/crossref_writer_spec.rb +99 -91
  73. data/spec/writers/csv_writer_spec.rb +70 -70
  74. data/spec/writers/datacite_json_writer_spec.rb +78 -68
  75. data/spec/writers/datacite_writer_spec.rb +417 -322
  76. data/spec/writers/jats_writer_spec.rb +177 -161
  77. data/spec/writers/rdf_xml_writer_spec.rb +68 -63
  78. data/spec/writers/ris_writer_spec.rb +162 -162
  79. data/spec/writers/turtle_writer_spec.rb +47 -47
  80. metadata +250 -160
  81. data/.github/workflows/release.yml +0 -47
@@ -6,17 +6,13 @@ module Briard
6
6
  class Metadata
7
7
  include Briard::MetadataUtils
8
8
 
9
- attr_accessor :string, :from, :sandbox, :meta, :regenerate, :issue, :show_errors
9
+ attr_accessor :string, :from, :sandbox, :meta, :regenerate, :issue, :show_errors, :depositor,
10
+ :email, :registrant
10
11
  attr_reader :doc, :page_start, :page_end
11
- attr_writer :id, :provider_id, :client_id, :doi, :identifiers, :creators, :contributors, :titles, :publisher,
12
- :rights_list, :dates, :publication_year, :volume, :url, :version_info,
13
- :subjects, :contributor, :descriptions, :language, :sizes,
14
- :formats, :schema_version, :meta, :container, :agency,
15
- :format, :funding_references, :state, :geo_locations,
16
- :types, :content_url, :related_identifiers, :related_items, :style, :locale, :date_registered,
17
- :depositor, :email, :registrant
18
-
19
- def initialize(options={})
12
+ attr_writer :id, :provider_id, :client_id, :doi, :identifiers, :creators, :contributors,
13
+ :titles, :publisher, :rights_list, :dates, :publication_year, :volume, :url, :version_info, :subjects, :contributor, :descriptions, :language, :sizes, :formats, :schema_version, :meta, :container, :agency, :format, :funding_references, :state, :geo_locations, :types, :content_url, :related_identifiers, :related_items, :style, :locale, :date_registered
14
+
15
+ def initialize(options = {})
20
16
  options.symbolize_keys!
21
17
 
22
18
  id = normalize_id(options[:input], options)
@@ -26,64 +22,69 @@ module Briard
26
22
  @from = options[:from] || find_from_format(id: id)
27
23
 
28
24
  # mEDRA, KISTI, JaLC and OP DOIs are found in the Crossref index
29
- if @from == "medra"
30
- ra = "mEDRA"
31
- elsif @from == "kisti"
32
- ra = "KISTI"
33
- elsif @from == "jalc"
34
- ra = "JaLC"
35
- elsif @from == "op"
36
- ra = "OP"
25
+ case @from
26
+ when 'medra'
27
+ ra = 'mEDRA'
28
+ when 'kisti'
29
+ ra = 'KISTI'
30
+ when 'jalc'
31
+ ra = 'JaLC'
32
+ when 'op'
33
+ ra = 'OP'
37
34
  end
38
35
 
39
36
  # generate name for method to call dynamically
40
- hsh = @from.present? ? send("get_" + @from, id: id, sandbox: options[:sandbox]) : {}
41
- string = hsh.fetch("string", nil)
37
+ hsh = @from.present? ? send("get_#{@from}", id: id, sandbox: options[:sandbox]) : {}
38
+ string = hsh.fetch('string', nil)
42
39
 
43
40
  elsif options[:input].present? && File.exist?(options[:input])
44
41
  filename = File.basename(options[:input])
45
42
  ext = File.extname(options[:input])
46
- if %w(.bib .ris .xml .json .cff).include?(ext)
43
+ if %w[.bib .ris .xml .json .cff].include?(ext)
47
44
  hsh = {
48
- "url" => options[:url],
49
- "state" => options[:state],
50
- "date_registered" => options[:date_registered],
51
- "date_updated" => options[:date_updated],
52
- "provider_id" => options[:provider_id],
53
- "client_id" => options[:client_id],
54
- "depositor" => options[:depositor],
55
- "email" => options[:email],
56
- "registrant" => options[:registrant],
57
- "content_url" => options[:content_url] }
58
- string = IO.read(options[:input])
45
+ 'url' => options[:url],
46
+ 'state' => options[:state],
47
+ 'date_registered' => options[:date_registered],
48
+ 'date_updated' => options[:date_updated],
49
+ 'provider_id' => options[:provider_id],
50
+ 'client_id' => options[:client_id],
51
+ 'depositor' => options[:depositor],
52
+ 'email' => options[:email],
53
+ 'registrant' => options[:registrant],
54
+ 'content_url' => options[:content_url]
55
+ }
56
+ string = File.read(options[:input])
59
57
  @from = options[:from] || find_from_format(string: string, filename: filename, ext: ext)
60
58
  else
61
- $stderr.puts "File type #{ext} not supported"
59
+ warn "File type #{ext} not supported"
62
60
  exit 1
63
61
  end
64
62
  else
65
63
  hsh = {
66
- "url" => options[:url],
67
- "state" => options[:state],
68
- "date_registered" => options[:date_registered],
69
- "date_updated" => options[:date_updated],
70
- "provider_id" => options[:provider_id],
71
- "client_id" => options[:client_id],
72
- "depositor" => options[:depositor],
73
- "email" => options[:email],
74
- "registrant" => options[:registrant],
75
- "content_url" => options[:content_url],
76
- "creators" => options[:creators],
77
- "contributors" => options[:contributors],
78
- "titles" => options[:titles],
79
- "publisher" => options[:publisher],
80
- "publication_year" => options[:publication_year] }
64
+ 'url' => options[:url],
65
+ 'state' => options[:state],
66
+ 'date_registered' => options[:date_registered],
67
+ 'date_updated' => options[:date_updated],
68
+ 'provider_id' => options[:provider_id],
69
+ 'client_id' => options[:client_id],
70
+ 'depositor' => options[:depositor],
71
+ 'email' => options[:email],
72
+ 'registrant' => options[:registrant],
73
+ 'content_url' => options[:content_url],
74
+ 'creators' => options[:creators],
75
+ 'contributors' => options[:contributors],
76
+ 'titles' => options[:titles],
77
+ 'publisher' => options[:publisher],
78
+ 'publication_year' => options[:publication_year]
79
+ }
81
80
  string = options[:input]
82
81
  @from = options[:from] || find_from_format(string: string)
83
82
  end
84
83
 
85
84
  # make sure input is encoded as utf8
86
- dup_string = string.dup.force_encoding("UTF-8").encode! if string.present? && string.is_a?(String)
85
+ if string.present? && string.is_a?(String)
86
+ dup_string = string.dup.force_encoding('UTF-8').encode!
87
+ end
87
88
  @string = dup_string
88
89
 
89
90
  # input options for citation formatting
@@ -93,19 +94,19 @@ module Briard
93
94
  @sandbox = options[:sandbox]
94
95
 
95
96
  # options that come from the datacite database
96
- @url = hsh.to_h["url"].presence || options[:url].presence
97
- @state = hsh.to_h["state"].presence
98
- @date_registered = hsh.to_h["date_registered"].presence
99
- @date_updated = hsh.to_h["date_updated"].presence
100
- @provider_id = hsh.to_h["provider_id"].presence
101
- @client_id = hsh.to_h["client_id"].presence
102
- @content_url = hsh.to_h["content_url"].presence
97
+ @url = hsh.to_h['url'].presence || options[:url].presence
98
+ @state = hsh.to_h['state'].presence
99
+ @date_registered = hsh.to_h['date_registered'].presence
100
+ @date_updated = hsh.to_h['date_updated'].presence
101
+ @provider_id = hsh.to_h['provider_id'].presence
102
+ @client_id = hsh.to_h['client_id'].presence
103
+ @content_url = hsh.to_h['content_url'].presence
103
104
 
104
105
  # options that come from the submission, needed
105
106
  # for crossref doi registration
106
- @depositor = hsh.to_h["depositor"].presence
107
- @email = hsh.to_h["email"].presence
108
- @registrant = hsh.to_h["registrant"].presence
107
+ @depositor = hsh.to_h['depositor'].presence
108
+ @email = hsh.to_h['email'].presence
109
+ @registrant = hsh.to_h['registrant'].presence
109
110
 
110
111
  # set attributes directly
111
112
  read_options = options.slice(
@@ -133,40 +134,29 @@ module Briard
133
134
 
134
135
  @regenerate = options[:regenerate] || read_options.present?
135
136
  # generate name for method to call dynamically
136
- opts = { string: string, sandbox: options[:sandbox], doi: options[:doi], id: id, ra: ra }.merge(read_options)
137
- @meta = @from.present? ? send("read_" + @from, **opts) : {}
138
- end
139
-
140
- def depositor
141
- @depositor
142
- end
143
-
144
- def email
145
- @email
146
- end
147
-
148
- def registrant
149
- @registrant
137
+ opts = { string: string, sandbox: options[:sandbox], doi: options[:doi], id: id,
138
+ ra: ra }.merge(read_options)
139
+ @meta = @from.present? ? send("read_#{@from}", **opts) : {}
150
140
  end
151
141
 
152
142
  def id
153
- @id ||= meta.fetch("id", nil)
143
+ @id ||= meta.fetch('id', nil)
154
144
  end
155
145
 
156
146
  def doi
157
- @doi ||= meta.fetch("doi", nil)
147
+ @doi ||= meta.fetch('doi', nil)
158
148
  end
159
149
 
160
150
  def provider_id
161
- @provider_id ||= meta.fetch("provider_id", nil)
151
+ @provider_id ||= meta.fetch('provider_id', nil)
162
152
  end
163
153
 
164
154
  def client_id
165
- @client_id ||= meta.fetch("client_id", nil)
155
+ @client_id ||= meta.fetch('client_id', nil)
166
156
  end
167
157
 
168
158
  def exists?
169
- (@state || meta.fetch("state", nil)) != "not_found"
159
+ (@state || meta.fetch('state', nil)) != 'not_found'
170
160
  end
171
161
 
172
162
  def valid?
@@ -175,111 +165,111 @@ module Briard
175
165
 
176
166
  # validate against DataCite schema, unless already errors in the reader
177
167
  def errors
178
- meta.fetch("errors", nil) || datacite_errors(xml: datacite, schema_version: schema_version)
168
+ meta.fetch('errors', nil) || datacite_errors(xml: datacite, schema_version: schema_version)
179
169
  end
180
170
 
181
171
  def descriptions
182
- @descriptions ||= meta.fetch("descriptions", nil)
172
+ @descriptions ||= meta.fetch('descriptions', nil)
183
173
  end
184
174
 
185
175
  def rights_list
186
- @rights_list ||= meta.fetch("rights_list", nil)
176
+ @rights_list ||= meta.fetch('rights_list', nil)
187
177
  end
188
178
 
189
179
  def subjects
190
- @subjects ||= meta.fetch("subjects", nil)
180
+ @subjects ||= meta.fetch('subjects', nil)
191
181
  end
192
182
 
193
183
  def language
194
- @language ||= meta.fetch("language", nil)
184
+ @language ||= meta.fetch('language', nil)
195
185
  end
196
186
 
197
187
  def sizes
198
- @sizes ||= meta.fetch("sizes", nil)
188
+ @sizes ||= meta.fetch('sizes', nil)
199
189
  end
200
190
 
201
191
  def formats
202
- @formats ||= meta.fetch("formats", nil)
192
+ @formats ||= meta.fetch('formats', nil)
203
193
  end
204
194
 
205
195
  def schema_version
206
- @schema_version ||= meta.fetch("schema_version", nil)
196
+ @schema_version ||= meta.fetch('schema_version', nil)
207
197
  end
208
198
 
209
199
  def funding_references
210
- @funding_references ||= meta.fetch("funding_references", nil)
200
+ @funding_references ||= meta.fetch('funding_references', nil)
211
201
  end
212
202
 
213
203
  def related_identifiers
214
- @related_identifiers ||= meta.fetch("related_identifiers", nil)
204
+ @related_identifiers ||= meta.fetch('related_identifiers', nil)
215
205
  end
216
206
 
217
207
  def related_items
218
- @related_items ||= meta.fetch("related_items", nil)
208
+ @related_items ||= meta.fetch('related_items', nil)
219
209
  end
220
210
 
221
211
  def url
222
- @url ||= meta.fetch("url", nil)
212
+ @url ||= meta.fetch('url', nil)
223
213
  end
224
214
 
225
215
  def version_info
226
- @version_info ||= meta.fetch("version_info", nil) || meta.fetch("version", nil)
216
+ @version_info ||= meta.fetch('version_info', nil) || meta.fetch('version', nil)
227
217
  end
228
218
 
229
219
  def publication_year
230
- @publication_year ||= meta.fetch("publication_year", nil)
220
+ @publication_year ||= meta.fetch('publication_year', nil)
231
221
  end
232
222
 
233
223
  def container
234
- @container ||= meta.fetch("container", nil)
224
+ @container ||= meta.fetch('container', nil)
235
225
  end
236
226
 
237
227
  def geo_locations
238
- @geo_locations ||= meta.fetch("geo_locations", nil)
228
+ @geo_locations ||= meta.fetch('geo_locations', nil)
239
229
  end
240
230
 
241
231
  def dates
242
- @dates ||= meta.fetch("dates", nil)
232
+ @dates ||= meta.fetch('dates', nil)
243
233
  end
244
234
 
245
235
  def publisher
246
- @publisher ||= meta.fetch("publisher", nil)
236
+ @publisher ||= meta.fetch('publisher', nil)
247
237
  end
248
238
 
249
239
  def identifiers
250
- @identifiers ||= meta.fetch("identifiers", nil)
240
+ @identifiers ||= meta.fetch('identifiers', nil)
251
241
  end
252
242
 
253
243
  def content_url
254
- @content_url ||= meta.fetch("content_url", nil)
244
+ @content_url ||= meta.fetch('content_url', nil)
255
245
  end
256
246
 
257
247
  def agency
258
- @agency ||= meta.fetch("agency", nil)
248
+ @agency ||= meta.fetch('agency', nil)
259
249
  end
260
250
 
261
251
  def state
262
- @state ||= meta.fetch("state", nil)
252
+ @state ||= meta.fetch('state', nil)
263
253
  end
264
254
 
265
255
  def date_registered
266
- @date_registered ||= meta.fetch("date_registered", nil)
256
+ @date_registered ||= meta.fetch('date_registered', nil)
267
257
  end
268
258
 
269
259
  def types
270
- @types ||= meta.fetch("types", nil)
260
+ @types ||= meta.fetch('types', nil)
271
261
  end
272
262
 
273
263
  def titles
274
- @titles ||= meta.fetch("titles", nil)
264
+ @titles ||= meta.fetch('titles', nil)
275
265
  end
276
266
 
277
267
  def creators
278
- @creators ||= meta.fetch("creators", nil)
268
+ @creators ||= meta.fetch('creators', nil)
279
269
  end
280
270
 
281
271
  def contributors
282
- @contributors ||= meta.fetch("contributors", nil)
272
+ @contributors ||= meta.fetch('contributors', nil)
283
273
  end
284
274
  end
285
- end
275
+ end
@@ -86,25 +86,23 @@ module Briard
86
86
  # replace DOI in XML if provided in options
87
87
  def raw
88
88
  r = string.present? ? string.strip : nil
89
- return r unless (from == "datacite" && r.present?)
89
+ return r unless from == 'datacite' && r.present?
90
90
 
91
91
  doc = Nokogiri::XML(string, nil, 'UTF-8', &:noblanks)
92
- node = doc.at_css("identifier")
92
+ node = doc.at_css('identifier')
93
93
  node.content = doi.to_s.upcase if node.present? && doi.present?
94
94
  doc.to_xml.strip
95
95
  end
96
96
 
97
97
  def should_passthru
98
- (from == "datacite") && regenerate.blank? && raw.present?
98
+ (from == 'datacite') && regenerate.blank? && raw.present?
99
99
  end
100
100
 
101
101
  def container_title
102
102
  if container.present?
103
- container["title"]
104
- elsif types["citeproc"] == "article-journal"
103
+ container['title']
104
+ elsif types['citeproc'] == 'article-journal'
105
105
  publisher
106
- else
107
- nil
108
106
  end
109
107
  end
110
108
 
@@ -114,16 +112,20 @@ module Briard
114
112
  end
115
113
 
116
114
  def reverse
117
- { "citation" => Array.wrap(related_identifiers).select { |ri| ri["relationType"] == "IsReferencedBy" }.map do |r|
118
- { "@id" => normalize_doi(r["relatedIdentifier"]),
119
- "@type" => r["resourceTypeGeneral"] || "ScholarlyArticle",
120
- "identifier" => r["relatedIdentifierType"] == "DOI" ? nil : to_identifier(r) }.compact
121
- end.unwrap,
122
- "isBasedOn" => Array.wrap(related_identifiers).select { |ri| ri["relationType"] == "IsSupplementTo" }.map do |r|
123
- { "@id" => normalize_doi(r["relatedIdentifier"]),
124
- "@type" => r["resourceTypeGeneral"] || "ScholarlyArticle",
125
- "identifier" => r["relatedIdentifierType"] == "DOI" ? nil : to_identifier(r) }.compact
126
- end.unwrap }.compact
115
+ { 'citation' => Array.wrap(related_identifiers).select do |ri|
116
+ ri['relationType'] == 'IsReferencedBy'
117
+ end.map do |r|
118
+ { '@id' => normalize_doi(r['relatedIdentifier']),
119
+ '@type' => r['resourceTypeGeneral'] || 'ScholarlyArticle',
120
+ 'identifier' => r['relatedIdentifierType'] == 'DOI' ? nil : to_identifier(r) }.compact
121
+ end.unwrap,
122
+ 'isBasedOn' => Array.wrap(related_identifiers).select do |ri|
123
+ ri['relationType'] == 'IsSupplementTo'
124
+ end.map do |r|
125
+ { '@id' => normalize_doi(r['relatedIdentifier']),
126
+ '@type' => r['resourceTypeGeneral'] || 'ScholarlyArticle',
127
+ 'identifier' => r['relatedIdentifierType'] == 'DOI' ? nil : to_identifier(r) }.compact
128
+ end.unwrap }.compact
127
129
  end
128
130
 
129
131
  def graph
@@ -139,81 +141,88 @@ module Briard
139
141
  end
140
142
 
141
143
  def citeproc_hsh
142
- page = container.to_h["firstPage"].present? ? [container["firstPage"], container["lastPage"]].compact.join("-") : nil
143
- if Array.wrap(creators).size == 1 && Array.wrap(creators).first.fetch("name", nil) == ":(unav)"
144
- author = nil
145
- else
146
- author = to_citeproc(creators)
147
- end
148
-
149
- if types["resourceTypeGeneral"] == "Software" && version_info.present?
150
- type = "book"
151
- else
152
- type = types["citeproc"]
153
- end
144
+ page = if container.to_h['firstPage'].present?
145
+ [container['firstPage'], container['lastPage']].compact.join('-')
146
+ end
147
+ author = if Array.wrap(creators).size == 1 && Array.wrap(creators).first.fetch('name',
148
+ nil) == ':(unav)'
149
+ nil
150
+ else
151
+ to_citeproc(creators)
152
+ end
153
+
154
+ type = if types['resourceTypeGeneral'] == 'Software' && version_info.present?
155
+ 'book'
156
+ else
157
+ types['citeproc']
158
+ end
154
159
 
155
160
  {
156
- "type" => type,
157
- "id" => normalize_doi(doi),
158
- "categories" => Array.wrap(subjects).map { |k| parse_attributes(k, content: "subject", first: true) }.presence,
159
- "language" => language,
160
- "author" => author,
161
- "contributor" => to_citeproc(contributors),
162
- "issued" => get_date(dates, "Issued") ? get_date_parts(get_date(dates, "Issued")) : get_date_parts(publication_year.to_s),
163
- "submitted" => Array.wrap(dates).find { |d| d["dateType"] == "Submitted" }.to_h.fetch("__content__", nil),
164
- "abstract" => parse_attributes(descriptions, content: "description", first: true),
165
- "container-title" => container_title,
166
- "DOI" => doi,
167
- "volume" => container.to_h["volume"],
168
- "issue" => container.to_h["issue"],
169
- "page" => page,
170
- "publisher" => publisher,
171
- "title" => parse_attributes(titles, content: "title", first: true),
172
- "URL" => url,
173
- "copyright" => Array.wrap(rights_list).map { |l| l["rights"] }.first,
174
- "version" => version_info
161
+ 'type' => type,
162
+ 'id' => normalize_doi(doi),
163
+ 'categories' => Array.wrap(subjects).map do |k|
164
+ parse_attributes(k, content: 'subject', first: true)
165
+ end.presence,
166
+ 'language' => language,
167
+ 'author' => author,
168
+ 'contributor' => to_citeproc(contributors),
169
+ 'issued' => get_date_parts(get_date(dates, 'Issued') || publication_year.to_s),
170
+ 'submitted' => Array.wrap(dates).find do |d|
171
+ d['dateType'] == 'Submitted'
172
+ end.to_h.fetch('__content__', nil),
173
+ 'abstract' => parse_attributes(descriptions, content: 'description', first: true),
174
+ 'container-title' => container_title,
175
+ 'DOI' => doi,
176
+ 'volume' => container.to_h['volume'],
177
+ 'issue' => container.to_h['issue'],
178
+ 'page' => page,
179
+ 'publisher' => publisher,
180
+ 'title' => parse_attributes(titles, content: 'title', first: true),
181
+ 'URL' => url,
182
+ 'copyright' => Array.wrap(rights_list).map { |l| l['rights'] }.first,
183
+ 'version' => version_info
175
184
  }.compact.symbolize_keys
176
185
  end
177
186
 
178
187
  def crosscite_hsh
179
188
  {
180
- "id" => normalize_doi(doi),
181
- "doi" => doi,
182
- "url" => url,
183
- "types" => types,
184
- "creators" => creators,
185
- "titles" => titles,
186
- "publisher" => publisher,
187
- "container" => container,
188
- "subjects" => subjects,
189
- "contributors" => contributors,
190
- "dates" => dates,
191
- "publication_year" => publication_year,
192
- "language" => language,
193
- "identifiers" => identifiers,
194
- "sizes" => sizes,
195
- "formats" => formats,
196
- "version" => version_info,
197
- "rights_list" => rights_list,
198
- "descriptions" => descriptions,
199
- "geo_locations" => geo_locations,
200
- "funding_references" => funding_references,
201
- "related_identifiers" => related_identifiers,
202
- "related_items" => related_items,
203
- "schema_version" => schema_version,
204
- "provider_id" => provider_id,
205
- "client_id" => client_id,
206
- "agency" => agency,
207
- "state" => state
189
+ 'id' => normalize_doi(doi),
190
+ 'doi' => doi,
191
+ 'url' => url,
192
+ 'types' => types,
193
+ 'creators' => creators,
194
+ 'titles' => titles,
195
+ 'publisher' => publisher,
196
+ 'container' => container,
197
+ 'subjects' => subjects,
198
+ 'contributors' => contributors,
199
+ 'dates' => dates,
200
+ 'publication_year' => publication_year,
201
+ 'language' => language,
202
+ 'identifiers' => identifiers,
203
+ 'sizes' => sizes,
204
+ 'formats' => formats,
205
+ 'version' => version_info,
206
+ 'rights_list' => rights_list,
207
+ 'descriptions' => descriptions,
208
+ 'geo_locations' => geo_locations,
209
+ 'funding_references' => funding_references,
210
+ 'related_identifiers' => related_identifiers,
211
+ 'related_items' => related_items,
212
+ 'schema_version' => schema_version,
213
+ 'provider_id' => provider_id,
214
+ 'client_id' => client_id,
215
+ 'agency' => agency,
216
+ 'state' => state
208
217
  }.compact
209
218
  end
210
219
 
211
220
  def style
212
- @style ||= "apa"
221
+ @style ||= 'apa'
213
222
  end
214
223
 
215
224
  def locale
216
- @locale ||= "en-US"
225
+ @locale ||= 'en-US'
217
226
  end
218
227
  end
219
228
  end