briard 2.4.1 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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