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.
- 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
|