cff 0.1.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
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
+ # ModelPart is the superclass of anything that makes up part of the CFF Model.
21
+ # This includes Model, Person, Entity and Reference.
22
+ #
23
+ # ModelPart does not provide any methods or fields for the public API.
24
+ class ModelPart
25
+
26
+ # :stopdoc:
27
+ include Util
28
+
29
+ attr_reader :fields
30
+
31
+ def method_missing(name, *args)
32
+ n = method_to_field(name.id2name)
33
+ super unless self.class::ALLOWED_FIELDS.include?(n.chomp('='))
34
+
35
+ if n.end_with?('=')
36
+ @fields[n.chomp('=')] = args[0] || ''
37
+ else
38
+ @fields[n]
39
+ end
40
+ end
41
+
42
+ def respond_to_missing?(name, *)
43
+ n = method_to_field(name.id2name)
44
+ self.class::ALLOWED_FIELDS.include?(n.chomp('=')) || super
45
+ end
46
+
47
+ # :startdoc:
48
+ end
49
+ end
data/lib/cff/person.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (c) 2018 Robert Haines.
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,24 +14,63 @@
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
  # A Person represents a person in a CITATION.cff file. A Person might have a
19
21
  # number of roles, such as author, contact, editor, etc.
20
- class Person
22
+ #
23
+ # Person implements all of the fields listed in the
24
+ # [CFF standard](https://citation-file-format.github.io/). All fields
25
+ # are simple strings and can be set as such. A field which has not been set
26
+ # will return the empty string. The simple fields are (with defaults in
27
+ # parentheses):
28
+ #
29
+ # * `address`
30
+ # * `affiliation`
31
+ # * `alias`
32
+ # * `city`
33
+ # * `country`
34
+ # * `email`
35
+ # * `family_names`
36
+ # * `fax`
37
+ # * `given_names`
38
+ # * `name_particle`
39
+ # * `name_suffix`
40
+ # * `orcid`
41
+ # * `post_code`
42
+ # * `region`
43
+ # * `tel`
44
+ # * `website`
45
+ class Person < ModelPart
21
46
 
22
- attr_reader :fields # :nodoc:
47
+ ALLOWED_FIELDS = [
48
+ 'address', 'affiliation', 'alias', 'city', 'country', 'email',
49
+ 'family-names', 'fax', 'given-names', 'name-particle', 'name-suffix',
50
+ 'orcid', 'post-code', 'region', 'tel', 'website'
51
+ ].freeze # :nodoc:
23
52
 
24
53
  # :call-seq:
54
+ # new -> Person
55
+ # new { |person| block } -> Person
25
56
  # new(given_name, family_name) -> Person
57
+ # new(given_name, family_name) { |person| block } -> Person
26
58
  #
27
- # Create a new Person with the supplied given and family names.
28
- def initialize(given, family)
29
- @fields = Hash.new('')
30
- @fields['family-names'] = family
31
- @fields['given-names'] = given
32
- end
59
+ # Create a new Person with the optionally supplied given and family names.
60
+ def initialize(param = nil, *more)
61
+ if param.is_a?(Hash)
62
+ @fields = param
63
+ @fields.default = ''
64
+ else
65
+ @fields = Hash.new('')
33
66
 
67
+ unless param.nil?
68
+ @fields['family-names'] = more[0]
69
+ @fields['given-names'] = param
70
+ end
71
+ end
72
+
73
+ yield self if block_given?
74
+ end
34
75
  end
35
76
  end
@@ -0,0 +1,541 @@
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
+ # Reference provides a reference pertaining to the software version or the
21
+ # software itself, e.g., a software paper describing the abstract concepts of
22
+ # the software, a paper describing an algorithm that has been implemented in
23
+ # the software version, etc.
24
+ #
25
+ # Reference implements all of the fields listed in the
26
+ # [CFF standard](https://citation-file-format.github.io/). Complex
27
+ # fields - `authors`, `contact`, `editors`, `editors_series`, `identifiers`,
28
+ # `keywords`, `languages`, `patent_states`, `recipients`, `senders` and
29
+ # `translators` - are documented below. All other fields are simple strings
30
+ # and can be set as such. A field which has not been set will return the
31
+ # empty string. The simple fields are (with defaults in parentheses):
32
+ #
33
+ # * `abbreviation`
34
+ # * `abstract`
35
+ # * `collection_doi`
36
+ # * `collection_title`
37
+ # * `collection_type`
38
+ # * `commit`
39
+ # * `conference`
40
+ # * `copyright`
41
+ # * `data-type`
42
+ # * `database`
43
+ # * `database_provider`
44
+ # * `date_accessed` - *Note:* returns a `Date` object
45
+ # * `date_downloaded` - *Note:* returns a `Date` object
46
+ # * `date_published` - *Note:* returns a `Date` object
47
+ # * `date_released` - *Note:* returns a `Date` object
48
+ # * `department`
49
+ # * `doi`
50
+ # * `edition`
51
+ # * `end`
52
+ # * `entry`
53
+ # * `filename`
54
+ # * `format`
55
+ # * `institution`
56
+ # * `isbn`
57
+ # * `issn`
58
+ # * `issue`
59
+ # * `issue_date` - *Note:* returns a `Date` object
60
+ # * `issue_title`
61
+ # * `journal`
62
+ # * `license` - *Note:* see documentation for `license =` below
63
+ # * `license_url`
64
+ # * `loc_end`
65
+ # * `loc_start`
66
+ # * `location`
67
+ # * `medium`
68
+ # * `month`
69
+ # * `nihmsid`
70
+ # * `notes`
71
+ # * `number`
72
+ # * `number_volumes`
73
+ # * `pages`
74
+ # * `pmcid`
75
+ # * `publisher`
76
+ # * `repository`
77
+ # * `repository_code`
78
+ # * `repository_artifact`
79
+ # * `scope`
80
+ # * `section`
81
+ # * `start`
82
+ # * `status` - *Note:* see documentation for `status =` below
83
+ # * `thesis_type`
84
+ # * `title`
85
+ # * `type` - *Note:* see documentation for `type =` below
86
+ # * `url`
87
+ # * `version`
88
+ # * `volume`
89
+ # * `volume_title`
90
+ # * `year`
91
+ # * `year_original`
92
+ class Reference < ModelPart
93
+
94
+ include Licensable
95
+
96
+ ALLOWED_FIELDS = [
97
+ 'abbreviation', 'abstract', 'authors', 'collection-doi',
98
+ 'collection-title', 'collection-type', 'commit', 'conference', 'contact',
99
+ 'copyright', 'data-type', 'database', 'database-provider',
100
+ 'date-accessed', 'date-downloaded', 'date-published', 'date-released',
101
+ 'department', 'doi', 'edition', 'editors', 'editors-series', 'end',
102
+ 'entry', 'filename', 'identifiers', 'institution', 'isbn', 'issn',
103
+ 'issue', 'issue-date', 'issue-title', 'journal', 'keywords', 'license',
104
+ 'license-url', 'loc-end', 'loc-start', 'location', 'medium', 'month',
105
+ 'nihmsid', 'notes', 'number', 'number-volumes', 'pages', 'patent-states',
106
+ 'pmcid', 'publisher', 'recipients', 'repository', 'repository-code',
107
+ 'repository-artifact', 'scope', 'section', 'senders', 'start', 'status',
108
+ 'thesis-type', 'title', 'translators', 'type', 'url', 'version',
109
+ 'volume', 'volume-title', 'year', 'year-original'
110
+ ].freeze # :nodoc:
111
+
112
+ # The [defined set of reference types](https://github.com/citation-file-format/citation-file-format#reference-types).
113
+ REFERENCE_TYPES = [
114
+ 'art', 'article', 'audiovisual', 'bill', 'blog', 'book', 'catalogue',
115
+ 'conference', 'conference-paper', 'data', 'database', 'dictionary',
116
+ 'edited-work', 'encyclopedia', 'film-broadcast', 'generic',
117
+ 'government-document', 'grant', 'hearing', 'historical-work',
118
+ 'legal-case', 'legal-rule', 'magazine-article', 'manual', 'map',
119
+ 'multimedia', 'music', 'newspaper-article', 'pamphlet', 'patent',
120
+ 'personal-communication', 'proceedings', 'report', 'serial', 'slides',
121
+ 'software', 'software-code', 'software-container', 'software-executable',
122
+ 'software-virtual-machine', 'sound-recording', 'standard', 'statute',
123
+ 'thesis', 'unpublished', 'video', 'website'
124
+ ].freeze
125
+
126
+ # The [defined set of reference status types](https://github.com/citation-file-format/citation-file-format#status-strings).
127
+ REFERENCE_STATUS_TYPES = [
128
+ 'abstract', 'advance-online', 'in-preparation', 'in-press',
129
+ 'pre-print', 'submitted'
130
+ ].freeze
131
+
132
+ # :call-seq:
133
+ # new(title) -> Reference
134
+ # new(title) { |ref| block } -> Reference
135
+ # new(title, type) -> Reference
136
+ # new(title, type) { |ref| block } -> Reference
137
+ #
138
+ # Create a new Reference with the supplied title and, optionally, type.
139
+ # If type is not given, or is not one of the
140
+ # [defined set of reference types](https://github.com/citation-file-format/citation-file-format#reference-types),
141
+ # 'generic' will be used by default.
142
+ def initialize(param, *more) # rubocop:disable Metrics/AbcSize
143
+ if param.is_a?(Hash)
144
+ @fields = build_model(param)
145
+ @fields.default = ''
146
+ else
147
+ @fields = Hash.new('')
148
+ type = more[0] &&= more[0].downcase
149
+ @fields['type'] = REFERENCE_TYPES.include?(type) ? type : 'generic'
150
+ @fields['title'] = param
151
+ end
152
+
153
+ [
154
+ 'authors', 'contact', 'editors', 'editors-series', 'identifiers',
155
+ 'keywords', 'patent-states', 'recipients', 'senders', 'translators'
156
+ ].each do |field|
157
+ @fields[field] = [] if @fields[field].empty?
158
+ end
159
+
160
+ yield self if block_given?
161
+ end
162
+
163
+ # :call-seq:
164
+ # add_language language
165
+ #
166
+ # Add a language to this Reference. Input is converted to the ISO 639-3
167
+ # three letter language code, so `GER` becomes `deu`, `french` becomes
168
+ # `fra` and `en` becomes `eng`.
169
+ def add_language(lang)
170
+ @fields['languages'] = [] if @fields['languages'].empty?
171
+ lang = LanguageList::LanguageInfo.find(lang)
172
+ return if lang.nil?
173
+
174
+ lang = lang.iso_639_3
175
+ @fields['languages'] << lang unless @fields['languages'].include? lang
176
+ end
177
+
178
+ # :call-seq:
179
+ # reset_languages
180
+ #
181
+ # Reset the list of languages for this Reference to be empty.
182
+ def reset_languages
183
+ @fields.delete('languages')
184
+ end
185
+
186
+ # :call-seq:
187
+ # languages -> Array
188
+ #
189
+ # Return the list of languages associated with this Reference.
190
+ def languages
191
+ @fields['languages'].empty? ? [] : @fields['languages'].dup
192
+ end
193
+
194
+ # :call-seq:
195
+ # date_accessed = date
196
+ #
197
+ # Set the `date-accessed` field. If a non-Date object is passed in it will
198
+ # be parsed into a Date.
199
+ def date_accessed=(date)
200
+ date = Date.parse(date) unless date.is_a?(Date)
201
+
202
+ @fields['date-accessed'] = date
203
+ end
204
+
205
+ # :call-seq:
206
+ # date_downloaded = date
207
+ #
208
+ # Set the `date-downloaded` field. If a non-Date object is passed in it will
209
+ # be parsed into a Date.
210
+ def date_downloaded=(date)
211
+ date = Date.parse(date) unless date.is_a?(Date)
212
+
213
+ @fields['date-downloaded'] = date
214
+ end
215
+
216
+ # :call-seq:
217
+ # date_published = date
218
+ #
219
+ # Set the `date-published` field. If a non-Date object is passed in it will
220
+ # be parsed into a Date.
221
+ def date_published=(date)
222
+ date = Date.parse(date) unless date.is_a?(Date)
223
+
224
+ @fields['date-published'] = date
225
+ end
226
+
227
+ # :call-seq:
228
+ # date_released = date
229
+ #
230
+ # Set the `date-released` field. If a non-Date object is passed in it will
231
+ # be parsed into a Date.
232
+ def date_released=(date)
233
+ date = Date.parse(date) unless date.is_a?(Date)
234
+
235
+ @fields['date-released'] = date
236
+ end
237
+
238
+ # Returns the format of this Reference.
239
+ #
240
+ # This method is explicitly defined to override the private format method
241
+ # that all objects seem to have.
242
+ def format # :nodoc:
243
+ @fields['format']
244
+ end
245
+
246
+ # Sets the format of this Reference.
247
+ #
248
+ # This method is explicitly defined to override the private format method
249
+ # that all objects seem to have.
250
+ def format=(fmt) # :nodoc:
251
+ @fields['format'] = fmt
252
+ end
253
+
254
+ # :call-seq:
255
+ # status = status
256
+ #
257
+ # Sets the status of this Reference. The status is restricted to a
258
+ # [defined set of status types](https://github.com/citation-file-format/citation-file-format#status-strings).
259
+ def status=(status)
260
+ status = status.downcase
261
+ @fields['status'] = status if REFERENCE_STATUS_TYPES.include?(status)
262
+ end
263
+
264
+ # :call-seq:
265
+ # type = type
266
+ #
267
+ # Sets the type of this Reference. The type is restricted to a
268
+ # [defined set of reference types](https://github.com/citation-file-format/citation-file-format#reference-types).
269
+ def type=(type)
270
+ type = type.downcase
271
+ @fields['type'] = type if REFERENCE_TYPES.include?(type)
272
+ end
273
+
274
+ # Override superclass #fields as References contain model parts too.
275
+ def fields # :nodoc:
276
+ [
277
+ 'authors', 'contact', 'editors', 'editors-series', 'identifiers',
278
+ 'recipients', 'senders', 'translators'
279
+ ].each do |field|
280
+ normalize_modelpart_array!(@fields[field])
281
+ end
282
+
283
+ fields_to_hash(@fields)
284
+ end
285
+
286
+ private
287
+
288
+ def build_model(fields) # :nodoc:
289
+ [
290
+ 'authors', 'contact', 'editors', 'editors-series', 'recipients',
291
+ 'senders', 'translators'
292
+ ].each do |field|
293
+ build_actor_collection!(fields[field]) if fields.include?(field)
294
+ end
295
+
296
+ [
297
+ 'conference', 'database-provider', 'institution', 'location',
298
+ 'publisher'
299
+ ].each do |field|
300
+ fields[field] &&= Entity.new(fields[field])
301
+ end
302
+
303
+ (fields['identifiers'] || []).map! do |i|
304
+ Identifier.new(i)
305
+ end
306
+
307
+ fields
308
+ end
309
+
310
+ public
311
+
312
+ # Some documentation of "hidden" methods is provided here, out of the
313
+ # way of the main class code.
314
+
315
+ ##
316
+ # :method: authors
317
+ # :call-seq:
318
+ # authors -> Array
319
+ #
320
+ # Return the list of authors for this Reference. To add an author to the
321
+ # list, use:
322
+ #
323
+ # ```
324
+ # reference.authors << author
325
+ # ```
326
+ #
327
+ # Authors can be a Person or Entity.
328
+
329
+ ##
330
+ # :method: authors=
331
+ # :call-seq:
332
+ # authors = array_of_authors -> Array
333
+ #
334
+ # Replace the list of authors for this reference.
335
+ #
336
+ # Authors can be a Person or Entity.
337
+
338
+ ##
339
+ # :method: contact
340
+ # :call-seq:
341
+ # contact -> Array
342
+ #
343
+ # Return the list of contacts for this Reference. To add a contact to the
344
+ # list, use:
345
+ #
346
+ # ```
347
+ # reference.contact << contact
348
+ # ```
349
+ #
350
+ # Contacts can be a Person or Entity.
351
+
352
+ ##
353
+ # :method: contact=
354
+ # :call-seq:
355
+ # contact = array_of_contacts -> Array
356
+ #
357
+ # Replace the list of contacts for this reference.
358
+ #
359
+ # Contacts can be a Person or Entity.
360
+
361
+ ##
362
+ # :method: editors
363
+ # :call-seq:
364
+ # editors -> Array
365
+ #
366
+ # Return the list of editors for this Reference. To add an editor to the
367
+ # list, use:
368
+ #
369
+ # ```
370
+ # reference.editors << editor
371
+ # ```
372
+ #
373
+ # An editor can be a Person or Entity.
374
+
375
+ ##
376
+ # :method: editors=
377
+ # :call-seq:
378
+ # editors = array_of_editors -> Array
379
+ #
380
+ # Replace the list of editors for this reference.
381
+ #
382
+ # Editors can be a Person or Entity.
383
+
384
+ ##
385
+ # :method: editors_series
386
+ # :call-seq:
387
+ # editors_series -> Array
388
+ #
389
+ # Return the list of series editors for this Reference. To add a series
390
+ # editor to the list, use:
391
+ #
392
+ # ```
393
+ # reference.editors_series << editor
394
+ # ```
395
+ #
396
+ # An editor can be a Person or Entity.
397
+
398
+ ##
399
+ # :method: editors_series=
400
+ # :call-seq:
401
+ # editors_series = array_of_series_editors -> Array
402
+ #
403
+ # Replace the list of series editors for this reference.
404
+ #
405
+ # Series editors can be a Person or Entity.
406
+
407
+ ##
408
+ # :method: identifiers
409
+ # :call-seq:
410
+ # identifiers -> Array
411
+ #
412
+ # Return the list of identifiers for this citation. To add a identifier to
413
+ # the list, use:
414
+ #
415
+ # ```
416
+ # model.identifiers << identifier
417
+ # ```
418
+
419
+ ##
420
+ # :method: identifiers=
421
+ # :call-seq:
422
+ # identifiers = array_of_identifiers -> Array
423
+ #
424
+ # Replace the list of identifiers for this citation.
425
+
426
+ ##
427
+ # :method: keywords
428
+ # :call-seq:
429
+ # keywords -> Array
430
+ #
431
+ # Return the list of keywords for this reference. To add a keyword to the
432
+ # list, use:
433
+ #
434
+ # ```
435
+ # model.keywords << keyword
436
+ # ```
437
+ #
438
+ # Keywords will be converted to Strings on output.
439
+
440
+ ##
441
+ # :method: keywords=
442
+ # :call-seq:
443
+ # keywords = array_of_keywords -> Array
444
+ #
445
+ # Replace the list of keywords for this reference.
446
+ #
447
+ # Keywords will be converted to Strings on output.
448
+
449
+ ##
450
+ # :method: patent_states
451
+ # :call-seq:
452
+ # patent_states -> Array
453
+ #
454
+ # Return the list of patent states for this reference. To add a patent
455
+ # state to the list, use:
456
+ #
457
+ # ```
458
+ # model.patent_states << patent_state
459
+ # ```
460
+ #
461
+ # Patent states will be converted to Strings on output.
462
+
463
+ ##
464
+ # :method: patent_states=
465
+ # :call-seq:
466
+ # patent_states = array_of_states -> Array
467
+ #
468
+ # Replace the list of patent states for this reference.
469
+ #
470
+ # Patent states will be converted to Strings on output.
471
+
472
+ ##
473
+ # :method: recipients
474
+ # :call-seq:
475
+ # recipients -> Array
476
+ #
477
+ # Return the list of recipients for this Reference. To add a recipient
478
+ # to the list, use:
479
+ #
480
+ # ```
481
+ # reference.recipients << recipient
482
+ # ```
483
+ #
484
+ # Recipients can be a Person or Entity.
485
+
486
+ ##
487
+ # :method: recipients=
488
+ # :call-seq:
489
+ # recipients = array_of_recipients -> Array
490
+ #
491
+ # Replace the list of recipients for this reference.
492
+ #
493
+ # Recipients can be a Person or Entity.
494
+
495
+ ##
496
+ # :method: senders
497
+ # :call-seq:
498
+ # senders -> Array
499
+ #
500
+ # Return the list of senders for this Reference. To add a sender to the
501
+ # list, use:
502
+ #
503
+ # ```
504
+ # reference.senders << sender
505
+ # ```
506
+ #
507
+ # Senders can be a Person or Entity.
508
+
509
+ ##
510
+ # :method: senders=
511
+ # :call-seq:
512
+ # senders = array_of_senders -> Array
513
+ #
514
+ # Replace the list of senders for this reference.
515
+ #
516
+ # Senders can be a Person or Entity.
517
+
518
+ ##
519
+ # :method: translators
520
+ # :call-seq:
521
+ # translators -> Array
522
+ #
523
+ # Return the list of translators for this Reference. To add a translator
524
+ # to the list, use:
525
+ #
526
+ # ```
527
+ # reference.translators << translator
528
+ # ```
529
+ #
530
+ # Translators can be a Person or Entity.
531
+
532
+ ##
533
+ # :method: translators=
534
+ # :call-seq:
535
+ # translators = array_of_translators -> Array
536
+ #
537
+ # Replace the list of translators for this reference.
538
+ #
539
+ # Translators can be a Person or Entity.
540
+ end
541
+ end