relaton-bib 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile.lock +24 -19
- data/README.adoc +185 -136
- data/bin/rspec +29 -0
- data/docs/hash.adoc +130 -20
- data/lib/relaton_bib/bibliographic_item.rb +176 -9
- data/lib/relaton_bib/bibtex_parser.rb +236 -0
- data/lib/relaton_bib/contribution_info.rb +1 -1
- data/lib/relaton_bib/hash_converter.rb +12 -6
- data/lib/relaton_bib/place.rb +37 -0
- data/lib/relaton_bib/series.rb +2 -2
- data/lib/relaton_bib/typed_title_string.rb +1 -1
- data/lib/relaton_bib/version.rb +1 -1
- data/lib/relaton_bib/xml_parser.rb +10 -5
- data/relaton-bib.gemspec +2 -1
- metadata +33 -16
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
|
7
|
+
generalised to `bibdata/ext`, the flavour-specific extensions of relaton.
|
8
8
|
|
9
|
-
|
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
|
276
|
+
The Metanorma Asciidoctor representation of the Relaton hash structure
|
260
277
|
in a bibliography
|
261
|
-
is as a definition list
|
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
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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`.
|
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
|
-
|
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
|
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
|
-
|
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.
|
332
|
-
|
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,
|
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
|
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
|
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<
|
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
|
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
|
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
|
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
|
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|
|
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
|
522
|
+
classification.each { |cls| cls.to_xml builder }
|
356
523
|
validity&.to_xml builder
|
357
524
|
if block_given?
|
358
525
|
yield builder
|