relaton 3.0.7 → 3.1.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/bin/relaton +20 -0
- data/lib/relaton/3gpp/processor.rb +1 -1
- data/lib/relaton/3gpp.rb +3 -3
- data/lib/relaton/adobe/processor.rb +1 -1
- data/lib/relaton/adobe.rb +3 -3
- data/lib/relaton/bib/item_data.rb +2 -2
- data/lib/relaton/bib/model/docidentifier.rb +17 -2
- data/lib/relaton/bib.rb +2 -2
- data/lib/relaton/bibcollection.rb +146 -0
- data/lib/relaton/bibdata.rb +92 -0
- data/lib/relaton/bipm/data_outcomes_parser.rb +6 -1
- data/lib/relaton/bipm/processor.rb +1 -1
- data/lib/relaton/bipm.rb +3 -3
- data/lib/relaton/bsi/processor.rb +1 -1
- data/lib/relaton/bsi.rb +1 -1
- data/lib/relaton/calconnect/data_fetcher.rb +2 -2
- data/lib/relaton/calconnect/model/item.rb +1 -1
- data/lib/relaton/calconnect/processor.rb +1 -1
- data/lib/relaton/calconnect.rb +2 -2
- data/lib/relaton/ccsds/data/fetcher.rb +1 -1
- data/lib/relaton/ccsds/model/item.rb +1 -1
- data/lib/relaton/ccsds/processor.rb +1 -1
- data/lib/relaton/ccsds/util.rb +1 -1
- data/lib/relaton/ccsds.rb +1 -1
- data/lib/relaton/cen/processor.rb +1 -1
- data/lib/relaton/cen.rb +2 -2
- data/lib/relaton/cie/data_fetcher.rb +3 -3
- data/lib/relaton/cie/processor.rb +1 -1
- data/lib/relaton/cie.rb +2 -2
- data/lib/relaton/cli/base_convertor.rb +134 -0
- data/lib/relaton/cli/command.rb +396 -0
- data/lib/relaton/cli/data_fetcher.rb +20 -0
- data/lib/relaton/cli/frontend/dist/404.html +18 -0
- data/lib/relaton/cli/frontend/dist/app.iife.js +1 -0
- data/lib/relaton/cli/frontend/dist/style.css +3 -0
- data/lib/relaton/cli/frontend/index.html +14 -0
- data/lib/relaton/cli/frontend/package-lock.json +2945 -0
- data/lib/relaton/cli/frontend/package.json +29 -0
- data/lib/relaton/cli/frontend/public/404.html +18 -0
- data/lib/relaton/cli/frontend/src/App.test.ts +501 -0
- data/lib/relaton/cli/frontend/src/App.vue +506 -0
- data/lib/relaton/cli/frontend/src/app.ts +90 -0
- data/lib/relaton/cli/frontend/src/components/DocumentDetail.test.ts +142 -0
- data/lib/relaton/cli/frontend/src/components/DocumentDetail.vue +228 -0
- data/lib/relaton/cli/frontend/src/components/DocumentRow.vue +88 -0
- data/lib/relaton/cli/frontend/src/components/Icon.test.ts +44 -0
- data/lib/relaton/cli/frontend/src/components/Icon.vue +55 -0
- data/lib/relaton/cli/frontend/src/components/Pagination.vue +26 -0
- data/lib/relaton/cli/frontend/src/dev/main.ts +100 -0
- data/lib/relaton/cli/frontend/src/dev/sample-data.json +71 -0
- data/lib/relaton/cli/frontend/src/lib/filter.test.ts +88 -0
- data/lib/relaton/cli/frontend/src/lib/filter.ts +95 -0
- data/lib/relaton/cli/frontend/src/lib/hydrate.test.ts +102 -0
- data/lib/relaton/cli/frontend/src/lib/hydrate.ts +55 -0
- data/lib/relaton/cli/frontend/src/lib/shards.test.ts +319 -0
- data/lib/relaton/cli/frontend/src/lib/shards.ts +183 -0
- data/lib/relaton/cli/frontend/src/lib/types.ts +148 -0
- data/lib/relaton/cli/frontend/src/lib/url.test.ts +151 -0
- data/lib/relaton/cli/frontend/src/lib/url.ts +111 -0
- data/lib/relaton/cli/frontend/src/shims-vue.d.ts +5 -0
- data/lib/relaton/cli/frontend/src/styles/index.css +27 -0
- data/lib/relaton/cli/frontend/src/test/fetch.ts +58 -0
- data/lib/relaton/cli/frontend/tsconfig.json +20 -0
- data/lib/relaton/cli/frontend/vite.config.ts +42 -0
- data/lib/relaton/cli/frontend/vitest.config.ts +11 -0
- data/lib/relaton/cli/frontend_assets.rb +58 -0
- data/lib/relaton/cli/full_text_search.rb +98 -0
- data/lib/relaton/cli/i18n.yaml +1 -0
- data/lib/relaton/cli/index_item_normalizer.rb +380 -0
- data/lib/relaton/cli/index_site_generator.rb +1043 -0
- data/lib/relaton/cli/relaton_file.rb +290 -0
- data/lib/relaton/cli/subcommand_collection.rb +263 -0
- data/lib/relaton/cli/subcommand_db.rb +81 -0
- data/lib/relaton/cli/templates/_document.liquid +111 -0
- data/lib/relaton/cli/templates/_index.liquid +61 -0
- data/lib/relaton/cli/templates/index/page.liquid +20 -0
- data/lib/relaton/cli/templates/index-style.css +1017 -0
- data/lib/relaton/cli/util.rb +8 -0
- data/lib/relaton/cli/xml_convertor.rb +47 -0
- data/lib/relaton/cli/xml_to_html_renderer.rb +117 -0
- data/lib/relaton/cli/yaml_convertor.rb +102 -0
- data/lib/relaton/cli.rb +103 -0
- data/lib/relaton/core/processor.rb +1 -1
- data/lib/relaton/core.rb +1 -1
- data/lib/relaton/db/registry.rb +1 -1
- data/lib/relaton/db.rb +1 -1
- data/lib/relaton/doi/CLAUDE.md +1 -1
- data/lib/relaton/doi/parser.rb +2 -1
- data/lib/relaton/doi/processor.rb +1 -1
- data/lib/relaton/doi.rb +4 -4
- data/lib/relaton/easc/processor.rb +1 -1
- data/lib/relaton/easc.rb +3 -3
- data/lib/relaton/ecma/data_fetcher.rb +1 -1
- data/lib/relaton/ecma/processor.rb +1 -1
- data/lib/relaton/ecma.rb +2 -2
- data/lib/relaton/element_finder.rb +29 -0
- data/lib/relaton/etsi/data_fetcher.rb +2 -2
- data/lib/relaton/etsi/item.rb +1 -1
- data/lib/relaton/etsi/processor.rb +2 -2
- data/lib/relaton/etsi.rb +1 -1
- data/lib/relaton/evs/processor.rb +1 -1
- data/lib/relaton/evs.rb +2 -2
- data/lib/relaton/gb/CLAUDE.md +1 -1
- data/lib/relaton/gb/bibliography.rb +1 -1
- data/lib/relaton/gb/processor.rb +1 -1
- data/lib/relaton/gb.rb +2 -2
- data/lib/relaton/gost/processor.rb +1 -1
- data/lib/relaton/gost.rb +3 -3
- data/lib/relaton/iala/processor.rb +1 -1
- data/lib/relaton/iala.rb +3 -3
- data/lib/relaton/iana/data_fetcher.rb +1 -1
- data/lib/relaton/iana/processor.rb +1 -1
- data/lib/relaton/iana.rb +2 -2
- data/lib/relaton/iec/data_fetcher.rb +1 -1
- data/lib/relaton/iec/processor.rb +1 -1
- data/lib/relaton/iec.rb +2 -2
- data/lib/relaton/ieee/processor.rb +1 -1
- data/lib/relaton/ieee.rb +2 -2
- data/lib/relaton/ietf/CLAUDE.md +1 -1
- data/lib/relaton/ietf/data_fetcher.rb +1 -1
- data/lib/relaton/ietf/processor.rb +1 -1
- data/lib/relaton/ietf.rb +2 -2
- data/lib/relaton/iho/CLAUDE.md +3 -3
- data/lib/relaton/iho/bibliography.rb +41 -27
- data/lib/relaton/iho/hash_parser_v1.rb +1 -1
- data/lib/relaton/iho/processor.rb +4 -3
- data/lib/relaton/iho.rb +2 -2
- data/lib/relaton/index.rb +1 -1
- data/lib/relaton/isbn/processor.rb +1 -1
- data/lib/relaton/isbn.rb +1 -1
- data/lib/relaton/iso/hash_parser_v1.rb +1 -1
- data/lib/relaton/iso/processor.rb +1 -1
- data/lib/relaton/iso.rb +3 -3
- data/lib/relaton/itu/processor.rb +1 -1
- data/lib/relaton/itu.rb +3 -3
- data/lib/relaton/jcgm/processor.rb +1 -1
- data/lib/relaton/jcgm.rb +2 -2
- data/lib/relaton/jis/processor.rb +1 -1
- data/lib/relaton/jis.rb +2 -2
- data/lib/relaton/nist/CLAUDE.md +11 -1
- data/lib/relaton/nist/README.adoc +7 -1
- data/lib/relaton/nist/hit_collection.rb +25 -1
- data/lib/relaton/nist/mods_parser.rb +32 -8
- data/lib/relaton/nist/processor.rb +1 -1
- data/lib/relaton/nist/pubs_export.rb +69 -11
- data/lib/relaton/nist.rb +2 -2
- data/lib/relaton/oasis/processor.rb +1 -1
- data/lib/relaton/oasis.rb +2 -2
- data/lib/relaton/ogc/CLAUDE.md +1 -1
- data/lib/relaton/ogc/processor.rb +1 -1
- data/lib/relaton/ogc.rb +2 -2
- data/lib/relaton/oiml/processor.rb +1 -1
- data/lib/relaton/oiml.rb +2 -2
- data/lib/relaton/omg/CLAUDE.md +1 -1
- data/lib/relaton/omg/processor.rb +1 -1
- data/lib/relaton/omg.rb +1 -1
- data/lib/relaton/plateau/CLAUDE.md +1 -1
- data/lib/relaton/plateau/data_fetcher.rb +1 -1
- data/lib/relaton/plateau/processor.rb +1 -1
- data/lib/relaton/plateau.rb +2 -2
- data/lib/relaton/render/general.rb +319 -0
- data/lib/relaton/render/iso690/csl_import.rb +129 -0
- data/lib/relaton/render/iso690/element.rb +153 -0
- data/lib/relaton/render/iso690/elements/access.rb +44 -0
- data/lib/relaton/render/iso690/elements/authorizer.rb +45 -0
- data/lib/relaton/render/iso690/elements/citeid.rb +39 -0
- data/lib/relaton/render/iso690/elements/component_part.rb +97 -0
- data/lib/relaton/render/iso690/elements/creator.rb +267 -0
- data/lib/relaton/render/iso690/elements/edition.rb +97 -0
- data/lib/relaton/render/iso690/elements/extent.rb +71 -0
- data/lib/relaton/render/iso690/elements/identifier.rb +46 -0
- data/lib/relaton/render/iso690/elements/location.rb +73 -0
- data/lib/relaton/render/iso690/elements/medium.rb +32 -0
- data/lib/relaton/render/iso690/elements/numeration.rb +26 -0
- data/lib/relaton/render/iso690/elements/production.rb +111 -0
- data/lib/relaton/render/iso690/elements/pub_date.rb +63 -0
- data/lib/relaton/render/iso690/elements/series.rb +66 -0
- data/lib/relaton/render/iso690/elements/size.rb +45 -0
- data/lib/relaton/render/iso690/elements/status.rb +30 -0
- data/lib/relaton/render/iso690/elements/stddoc.rb +40 -0
- data/lib/relaton/render/iso690/elements/title.rb +56 -0
- data/lib/relaton/render/iso690/elements/updated.rb +38 -0
- data/lib/relaton/render/iso690/elements.rb +67 -0
- data/lib/relaton/render/iso690/fields.rb +142 -0
- data/lib/relaton/render/iso690/i18n/en.yml +48 -0
- data/lib/relaton/render/iso690/i18n/fr.yml +14 -0
- data/lib/relaton/render/iso690/i18n/ja.yml +38 -0
- data/lib/relaton/render/iso690/i18n.rb +83 -0
- data/lib/relaton/render/iso690/identifier_kinds.rb +29 -0
- data/lib/relaton/render/iso690/index_renderer.rb +57 -0
- data/lib/relaton/render/iso690/kinds.rb +53 -0
- data/lib/relaton/render/iso690/renderer.rb +150 -0
- data/lib/relaton/render/iso690/rules/bipm.rb +186 -0
- data/lib/relaton/render/iso690/rules/jis.rb +103 -0
- data/lib/relaton/render/iso690/rules/nist.rb +384 -0
- data/lib/relaton/render/iso690/rules.rb +227 -0
- data/lib/relaton/render/iso690/style/locale.rb +59 -0
- data/lib/relaton/render/iso690/style/name_form.rb +87 -0
- data/lib/relaton/render/iso690/style/scheme.rb +33 -0
- data/lib/relaton/render/iso690/style/sort_rule.rb +25 -0
- data/lib/relaton/render/iso690/style/template_map.rb +40 -0
- data/lib/relaton/render/iso690/style/type_template.rb +45 -0
- data/lib/relaton/render/iso690/style.rb +227 -0
- data/lib/relaton/render/iso690/styles/apa.yml +45 -0
- data/lib/relaton/render/iso690/styles/author-date.yml +31 -0
- data/lib/relaton/render/iso690/styles/chicago.yml +49 -0
- data/lib/relaton/render/iso690/styles/ieee-sa.yml +45 -0
- data/lib/relaton/render/iso690/styles/jis-en.yml +68 -0
- data/lib/relaton/render/iso690/styles/jis-ja.yml +67 -0
- data/lib/relaton/render/iso690/styles/lncs.yml +54 -0
- data/lib/relaton/render/iso690/styles/mla.yml +56 -0
- data/lib/relaton/render/iso690/template.rb +248 -0
- data/lib/relaton/render/iso690.rb +28 -0
- data/lib/relaton/sae/CLAUDE.md +89 -0
- data/lib/relaton/sae/bibdata.rb +8 -0
- data/lib/relaton/sae/bibitem.rb +8 -0
- data/lib/relaton/sae/bibliography.rb +128 -0
- data/lib/relaton/sae/data_fetcher.rb +219 -0
- data/lib/relaton/sae/doi_code.rb +83 -0
- data/lib/relaton/sae/item.rb +10 -0
- data/lib/relaton/sae/item_data.rb +6 -0
- data/lib/relaton/sae/processor.rb +62 -0
- data/lib/relaton/sae/util.rb +9 -0
- data/lib/relaton/sae.rb +37 -0
- data/lib/relaton/un/CLAUDE.md +1 -1
- data/lib/relaton/un/processor.rb +1 -1
- data/lib/relaton/un.rb +1 -1
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/w3c/bibliography.rb +1 -1
- data/lib/relaton/w3c/data_fetcher.rb +1 -1
- data/lib/relaton/w3c/processor.rb +1 -1
- data/lib/relaton/w3c.rb +2 -2
- data/lib/relaton/xsf/data_fetcher.rb +1 -1
- data/lib/relaton/xsf/processor.rb +1 -1
- data/lib/relaton/xsf.rb +2 -2
- data/lib/relaton-cli.rb +17 -0
- data/lib/relaton-render.rb +12 -0
- data/lib/relaton.rb +3 -2
- metadata +203 -23
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
lang: en
|
|
2
|
+
labels:
|
|
3
|
+
edition: "ed"
|
|
4
|
+
ordinal_word_1: "First"
|
|
5
|
+
ordinal_word_2: "Second"
|
|
6
|
+
ordinal_word_3: "Third"
|
|
7
|
+
ordinal_word_4: "Fourth"
|
|
8
|
+
ordinal_word_5: "Fifth"
|
|
9
|
+
ordinal_word_6: "Sixth"
|
|
10
|
+
ordinal_word_7: "Seventh"
|
|
11
|
+
ordinal_word_8: "Eighth"
|
|
12
|
+
ordinal_word_9: "Ninth"
|
|
13
|
+
ordinal_word_10: "Tenth"
|
|
14
|
+
size_volume: "vol."
|
|
15
|
+
size_page: "pp."
|
|
16
|
+
page: "p. %"
|
|
17
|
+
pages: "pp. %"
|
|
18
|
+
volume: "vol. %"
|
|
19
|
+
issue: "no. %"
|
|
20
|
+
no_place: "n.p."
|
|
21
|
+
version: "Version"
|
|
22
|
+
medium_website: "[website]"
|
|
23
|
+
viewed: "viewed"
|
|
24
|
+
month_1: "January"
|
|
25
|
+
month_2: "February"
|
|
26
|
+
month_3: "March"
|
|
27
|
+
month_4: "April"
|
|
28
|
+
month_5: "May"
|
|
29
|
+
month_6: "June"
|
|
30
|
+
month_7: "July"
|
|
31
|
+
month_8: "August"
|
|
32
|
+
month_9: "September"
|
|
33
|
+
month_10: "October"
|
|
34
|
+
month_11: "November"
|
|
35
|
+
month_12: "December"
|
|
36
|
+
|
|
37
|
+
series_no: "no."
|
|
38
|
+
report_no: "Report no."
|
|
39
|
+
available_from: "Available from:"
|
|
40
|
+
at_url: "At:"
|
|
41
|
+
in: "In:"
|
|
42
|
+
and: "and"
|
|
43
|
+
oxford_comma: ","
|
|
44
|
+
others: "et al."
|
|
45
|
+
ed: "ed."
|
|
46
|
+
eds: "eds."
|
|
47
|
+
date_range: "–"
|
|
48
|
+
punct: {}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
lang: ja
|
|
2
|
+
labels:
|
|
3
|
+
edition: "版"
|
|
4
|
+
size_volume: "巻"
|
|
5
|
+
size_page: "頁"
|
|
6
|
+
page: "%頁"
|
|
7
|
+
pages: "%頁"
|
|
8
|
+
volume: "巻%"
|
|
9
|
+
issue: "%号"
|
|
10
|
+
version: "版"
|
|
11
|
+
viewed: "閲覧"
|
|
12
|
+
series_no: "番号"
|
|
13
|
+
report_no: "報告番号"
|
|
14
|
+
available_from: "入手先:"
|
|
15
|
+
at_url: "URL:"
|
|
16
|
+
in: "収録:"
|
|
17
|
+
ed: "編"
|
|
18
|
+
eds: "編"
|
|
19
|
+
updated: "更新"
|
|
20
|
+
no_place: "出版地不明"
|
|
21
|
+
edition_cardinal: "第{{ var1 }}版"
|
|
22
|
+
edition_ordinal: "第{{ var1 }}版"
|
|
23
|
+
version_cardinal: "第{{ var1 }}版"
|
|
24
|
+
in_series: "シリーズ"
|
|
25
|
+
list_separator: "、 "
|
|
26
|
+
and: ""
|
|
27
|
+
oxford_comma: ""
|
|
28
|
+
date_range: "〜"
|
|
29
|
+
punct:
|
|
30
|
+
size-join: ""
|
|
31
|
+
marker-space: ""
|
|
32
|
+
production_sep: ": "
|
|
33
|
+
cjk-latin-separator: "、 "
|
|
34
|
+
period: "。"
|
|
35
|
+
comma: "、"
|
|
36
|
+
colon: ":"
|
|
37
|
+
open-paren: "("
|
|
38
|
+
close-paren: ")"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Relaton
|
|
6
|
+
module Render
|
|
7
|
+
module Iso690
|
|
8
|
+
# Language-specific labels and typographic punctuation, declared per
|
|
9
|
+
# language in i18n/<lang>.yml. Adding a language adds a YAML
|
|
10
|
+
# declaration — no code. A style instance's localized strings overlay
|
|
11
|
+
# the language pack; language-varying intra-element punctuation
|
|
12
|
+
# (e.g. French " : " production separator) is declared under
|
|
13
|
+
# `punct:`.
|
|
14
|
+
class I18n < Lutaml::Model::Serializable
|
|
15
|
+
attribute :lang, :string, default: "en"
|
|
16
|
+
attribute :labels, :hash, default: {}
|
|
17
|
+
attribute :punct, :hash, default: {}
|
|
18
|
+
|
|
19
|
+
key_value do
|
|
20
|
+
map "lang", to: :lang
|
|
21
|
+
map "labels", to: :labels
|
|
22
|
+
map "punct", to: :punct
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def label(key)
|
|
26
|
+
labels.fetch(key.to_s, key.to_s)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def punct_fetch(key, default)
|
|
30
|
+
punct.fetch(key, default)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Style-instance localized strings win over the language pack.
|
|
34
|
+
def overlay!(locale)
|
|
35
|
+
labels.merge!(locale.label_map)
|
|
36
|
+
punct.merge!(locale.punct || {})
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Runtime label overrides (a caller's i18n hash): the pack's label
|
|
41
|
+
# names win as the key mapping; unknown keys are ignored.
|
|
42
|
+
def overlay_hash!(hash)
|
|
43
|
+
known = %w[
|
|
44
|
+
edition series_no report_no available_from in and oxford_comma
|
|
45
|
+
ed eds date_range others no_date no_author at
|
|
46
|
+
edition_ordinal edition_cardinal version_cardinal
|
|
47
|
+
]
|
|
48
|
+
hash.each do |key, value|
|
|
49
|
+
labels[key.to_s] = value if known.include?(key.to_s) && !value.nil?
|
|
50
|
+
end
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class << self
|
|
55
|
+
def load(lang = "en")
|
|
56
|
+
code = lang.to_s.empty? ? "en" : lang
|
|
57
|
+
path = File.join(__dir__, "i18n", "#{code}.yml")
|
|
58
|
+
unless File.file?(path)
|
|
59
|
+
# 1.x carried declarations for every locale isodoc uses; the
|
|
60
|
+
# v2 packs are per-style data. Unknown languages fall back to
|
|
61
|
+
# the English pack rather than killing the whole conversion.
|
|
62
|
+
fallback_warn(code)
|
|
63
|
+
path = File.join(__dir__, "i18n", "en.yml")
|
|
64
|
+
raise ArgumentError, "no i18n declarations for language #{code}" unless File.file?(path)
|
|
65
|
+
# The pack supplies the labels; the requested language still
|
|
66
|
+
# governs localization (bilingual titles select by it)
|
|
67
|
+
return from_yaml(File.read(path)).tap { |i| i.lang = code }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
from_yaml(File.read(path))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def fallback_warn(code)
|
|
74
|
+
(@fallback_warned ||= {})[code] and return
|
|
75
|
+
@fallback_warned[code] = true
|
|
76
|
+
warn "relaton-render: no i18n declarations for language " \
|
|
77
|
+
"#{code}; falling back to en"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# Standard and persistent identifiers (ISO 690 clause 7.11): each
|
|
7
|
+
# identifier kind carries its own rendering method. Kinds are keyed by
|
|
8
|
+
# the docidentifier's type attribute — never guessed from content.
|
|
9
|
+
# Flavors register additional kinds (e.g. Pubid::Iala's MRN).
|
|
10
|
+
module IdentifierKinds
|
|
11
|
+
KINDS = {
|
|
12
|
+
"DOI" => ->(content) { "https://doi.org/#{content}" },
|
|
13
|
+
"ISBN" => ->(content) { "ISBN #{content}" },
|
|
14
|
+
"ISSN" => ->(content) { "ISSN #{content}" },
|
|
15
|
+
"URN" => ->(content) { content },
|
|
16
|
+
"MRN" => ->(content) { content },
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def render(docidentifier)
|
|
21
|
+
content = docidentifier.content.to_s
|
|
22
|
+
kind = KINDS[docidentifier.type]
|
|
23
|
+
kind ? kind.call(content) : content
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# A bibliographic index: the ordered reference list, laid out per the
|
|
7
|
+
# BibliographicStyle instance. Sorting follows the style's declared
|
|
8
|
+
# sortKey rules (creator, then date); numbering is layout data.
|
|
9
|
+
class IndexRenderer
|
|
10
|
+
def initialize(style: "author-date", lang: "en", script: "Latn")
|
|
11
|
+
@style = Style.load(style)
|
|
12
|
+
@i18n = I18n.load(lang).overlay!(@style.scheme.locale)
|
|
13
|
+
@renderer = Renderer.new(style: style, lang: lang, script: script)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The reference strings, sorted per the style's sortKey rules.
|
|
17
|
+
def references(models)
|
|
18
|
+
sort_rules = @style.sort_keys
|
|
19
|
+
fields = models.to_h { |m| [m, field_table(m)] }
|
|
20
|
+
models.sort do |a, b|
|
|
21
|
+
fa = fields[a]
|
|
22
|
+
fb = fields[b]
|
|
23
|
+
sort_rules.each do |rule|
|
|
24
|
+
cmp = key_of(fa, rule) <=> key_of(fb, rule)
|
|
25
|
+
next if cmp.zero?
|
|
26
|
+
|
|
27
|
+
break(rule.descending? ? -cmp : cmp)
|
|
28
|
+
end || 0
|
|
29
|
+
end.map { |model| @renderer.render(model) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The laid-out index: numbered entries per the layout rules
|
|
33
|
+
# (arabic by default; "none" renders bare references).
|
|
34
|
+
def render(models, numbering: "arabic")
|
|
35
|
+
refs = references(models)
|
|
36
|
+
return refs if numbering == "none"
|
|
37
|
+
|
|
38
|
+
refs.each_with_index.map { |ref, i| "#{i + 1}. #{ref}" }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def field_table(model)
|
|
44
|
+
Fields.new(model, style: @style, i18n: @i18n).to_h
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def key_of(fields, rule)
|
|
48
|
+
field = fields[rule.attribute.to_s.delete("_").downcase]
|
|
49
|
+
return "" if field.nil?
|
|
50
|
+
|
|
51
|
+
text = field.respond_to?(:text) ? field.text : field.to_s
|
|
52
|
+
text.downcase
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# The vocabulary mapping from a bibliographic item's wire type value
|
|
7
|
+
# to its ISO 690 clause 8 resource kind (TemplateType). This table is
|
|
8
|
+
# the engine's charter — style instances select perType templates on
|
|
9
|
+
# kinds and never enumerate type synonyms. Unmapped values fall to
|
|
10
|
+
# the report kind (clause 8.11), the runner's fallback.
|
|
11
|
+
module Kinds
|
|
12
|
+
TO_KIND = {
|
|
13
|
+
"book" => "monograph",
|
|
14
|
+
"booklet" => "monograph",
|
|
15
|
+
"manual" => "monograph",
|
|
16
|
+
"proceedings" => "monograph",
|
|
17
|
+
"thesis" => "monograph",
|
|
18
|
+
"standard" => "report",
|
|
19
|
+
"techreport" => "report",
|
|
20
|
+
"report" => "report",
|
|
21
|
+
"patent" => "patent",
|
|
22
|
+
"journal" => "continuing",
|
|
23
|
+
"serial" => "continuing",
|
|
24
|
+
"article-journal" => "continuing",
|
|
25
|
+
"article-magazine" => "continuing",
|
|
26
|
+
"inbook" => "component_part",
|
|
27
|
+
"incollection" => "component_part",
|
|
28
|
+
"inproceedings" => "component_part",
|
|
29
|
+
"article" => "serial_part",
|
|
30
|
+
"software" => "online",
|
|
31
|
+
"unpublished" => "online",
|
|
32
|
+
"dataset" => "online",
|
|
33
|
+
"website" => "webdoc",
|
|
34
|
+
"webresource" => "webdoc",
|
|
35
|
+
"webpage" => "online",
|
|
36
|
+
"online" => "online",
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
DEFAULT_KIND = "report"
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
def mapped?(type)
|
|
43
|
+
TO_KIND.key?(type.to_s)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.kind_for(type)
|
|
48
|
+
TO_KIND.fetch(type.to_s, DEFAULT_KIND)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# Public API: relaton model in, citation string out. The style
|
|
7
|
+
# instance supplies every rendering decision; this class only wires
|
|
8
|
+
# the template evaluator to the field resolver. No XML, no
|
|
9
|
+
# intermediate hashes.
|
|
10
|
+
class Renderer
|
|
11
|
+
DEFAULT_STYLE = "author-date"
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def render(model, style: DEFAULT_STYLE, lang: "en", script: "Latn",
|
|
15
|
+
elements: {})
|
|
16
|
+
new(style: style, lang: lang, script: script,
|
|
17
|
+
elements: elements).render(model)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def citation(model, disambiguator: nil, style: DEFAULT_STYLE,
|
|
21
|
+
lang: "en", script: "Latn")
|
|
22
|
+
new(style: style, lang: lang, script: script)
|
|
23
|
+
.citation(model, disambiguator: disambiguator)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize(style: DEFAULT_STYLE, lang: "en", script: "Latn",
|
|
28
|
+
labels: {}, elements: {})
|
|
29
|
+
@style = Style.load(style)
|
|
30
|
+
@elements = Rules.resolve(@style.rules, elements)
|
|
31
|
+
@i18n = I18n.load(lang)
|
|
32
|
+
@i18n.overlay_hash!(labels) unless labels.empty?
|
|
33
|
+
# The style instance is the citation-style authority: its
|
|
34
|
+
# declared strings win over the caller's generic i18n hash
|
|
35
|
+
@i18n.overlay!(@style.scheme.locale)
|
|
36
|
+
@script = script
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def render(model, disambiguator: nil)
|
|
40
|
+
kind = @style.kind_for(model.type)
|
|
41
|
+
template = @style.template_for(kind, home: home_docid?(model))
|
|
42
|
+
out = Template.new(template).evaluate(
|
|
43
|
+
Fields.new(model, style: @style, i18n: @i18n,
|
|
44
|
+
disambiguator: disambiguator,
|
|
45
|
+
elements: @elements).to_h,
|
|
46
|
+
)
|
|
47
|
+
raise ::Relaton::Render::Unrenderable,
|
|
48
|
+
"no renderable elements" if out.strip.empty?
|
|
49
|
+
|
|
50
|
+
out
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def home_docid?(model)
|
|
54
|
+
types = Array(@style.scheme.home_docid_type)
|
|
55
|
+
return false if types.empty?
|
|
56
|
+
|
|
57
|
+
Array(model.docidentifier).any? { |d| types.include?(d.type) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# A creator list alone (flavors' document-history name forms)
|
|
61
|
+
def render_creators(model)
|
|
62
|
+
Elements.build(:creator, model, style: @style, i18n: @i18n,
|
|
63
|
+
short: true, elements: @elements).render
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The short cite: the reference with the first-biblio marker
|
|
67
|
+
def render_short(model, delim)
|
|
68
|
+
kind = @style.kind_for(model.type)
|
|
69
|
+
template = @style.short_template_for(kind,
|
|
70
|
+
home: home_docid?(model)) ||
|
|
71
|
+
@style.template_for(kind, home: home_docid?(model))
|
|
72
|
+
Template.new(template).evaluate_short(
|
|
73
|
+
Fields.new(model, style: @style, i18n: @i18n, short: true,
|
|
74
|
+
elements: @elements).to_h,
|
|
75
|
+
delim,
|
|
76
|
+
)
|
|
77
|
+
rescue ::Relaton::Render::Unrenderable
|
|
78
|
+
""
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The in-text creator with its et-al truncation: the
|
|
82
|
+
# author-date tag's author part
|
|
83
|
+
def in_text_author(model)
|
|
84
|
+
Elements.build(:creator, model, style: @style, i18n: @i18n,
|
|
85
|
+
elements: @elements).in_text
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# The author-date in-text capsule ("Aluffi <em>et al.</em>
|
|
89
|
+
# 2022a"): the in-text creator and the disambiguated date
|
|
90
|
+
def author_date_citation(model, disambiguator: nil)
|
|
91
|
+
f = Fields.new(model, style: @style, i18n: @i18n,
|
|
92
|
+
disambiguator: disambiguator,
|
|
93
|
+
elements: @elements).to_h
|
|
94
|
+
[in_text_author(model), f["disambiguateddate"].text]
|
|
95
|
+
.reject(&:empty?).join(" ")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The bracketed author-date in-text capsule ("Aluffi (2022)"):
|
|
99
|
+
# the author and the PLAIN date (un-disambiguated, the 1.x
|
|
100
|
+
# citetemplate's {{ date }}) in the locale's parentheses
|
|
101
|
+
def bracketed_date_citation(model, **)
|
|
102
|
+
f = Fields.new(model, style: @style, i18n: @i18n,
|
|
103
|
+
elements: @elements).to_h
|
|
104
|
+
date = f["date"].text
|
|
105
|
+
return "" if date.empty?
|
|
106
|
+
|
|
107
|
+
open = @i18n.punct_fetch("open-paren", "(")
|
|
108
|
+
close = @i18n.punct_fetch("close-paren", ")")
|
|
109
|
+
[in_text_author(model), "#{open}#{date}#{close}"]
|
|
110
|
+
.reject(&:empty?).join(" ")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The disambiguated date alone (the citation renderings' date)
|
|
114
|
+
def disambiguated_date(model, disambiguator: nil)
|
|
115
|
+
Fields.new(model, style: @style, i18n: @i18n,
|
|
116
|
+
disambiguator: disambiguator,
|
|
117
|
+
elements: @elements).to_h["disambiguateddate"].text
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def short_from_reference?
|
|
121
|
+
@style.scheme.short_from_reference
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# The title citation ("{{ title }}" in the 1.x citetemplate):
|
|
125
|
+
# the title element's plain form, no style markers
|
|
126
|
+
def title_citation(model)
|
|
127
|
+
Elements.build(:title, model, style: @style, i18n: @i18n,
|
|
128
|
+
elements: @elements).plain
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# The in-text author key (the principal creator's surname, as
|
|
132
|
+
# the citation renders it): the batch disambiguation groups by
|
|
133
|
+
# it
|
|
134
|
+
def author_key(model)
|
|
135
|
+
Fields.new(model, style: @style, i18n: @i18n,
|
|
136
|
+
elements: @elements).to_h["surname"].text
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# In-text form: SURNAME, year + disambiguator (name-and-date)
|
|
140
|
+
def citation(model, disambiguator: nil)
|
|
141
|
+
Template.new(@style.templates.citation).evaluate(
|
|
142
|
+
Fields.new(model, style: @style, i18n: @i18n,
|
|
143
|
+
disambiguator: disambiguator,
|
|
144
|
+
elements: @elements).to_h,
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Rules
|
|
7
|
+
# The BIPM rule set, moved verbatim from the metanorma-bipm
|
|
8
|
+
# flavor's BipmElements: the affiliation-free organization
|
|
9
|
+
# creator, the bold-volume journal numeration, the
|
|
10
|
+
# no-place-with-publisher production, the separator-carrying
|
|
11
|
+
# edition and medium, and the component-part host order.
|
|
12
|
+
# Select from pack data:
|
|
13
|
+
# rules: { creator: bipm_creator, ... }
|
|
14
|
+
module Bipm
|
|
15
|
+
# The BIPM component-part order: the host editors before the
|
|
16
|
+
# host title, the host medium after it, and the production
|
|
17
|
+
# parenthesized with its own trailing period
|
|
18
|
+
class BipmComponentPart < Elements::ComponentPart
|
|
19
|
+
def render
|
|
20
|
+
h = host or return ""
|
|
21
|
+
out = +"#{lead}#{host_names(h)} (#{eds_label(h)})"
|
|
22
|
+
out += " #{host_title}" unless host_title_text.empty?
|
|
23
|
+
out += medium_text(h)
|
|
24
|
+
out += production_text(h)
|
|
25
|
+
out
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def host_editors(h)
|
|
31
|
+
Array(h.contributor).select { |c| has_role?(c, "editor") }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def eds_label(h)
|
|
35
|
+
@i18n.label(host_editors(h).one? ? "ed" : "eds")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def host_names(h)
|
|
39
|
+
names = host_editors(h).map { |c|
|
|
40
|
+
person = c.person or next ""
|
|
41
|
+
|
|
42
|
+
[person_surname(person), person_given(person)].reject(&:empty?)
|
|
43
|
+
.join(" ")
|
|
44
|
+
}.reject(&:empty?)
|
|
45
|
+
join_names(names)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def medium_text(h)
|
|
49
|
+
BipmMedium.new(h, style: @style, i18n: @i18n).render.to_s
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def production_text(h)
|
|
53
|
+
production = Elements::Production
|
|
54
|
+
.new(h, style: @style, i18n: @i18n).render.to_s
|
|
55
|
+
production.empty? ? "" : " (#{production})."
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The BIPM journal numeration: the volume bold and the issue
|
|
60
|
+
# in parens, pages unlabelled. Separate extent elements join
|
|
61
|
+
# with semicolons, localities within one element with spaces
|
|
62
|
+
class BipmExtent < Elements::Extent
|
|
63
|
+
def render
|
|
64
|
+
groups = extent_locality_groups.map { |g| group_text(g) }
|
|
65
|
+
.reject(&:empty?)
|
|
66
|
+
groups.join("; ")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def extent_locality_groups
|
|
72
|
+
Array(@model.extent).map do |e|
|
|
73
|
+
Array(e.locality) +
|
|
74
|
+
Array(e.locality_stack).flat_map { |s| Array(s.locality) }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def group_text(localities)
|
|
79
|
+
volume = plain_locality(localities, "volume")
|
|
80
|
+
volume = volume.empty? ? "" : "<strong>#{volume}</strong>"
|
|
81
|
+
issue = plain_locality(localities, "issue")
|
|
82
|
+
issue = issue.empty? ? "" : "(#{issue})"
|
|
83
|
+
[volume, issue, page_text(localities)].reject(&:empty?).join(" ")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def plain_locality(localities, type)
|
|
87
|
+
loc = localities.find { |l| l.type == type } or return ""
|
|
88
|
+
loc.reference_from.to_s
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def page_text(localities)
|
|
92
|
+
loc = localities.find { |l| l.type == "page" } or return ""
|
|
93
|
+
from = loc.reference_from.to_s
|
|
94
|
+
to = loc.reference_to.to_s
|
|
95
|
+
text = to.empty? || to == from ? from :
|
|
96
|
+
"#{from}#{@i18n.label('date_range')}#{to}"
|
|
97
|
+
return text if item_kind == "serial_part"
|
|
98
|
+
|
|
99
|
+
label = @i18n.label(to.empty? || to == from ? "page" : "pages")
|
|
100
|
+
# the page labels are %-templates ("pp. %"); the block
|
|
101
|
+
# form keeps a % in the cited text from re-expanding
|
|
102
|
+
label.include?("%") ? label.gsub("%") { text } : "#{label} #{text}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# The BIPM production: the no-place placeholder stands only
|
|
107
|
+
# with a publisher ("(n.p.: Publisher)"); a nameless
|
|
108
|
+
# publisher drops the production entirely
|
|
109
|
+
class BipmProduction < Elements::Production
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def no_place_production
|
|
113
|
+
return "" if publishers.empty?
|
|
114
|
+
|
|
115
|
+
super
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# The serial volume, bold, from the size's volume value
|
|
120
|
+
class BipmVolume < Element
|
|
121
|
+
def present?
|
|
122
|
+
!render.empty?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def render
|
|
126
|
+
volume = Array(@model.size&.value).find do |v|
|
|
127
|
+
!v.is_a?(String) && !v.is_a?(Hash) && v.type == "volume"
|
|
128
|
+
end or return ""
|
|
129
|
+
|
|
130
|
+
"<strong>#{volume.content}</strong>"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The BIPM medium, verbatim and bracketed with its leading
|
|
135
|
+
# separator (" [Online]", " [dataset]") — an absent medium
|
|
136
|
+
# attaches to nothing
|
|
137
|
+
class BipmMedium < Elements::Medium
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def medium
|
|
141
|
+
m = @model.medium or return ""
|
|
142
|
+
text = m.carrier.to_s
|
|
143
|
+
text = m.genre.to_s if text.empty?
|
|
144
|
+
text = [m.form.to_s, m.size.to_s].reject(&:empty?)
|
|
145
|
+
.join(", ") if text.empty?
|
|
146
|
+
text.empty? ? "" : " [#{text}]"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# The BIPM edition carries its own leading separator (",
|
|
151
|
+
# First edition" for monographs, ". Version 2" online), so
|
|
152
|
+
# its absence drops the separator with it
|
|
153
|
+
class BipmEdition < Elements::Edition
|
|
154
|
+
def render
|
|
155
|
+
text = super.to_s
|
|
156
|
+
sep = item_kind == "monograph" ? ", " : ". "
|
|
157
|
+
text.empty? ? "" : "#{sep}#{text}"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# The BIPM organization creator: the name alone, no
|
|
162
|
+
# abbreviation suffix. Standards without personal creators
|
|
163
|
+
# cite their publisher's name; monographs cite nothing
|
|
164
|
+
class BipmCreator < Elements::Creator
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def org_name(contributor)
|
|
168
|
+
Array(contributor.organization&.name).map { |n| localized(n) }
|
|
169
|
+
.join(", ")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def fallback_name
|
|
173
|
+
return "" if %w[monograph continuing component_part]
|
|
174
|
+
.include?(@style.kind_for(@model.type))
|
|
175
|
+
|
|
176
|
+
publishers = contributors("publisher").filter_map do |c|
|
|
177
|
+
localized(Array(c.organization&.name).first)
|
|
178
|
+
end
|
|
179
|
+
publishers.reject(&:empty?).first.to_s
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|