relaton-bib 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
data/docs/hash.adoc CHANGED
@@ -4,9 +4,26 @@
4
4
 
5
5
  The following structure is in place for encoding bibitem as YAML objects, and is also used
6
6
  to represent bibliographic entries in Metanorma Asciidoctor. The structure has not yet been
7
- generalised to `bibdata/ext`, the flavour specific extensions of relaton.
7
+ generalised to `bibdata/ext`, the flavour-specific extensions of relaton.
8
8
 
9
- Any elements which are arrays can also be populated by a hash or single element. For example,
9
+ If an element in Relaton XML has attributes, the content of the element is represented in YAML
10
+ with a `content` key:
11
+
12
+ [source,xml]
13
+ ....
14
+ <title type="main">Geographic information</title>
15
+ ....
16
+
17
+ [source,yaml]
18
+ ....
19
+ title:
20
+ type: main
21
+ content: Geographic information
22
+ ....
23
+
24
+ Any elements with a cardinality of many can be represented as arrays, but
25
+ they can also be populated by a hash or single element. For example,
26
+ a Relaton title can have multiple titles, and multiple scripts; so
10
27
  the following are equivalent:
11
28
 
12
29
  [source,yaml]
@@ -254,22 +271,53 @@ validity:
254
271
  revision: 2011-03-04 09:00
255
272
  ....
256
273
 
257
- == Metanorma structure: nested definition list
274
+ == Metanorma structure (AsciiBib): nested definition list
258
275
 
259
- The Metanorma Asciidoctor representation of this hash structure
276
+ The Metanorma Asciidoctor representation of the Relaton hash structure
260
277
  in a bibliography
261
- is as a definition list, with nested definition lists for nested structures.
278
+ is as a definition list of element name and element contents,
279
+ with nested definition lists for nested structures. If a nested
280
+ definition is given for an element, the element itself has a blank definition.
281
+
282
+ As with the YAML representation, if an element in Relaton XML has attributes,
283
+ the content of the element is represented in YAML with a `content` key:
284
+
285
+ [source,xml]
286
+ ....
287
+ <title type="main">Geographic information</title>
288
+ ....
289
+
290
+ [source,asciidoc]
291
+ ....
292
+ title::
293
+ type::: main
294
+ content::: Geographic information
295
+ ....
296
+
297
+ Likewise, as with the YAML representation,
262
298
  Repeating elements in a hash can be realised as ordered or unordered lists.
263
- However, given how awkward lists of definition lists are in Asciidoctor
264
- (with a limitation of three nesting levels),
265
- Metanorma Asciidoctor also supports representing repeating elements
266
- by repeating the key for that entry.
299
+
300
+ [source,asciidoc]
301
+ ----
302
+ language::
303
+ . en
304
+ . fr
305
+ ----
306
+
307
+ Metanorma Asciidoctor also supports representing repeating elements
308
+ by repeating the key for that entry. This will almost always be more
309
+ straightforward to use in Asciidoctor:
310
+
311
+ [source,asciidoc]
312
+ ----
313
+ language:: en
314
+ language:: fr
315
+ ----
267
316
 
268
317
  Each Relaton entry in a bibliography is represented in Metanorma Asciidoctor
269
318
  through a subclause with option attribute `[%bibitem]`. Any title given to the
270
319
  subclause is treated as the title for the bibliographic entry, with language `en`,
271
- script `Latn`, format `text/plain`, and type `main`. If there is no such title
272
- for the entry, the subclause title should be left as `{blank}`.
320
+ script `Latn`, format `text/plain`, and type `main`.
273
321
 
274
322
  So the following is a very simple reference in Metanorma Asciidoctor:
275
323
 
@@ -287,9 +335,28 @@ docid::
287
335
  type:: standard
288
336
  ----
289
337
 
290
- The anchor crossreference for the bibliographic entry may be encoded as the
338
+ If there is no such title
339
+ for the entry, the subclause title should be left as `{blank}`, and the desired
340
+ title should be given in the hash body:
341
+
342
+ [source,asciidoc]
343
+ ----
344
+ [%bibitem]
345
+ === {blank}
346
+ id:: iso123
347
+ title::
348
+ language::: fr
349
+ script::: Latn
350
+ format::: text/plain
351
+ type::: alt
352
+ content::: Latex de caoutchouc -- Échantillonnage
353
+ ----
354
+
355
+ Note the use of `content` as a key to represent the contents of the `title` tag.
356
+
357
+ The anchor crossreference for the bibliographic entry may be encoded as either the
291
358
  `id` entry in the definition list, or as the normal Asciidoctor anchor on the
292
- subclause, which takes priority over it:
359
+ subclause, which takes priority:
293
360
 
294
361
  [source,asciidoc]
295
362
  ----
@@ -302,9 +369,40 @@ docid::
302
369
  type:: standard
303
370
  ----
304
371
 
305
- Asciidoctor does not currently cope with definition lists more than four levels
372
+ Repeating elements in a hash can be realised as ordered or unordered lists.
373
+
374
+ [source,asciidoc]
375
+ ----
376
+ [[iso123]]
377
+ [%bibitem]
378
+ === Rubber latex -- Sampling
379
+ docid::
380
+ type::: ISO
381
+ id::: ISO 123
382
+ language::
383
+ . en
384
+ . fr
385
+ ----
386
+
387
+ Metanorma Asciidoctor also supports representing repeating elements
388
+ by repeating the key for that entry. This will almost always be more
389
+ straightforward to use in Asciidoctor:
390
+
391
+ [source,asciidoc]
392
+ ----
393
+ [[iso123]]
394
+ [%bibitem]
395
+ === Rubber latex -- Sampling
396
+ docid::
397
+ type::: ISO
398
+ id::: ISO 123
399
+ language:: en
400
+ language:: fr
401
+ ----
402
+
403
+ Asciidoctor does not recognise definition lists more than four levels
306
404
  deep. If deeper nesting is needed, you will need to attach a new definition
307
- list with a list continuation:
405
+ list with a list continuation, with the definition list depth reset back to one:
308
406
 
309
407
  [source,asciidoc]
310
408
  ----
@@ -327,13 +425,22 @@ completename::
327
425
  --
328
426
  ----
329
427
 
428
+ (This is very awkward, and <<JSONPath>> provides a workaround.)
429
+
330
430
  The most heavily nested parts of a Relaton entry are the contributors,
331
- series, and relations. To prevent excessive depth of nesting for such
332
- entries, they can be marked up as subclauses within the entry, with the clause
431
+ series, and relations.
432
+ Each of these can be marked up as subclauses within the entry, with the clause
333
433
  titles "contributor", "series", and "relation". Each subclause contains
334
434
  a new definition list, with its definition list reset to zero depth;
335
435
  the subclauses can be repeated for multiple instances of the same subentity.
336
436
 
437
+ AsciiBib citations can be combined with other Asciidoctor citations in the
438
+ same Metanorma document; but any Asciidoctor citations need be precede
439
+ AsciiBib citations. Each AsciiBib citations constitutes a subclause of its own,
440
+ and Metanorma will (unsuccessfully) attempt to incorporate any trailing material
441
+ in the subclause, including Asciidoctor citations, into the current AsciiBib
442
+ citation.
443
+
337
444
  The following is Metanorma Asciidoctor markup corresponding to the YAML
338
445
  given above:
339
446
 
@@ -549,11 +656,14 @@ formattedref::
549
656
  script::: Latn
550
657
  ....
551
658
 
659
+ [[JSONPath]]
552
660
  == JSON Path style definition lists
553
661
 
554
662
  The foregoing structure requires frequent breakouts into open blocks, to deal
555
663
  with the limitation on Asciidoctor nested definition lists. An alternative is to
556
- represent the nested structure of Relaton records in a simple, one-level definition list, and to use the key for each key-value pair to represent the hierarchical nesting of entries, as a dot-delimited path of keys. For example,
664
+ represent the nested structure of Relaton records in a simple, one-level definition list,
665
+ and to use the key for each key-value pair to represent the hierarchical nesting of entries,
666
+ as a dot-delimited path of keys. For example,
557
667
 
558
668
  [source,asciidoc]
559
669
  ----
@@ -573,7 +683,7 @@ can instead be represented as:
573
683
  === Rubber latex -- Sampling
574
684
  id:: iso123
575
685
  docid.type:: ISO
576
- docid.id::: ISO 123
686
+ docid.id:: ISO 123
577
687
  ----
578
688
 
579
689
  Whenever part of the key is repeated between entries, the entries are assumed to attach to the same parent. If an array of hashes is needed, a blank entry is required for the key of each repeating element: For example,
@@ -601,7 +711,7 @@ can instead be represented as:
601
711
  id:: iso123
602
712
  docid::
603
713
  docid.type:: ISO
604
- docid.id::: ISO 123
714
+ docid.id:: ISO 123
605
715
  docid::
606
716
  docid.type:: ABC
607
717
  docid.id:: 32784
@@ -18,10 +18,12 @@ require "relaton_bib/validity"
18
18
  require "relaton_bib/document_relation"
19
19
  require "relaton_bib/bib_item_locality"
20
20
  require "relaton_bib/xml_parser"
21
+ require "relaton_bib/bibtex_parser"
21
22
  require "relaton_bib/biblio_note"
22
23
  require "relaton_bib/biblio_version"
23
24
  require "relaton_bib/workers_pool"
24
25
  require "relaton_bib/hash_converter"
26
+ require "relaton_bib/place"
25
27
 
26
28
  module RelatonBib
27
29
  # Bibliographic item
@@ -93,7 +95,7 @@ module RelatonBib
93
95
  # @return [RelatonBib::Medium, NilClass]
94
96
  attr_reader :medium
95
97
 
96
- # @return [Array<String>]
98
+ # @return [Array<RelatonBib::Place>]
97
99
  attr_reader :place
98
100
 
99
101
  # @return [Array<RelatonBib::BibItemLocality>]
@@ -102,7 +104,7 @@ module RelatonBib
102
104
  # @return [Array<Strig>]
103
105
  attr_reader :accesslocation
104
106
 
105
- # @return [Relaton::Classification, NilClass]
107
+ # @return [Array<Relaton::Classification>]
106
108
  attr_reader :classification
107
109
 
108
110
  # @return [RelatonBib:Validity, NilClass]
@@ -128,10 +130,10 @@ module RelatonBib
128
130
  # @param biblionote [Array<RelatonBib::BiblioNote>]
129
131
  # @param series [Array<RelatonBib::Series>]
130
132
  # @param medium [RelatonBib::Medium, NilClas]
131
- # @param place [Array<String>]
133
+ # @param place [Array<String, RelatonBib::Place>]
132
134
  # @param extent [Array<Relaton::BibItemLocality>]
133
135
  # @param accesslocation [Array<String>]
134
- # @param classification [RelatonBib::Classification, NilClass]
136
+ # @param classification [Array<RelatonBib::Classification>]
135
137
  # @param validity [RelatonBib:Validity, NilClass]
136
138
  # @param fetched [Date, NilClass] default nil
137
139
  #
@@ -214,10 +216,10 @@ module RelatonBib
214
216
  @link = args.fetch(:link, []).map { |s| s.is_a?(Hash) ? TypedUri.new(s) : s }
215
217
  @series = args.fetch :series, []
216
218
  @medium = args[:medium]
217
- @place = args.fetch(:place, [])
219
+ @place = args.fetch(:place, []).map { |pl| pl.is_a?(String) ? Place.new(name: pl) : pl }
218
220
  @extent = args[:extent] || []
219
221
  @accesslocation = args.fetch :accesslocation, []
220
- @classification = args[:classification]
222
+ @classification = args.fetch :classification, []
221
223
  @validity = args[:validity]
222
224
  @fetched = args.fetch :fetched, nil # , Date.today # we should pass the fetched arg from scrappers
223
225
  end
@@ -298,12 +300,37 @@ module RelatonBib
298
300
  hash["place"] = single_element_array(place) if place&.any?
299
301
  hash["extent"] = single_element_array(extent) if extent&.any?
300
302
  hash["accesslocation"] = single_element_array(accesslocation) if accesslocation&.any?
301
- hash["classification"] = classification.to_hash if classification
303
+ hash["classification"] = single_element_array(classification) if classification&.any?
302
304
  hash["validity"] = validity.to_hash if validity
303
305
  hash["fetched"] = fetched.to_s if fetched
304
306
  hash
305
307
  end
306
308
 
309
+ # @param bibtex [BibTeX::Bibliography, NilClass]
310
+ # @return [String]
311
+ def to_bibtex(bibtex = nil)
312
+ item = BibTeX::Entry.new
313
+ item.type = bibtex_type
314
+ item.key = id
315
+ bibtex_title item
316
+ item.edition = edition if edition
317
+ bibtex_author item
318
+ bibtex_contributor item
319
+ item.address = place.first.name if place.any?
320
+ bibtex_note item
321
+ bibtex_relation item
322
+ bibtex_extent item
323
+ bibtex_date item
324
+ bibtex_series item
325
+ bibtex_classification item
326
+ bibtex_docidentifier item
327
+ item.timestamp = fetched.to_s if fetched
328
+ bibtex_link item
329
+ bibtex ||= BibTeX::Bibliography.new
330
+ bibtex << item
331
+ bibtex.to_s
332
+ end
333
+
307
334
  # If revision_date exists then returns it else returns published date or nil
308
335
  # @return [String, NilClass]
309
336
  def revdate
@@ -316,6 +343,146 @@ module RelatonBib
316
343
 
317
344
  private
318
345
 
346
+ # @return [String]
347
+ def bibtex_title(item)
348
+ title.each do |t|
349
+ case t.type
350
+ when "main" then item.tile = t.title.content
351
+ end
352
+ end
353
+ end
354
+
355
+ # @return [String]
356
+ def bibtex_type
357
+ case type
358
+ when "standard", nil then "misc"
359
+ else type
360
+ end
361
+ end
362
+
363
+ # @param [BibTeX::Entry]
364
+ def bibtex_author(item)
365
+ authors = contributor.select do |c|
366
+ c.entity.is_a?(Person) && c.role.map(&:type).include?("author")
367
+ end.map &:entity
368
+
369
+ return unless authors.any?
370
+
371
+ item.author = authors.map do |a|
372
+ if a.name.surname
373
+ "#{a.name.surname}, #{a.name.forename.map(&:to_s).join(" ")}"
374
+ else
375
+ a.name.completename.to_s
376
+ end
377
+ end.join " and "
378
+ end
379
+
380
+ # @param [BibTeX::Entry]
381
+ def bibtex_contributor(item)
382
+ contributor.each do |c|
383
+ rls = c.role.map(&:type)
384
+ if rls.include?("publisher") then item.publisher = c.entity.name
385
+ elsif rls.include?("distributor")
386
+ case type
387
+ when "techreport" then item.institution = c.entity.name
388
+ when "inproceedings", "conference", "manual", "proceedings"
389
+ item.organization = c.entity.name
390
+ when "mastersthesis", "phdthesis" then item.school = c.entity.name
391
+ end
392
+ end
393
+ end
394
+ end
395
+
396
+ # @param [BibTeX::Entry]
397
+ def bibtex_note(item)
398
+ biblionote.each do |n|
399
+ case n.type
400
+ when "annote" then item.annote = n.content
401
+ when "howpublished" then item.howpublished = n.content
402
+ when "comment" then item.comment = n.content
403
+ when "tableOfContents" then item.content = n.content
404
+ when nil then item.note = n.content
405
+ end
406
+ end
407
+ end
408
+
409
+ # @param [BibTeX::Entry]
410
+ def bibtex_relation(item)
411
+ rel = relation.detect { |r| r.type == "partOf" }
412
+ item.booktitle = rel.bibitem.title.detect { |t| t.type == "main" }.title.content if rel
413
+ end
414
+
415
+ # @param [BibTeX::Entry]
416
+ def bibtex_extent(item)
417
+ extent.each do |e|
418
+ case e.type
419
+ when "chapter" then item.chapter = e.reference_from
420
+ when "page"
421
+ value = e.reference_from
422
+ value += "-#{e.reference_to}" if e.reference_to
423
+ item.pages = value
424
+ when "volume" then item.volume = e.reference_from
425
+ end
426
+ end
427
+ end
428
+
429
+ # @param [BibTeX::Entry]
430
+ def bibtex_date(item)
431
+ date.each do |d|
432
+ case d.type
433
+ when "published"
434
+ item.year = d.on.year
435
+ item.month = d.on.month
436
+ when "accessed" then item.urldate = d.on.to_s
437
+ end
438
+ end
439
+ end
440
+
441
+ # @param [BibTeX::Entry]
442
+ def bibtex_series(item)
443
+ series.each do |s|
444
+ case s.type
445
+ when "journal"
446
+ item.journal = s.title.title
447
+ item.number = s.number if s.number
448
+ when nil then item.series = s.title.title
449
+ end
450
+ end
451
+ end
452
+
453
+ # @param [BibTeX::Entry]
454
+ def bibtex_classification(item)
455
+ classification.each do |c|
456
+ case c.type
457
+ when "type" then item["type"] = c.value
458
+ when "keyword" then item.keywords = c.value
459
+ when "mendeley" then item["mendeley-tags"] = c.value
460
+ end
461
+ end
462
+ end
463
+
464
+ # @param [BibTeX::Entry]
465
+ def bibtex_docidentifier(item)
466
+ docidentifier.each do |i|
467
+ case i.type
468
+ when "isbn" then item.isbn = i.id
469
+ when "lccn" then item.lccn = i.id
470
+ when "issn" then item.issn = i.id
471
+ end
472
+ end
473
+ end
474
+
475
+ # @param [BibTeX::Entry]
476
+ def bibtex_link(item)
477
+ link.each do |l|
478
+ case l.type
479
+ when "doi" then item.doi = l.content
480
+ when "file" then item.file2 = l.content
481
+ when "src" then item.url = l.content
482
+ end
483
+ end
484
+ end
485
+
319
486
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
320
487
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
321
488
  # rubocop:disable Style/NestedParenthesizedCalls, Metrics/BlockLength
@@ -349,10 +516,10 @@ module RelatonBib
349
516
  relation.each { |r| r.to_xml builder, **opts }
350
517
  series.each { |s| s.to_xml builder }
351
518
  medium&.to_xml builder
352
- place.each { |pl| builder.place pl }
519
+ place.each { |pl| pl.to_xml builder }
353
520
  extent.each { |e| builder.extent { e.to_xml builder } }
354
521
  accesslocation.each { |al| builder.accesslocation al }
355
- classification&.to_xml builder
522
+ classification.each { |cls| cls.to_xml builder }
356
523
  validity&.to_xml builder
357
524
  if block_given?
358
525
  yield builder