relaton 3.0.0.pre.alpha.1 → 3.0.0.pre.alpha.2
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/README.adoc +57 -1
- data/bin/console +0 -1
- data/lib/relaton/3gpp/bibliography.rb +82 -7
- data/lib/relaton/3gpp/data_fetcher.rb +51 -3
- data/lib/relaton/3gpp/docidentifier.rb +114 -0
- data/lib/relaton/3gpp/item.rb +6 -0
- data/lib/relaton/3gpp/parser.rb +1 -1
- data/lib/relaton/3gpp/processor.rb +4 -1
- data/lib/relaton/3gpp.rb +5 -1
- data/lib/relaton/adobe/bibdata.rb +8 -0
- data/lib/relaton/adobe/bibitem.rb +8 -0
- data/lib/relaton/adobe/bibliography.rb +92 -0
- data/lib/relaton/adobe/docidentifier.rb +49 -0
- data/lib/relaton/adobe/doctype.rb +14 -0
- data/lib/relaton/adobe/ext.rb +32 -0
- data/lib/relaton/adobe/item.rb +15 -0
- data/lib/relaton/adobe/item_base.rb +18 -0
- data/lib/relaton/adobe/item_data.rb +6 -0
- data/lib/relaton/adobe/processor.rb +45 -0
- data/lib/relaton/adobe/util.rb +8 -0
- data/lib/relaton/adobe.rb +37 -0
- data/lib/relaton/bib/model/address.rb +2 -2
- data/lib/relaton/bib/model/docidentifier.rb +24 -9
- data/lib/relaton/bib/model/localized_string.rb +1 -1
- data/lib/relaton/bib/model/structured_identifier.rb +10 -9
- data/lib/relaton/bib/sanitizer.rb +202 -6
- data/lib/relaton/bib.rb +0 -2
- data/lib/relaton/bipm/bibliography.rb +159 -10
- data/lib/relaton/bipm/data_fetcher.rb +26 -2
- data/lib/relaton/bipm/data_outcomes_parser.rb +3 -4
- data/lib/relaton/bipm/id_parser.rb +5 -4
- data/lib/relaton/bipm/model/structured_identifier.rb +21 -0
- data/lib/relaton/bipm/processor.rb +2 -2
- data/lib/relaton/bipm/rawdata_bipm_metrologia/fetcher.rb +2 -4
- data/lib/relaton/bipm/si_brochure_parser.rb +5 -3
- data/lib/relaton/bipm.rb +7 -1
- data/lib/relaton/bsi/bibliography.rb +115 -43
- data/lib/relaton/bsi/hit.rb +14 -0
- data/lib/relaton/bsi/hit_collection.rb +15 -16
- data/lib/relaton/bsi/model/docidentifier.rb +99 -1
- data/lib/relaton/bsi/processor.rb +1 -0
- data/lib/relaton/calconnect/bibliography.rb +12 -14
- data/lib/relaton/calconnect/data_fetcher.rb +77 -9
- data/lib/relaton/calconnect/docidentifier.rb +80 -0
- data/lib/relaton/calconnect/hit_collection.rb +65 -57
- data/lib/relaton/calconnect/model/item.rb +7 -0
- data/lib/relaton/calconnect/processor.rb +7 -1
- data/lib/relaton/calconnect.rb +11 -1
- data/lib/relaton/ccsds/data/fetcher.rb +17 -12
- data/lib/relaton/ccsds/data/parser.rb +1 -1
- data/lib/relaton/ccsds/hit_collection.rb +6 -1
- data/lib/relaton/ccsds/model/docidentifier.rb +121 -0
- data/lib/relaton/ccsds/model/item.rb +2 -0
- data/lib/relaton/cen/bibliography.rb +75 -47
- data/lib/relaton/cen/hit.rb +16 -1
- data/lib/relaton/cen/hit_collection.rb +59 -11
- data/lib/relaton/cen/model/docidentifier.rb +92 -1
- data/lib/relaton/cen/processor.rb +13 -8
- data/lib/relaton/cen/scraper.rb +13 -5
- data/lib/relaton/cen.rb +1 -0
- data/lib/relaton/cie/data_fetcher.rb +215 -30
- data/lib/relaton/cie/processor.rb +3 -1
- data/lib/relaton/cie/scrapper.rb +15 -2
- data/lib/relaton/cie.rb +2 -1
- data/lib/relaton/core/data_fetcher.rb +150 -3
- data/lib/relaton/core/governor.rb +320 -0
- data/lib/relaton/core/pacer.rb +134 -0
- data/lib/relaton/core/processor.rb +19 -0
- data/lib/relaton/core/request_error.rb +14 -0
- data/lib/relaton/core.rb +3 -0
- data/lib/relaton/db/registry.rb +41 -1
- data/lib/relaton/doi/crossref.rb +19 -2
- data/lib/relaton/doi/parser.rb +109 -15
- data/lib/relaton/easc/bibdata.rb +8 -0
- data/lib/relaton/easc/bibitem.rb +8 -0
- data/lib/relaton/easc/bibliography.rb +95 -0
- data/lib/relaton/easc/docidentifier.rb +100 -0
- data/lib/relaton/easc/doctype.rb +14 -0
- data/lib/relaton/easc/ext.rb +44 -0
- data/lib/relaton/easc/item.rb +13 -0
- data/lib/relaton/easc/item_base.rb +18 -0
- data/lib/relaton/easc/item_data.rb +6 -0
- data/lib/relaton/easc/processor.rb +46 -0
- data/lib/relaton/easc/util.rb +8 -0
- data/lib/relaton/easc.rb +35 -0
- data/lib/relaton/ecma/bibliography.rb +93 -25
- data/lib/relaton/ecma/data_fetcher.rb +71 -12
- data/lib/relaton/ecma/docidentifier.rb +124 -0
- data/lib/relaton/ecma/item.rb +2 -0
- data/lib/relaton/ecma/memento_parser.rb +1 -1
- data/lib/relaton/ecma/page_fetcher.rb +15 -3
- data/lib/relaton/ecma/parser_common.rb +2 -2
- data/lib/relaton/ecma/processor.rb +4 -1
- data/lib/relaton/ecma/standard_parser.rb +2 -2
- data/lib/relaton/ecma.rb +10 -1
- data/lib/relaton/etsi/bibliography.rb +67 -2
- data/lib/relaton/etsi/data_fetcher.rb +43 -4
- data/lib/relaton/etsi/processor.rb +3 -1
- data/lib/relaton/etsi.rb +2 -1
- data/lib/relaton/gb/bibliography.rb +55 -29
- data/lib/relaton/gb/docidentifier.rb +58 -9
- data/lib/relaton/gb/processor.rb +3 -0
- data/lib/relaton/gb/scraper.rb +27 -10
- data/lib/relaton/gost/bibdata.rb +8 -0
- data/lib/relaton/gost/bibitem.rb +8 -0
- data/lib/relaton/gost/bibliography.rb +107 -0
- data/lib/relaton/gost/docidentifier.rb +80 -0
- data/lib/relaton/gost/doctype.rb +16 -0
- data/lib/relaton/gost/ext.rb +46 -0
- data/lib/relaton/gost/item.rb +15 -0
- data/lib/relaton/gost/item_base.rb +18 -0
- data/lib/relaton/gost/item_data.rb +6 -0
- data/lib/relaton/gost/processor.rb +49 -0
- data/lib/relaton/gost/util.rb +8 -0
- data/lib/relaton/gost.rb +36 -0
- data/lib/relaton/iala/bibdata.rb +8 -0
- data/lib/relaton/iala/bibitem.rb +8 -0
- data/lib/relaton/iala/bibliography.rb +146 -0
- data/lib/relaton/iala/docidentifier.rb +89 -0
- data/lib/relaton/iala/doctype.rb +18 -0
- data/lib/relaton/iala/ext.rb +32 -0
- data/lib/relaton/iala/item.rb +21 -0
- data/lib/relaton/iala/item_base.rb +18 -0
- data/lib/relaton/iala/item_data.rb +6 -0
- data/lib/relaton/iala/processor.rb +43 -0
- data/lib/relaton/iala/relation.rb +7 -0
- data/lib/relaton/iala/util.rb +8 -0
- data/lib/relaton/iala.rb +35 -0
- data/lib/relaton/iana/bibliography.rb +67 -14
- data/lib/relaton/iana/data_fetcher.rb +35 -5
- data/lib/relaton/iana/processor.rb +3 -1
- data/lib/relaton/iana.rb +12 -1
- data/lib/relaton/iec/data_fetcher.rb +7 -1
- data/lib/relaton/iec/hit_collection.rb +1 -1
- data/lib/relaton/iec/model/docidentifier.rb +9 -5
- data/lib/relaton/iec/model/ext.rb +2 -2
- data/lib/relaton/iec/processor.rb +1 -0
- data/lib/relaton/ieee/bibliography.rb +25 -3
- data/lib/relaton/ieee/data_fetcher.rb +158 -17
- data/lib/relaton/ieee/idams_parser.rb +18 -11
- data/lib/relaton/ieee/processor.rb +4 -1
- data/lib/relaton/ieee/rawbib_id_parser.rb +291 -86
- data/lib/relaton/ieee.rb +2 -1
- data/lib/relaton/ietf/data_fetcher.rb +295 -12
- data/lib/relaton/ietf/processor.rb +7 -3
- data/lib/relaton/ietf/rfc/entry.rb +39 -3
- data/lib/relaton/ietf/scraper.rb +69 -36
- data/lib/relaton/ietf.rb +4 -1
- data/lib/relaton/iho/bibliography.rb +1 -1
- data/lib/relaton/iho/docidentifier.rb +1 -1
- data/lib/relaton/index/file_io.rb +11 -11
- data/lib/relaton/index/file_storage.rb +6 -1
- data/lib/relaton/index/pool.rb +6 -1
- data/lib/relaton/index/shard_source.rb +201 -0
- data/lib/relaton/index/type.rb +63 -12
- data/lib/relaton/index.rb +2 -1
- data/lib/relaton/iso/bibliography.rb +20 -15
- data/lib/relaton/iso/data_fetcher.rb +3 -3
- data/lib/relaton/iso/data_parser.rb +17 -3
- data/lib/relaton/iso/hit_collection.rb +27 -15
- data/lib/relaton/iso/item_data.rb +22 -0
- data/lib/relaton/iso/model/docidentifier.rb +24 -12
- data/lib/relaton/iso/processor.rb +1 -0
- data/lib/relaton/iso/scraper.rb +19 -3
- data/lib/relaton/itu/bibliography.rb +9 -4
- data/lib/relaton/itu/data_crawler_r.rb +664 -0
- data/lib/relaton/itu/data_fetcher.rb +496 -50
- data/lib/relaton/itu/data_merge_r.rb +149 -0
- data/lib/relaton/itu/data_parser_r.rb +163 -89
- data/lib/relaton/itu/data_parser_t.rb +228 -0
- data/lib/relaton/itu/family_cache.rb +177 -0
- data/lib/relaton/itu/governor.rb +56 -0
- data/lib/relaton/itu/hit.rb +9 -3
- data/lib/relaton/itu/hit_collection.rb +258 -86
- data/lib/relaton/itu/model/docidentifier.rb +67 -1
- data/lib/relaton/itu/model/structured_identifier.rb +19 -0
- data/lib/relaton/itu/processor.rb +10 -4
- data/lib/relaton/itu/pubid.rb +27 -5
- data/lib/relaton/itu/recommendation_fields.rb +334 -0
- data/lib/relaton/itu/recommendation_parser.rb +18 -149
- data/lib/relaton/itu/scraper.rb +13 -3
- data/lib/relaton/itu.rb +2 -1
- data/lib/relaton/jcgm/bibdata.rb +8 -0
- data/lib/relaton/jcgm/bibitem.rb +8 -0
- data/lib/relaton/jcgm/bibliography.rb +97 -0
- data/lib/relaton/jcgm/data_fetcher.rb +81 -0
- data/lib/relaton/jcgm/docidentifier.rb +102 -0
- data/lib/relaton/jcgm/doctype.rb +12 -0
- data/lib/relaton/jcgm/ext.rb +23 -0
- data/lib/relaton/jcgm/item.rb +20 -0
- data/lib/relaton/jcgm/item_base.rb +18 -0
- data/lib/relaton/jcgm/item_data.rb +6 -0
- data/lib/relaton/jcgm/meetings_parser.rb +175 -0
- data/lib/relaton/jcgm/processor.rb +71 -0
- data/lib/relaton/jcgm/relation.rb +9 -0
- data/lib/relaton/jcgm/structured_identifier.rb +40 -0
- data/lib/relaton/jcgm/util.rb +8 -0
- data/lib/relaton/jcgm.rb +24 -0
- data/lib/relaton/jis/bibliography.rb +8 -10
- data/lib/relaton/jis/data_fetcher.rb +21 -19
- data/lib/relaton/jis/docidentifier.rb +104 -5
- data/lib/relaton/jis/hit.rb +18 -23
- data/lib/relaton/jis/hit_collection.rb +19 -18
- data/lib/relaton/jis/processor.rb +1 -1
- data/lib/relaton/jis.rb +2 -3
- data/lib/relaton/logger/channels/gh_issue.rb +78 -13
- data/lib/relaton/nist/data_fetcher.rb +63 -13
- data/lib/relaton/nist/docidentifier.rb +165 -0
- data/lib/relaton/nist/item.rb +2 -0
- data/lib/relaton/nist/item_base.rb +16 -0
- data/lib/relaton/nist/mods_parser.rb +38 -12
- data/lib/relaton/nist/processor.rb +2 -1
- data/lib/relaton/nist/relation.rb +3 -0
- data/lib/relaton/nist/scraper.rb +6 -3
- data/lib/relaton/oasis/bibliography.rb +147 -6
- data/lib/relaton/oasis/data_fetcher.rb +41 -5
- data/lib/relaton/oasis/data_parser_utils.rb +37 -3
- data/lib/relaton/oasis/docidentifier.rb +54 -0
- data/lib/relaton/oasis/item.rb +3 -0
- data/lib/relaton/oasis/processor.rb +7 -1
- data/lib/relaton/oasis.rb +14 -1
- data/lib/relaton/ogc/data_fetcher.rb +23 -2
- data/lib/relaton/ogc/docidentifier.rb +105 -0
- data/lib/relaton/ogc/hit_collection.rb +78 -3
- data/lib/relaton/ogc/processor.rb +2 -1
- data/lib/relaton/ogc.rb +5 -1
- data/lib/relaton/oiml/bibliography.rb +90 -15
- data/lib/relaton/oiml/docidentifier.rb +18 -3
- data/lib/relaton/omg/docidentifier.rb +67 -0
- data/lib/relaton/omg/item.rb +1 -0
- data/lib/relaton/omg/processor.rb +1 -0
- data/lib/relaton/omg/scraper.rb +61 -16
- data/lib/relaton/omg.rb +1 -0
- data/lib/relaton/plateau/bibliography.rb +10 -3
- data/lib/relaton/plateau/data_fetcher.rb +25 -2
- data/lib/relaton/plateau/handbook_parser.rb +8 -1
- data/lib/relaton/plateau/hit.rb +10 -2
- data/lib/relaton/plateau/hit_collection.rb +31 -11
- data/lib/relaton/plateau/processor.rb +3 -1
- data/lib/relaton/plateau/technical_report_parser.rb +8 -1
- data/lib/relaton/plateau.rb +2 -1
- data/lib/relaton/sdo/config.rb +34 -0
- data/lib/relaton/sdo/fetcher.rb +52 -0
- data/lib/relaton/sdo/logo.rb +95 -0
- data/lib/relaton/sdo/name.rb +26 -0
- data/lib/relaton/sdo/organization.rb +71 -0
- data/lib/relaton/sdo/store.rb +49 -0
- data/lib/relaton/sdo.rb +29 -0
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/w3c/bibliography.rb +132 -12
- data/lib/relaton/w3c/data_fetcher.rb +194 -16
- data/lib/relaton/w3c/data_parser.rb +3 -3
- data/lib/relaton/w3c/docidentifier.rb +48 -0
- data/lib/relaton/w3c/governor.rb +32 -0
- data/lib/relaton/w3c/item.rb +3 -0
- data/lib/relaton/w3c/pubid.rb +12 -0
- data/lib/relaton/w3c/safe_realize.rb +110 -21
- data/lib/relaton/w3c.rb +12 -1
- data/lib/relaton/xsf/bibliography.rb +61 -1
- data/lib/relaton/xsf/data_fetcher.rb +55 -5
- data/lib/relaton/xsf/docidentifier.rb +46 -0
- data/lib/relaton/xsf/hit_collection.rb +31 -3
- data/lib/relaton/xsf/item.rb +6 -0
- data/lib/relaton/xsf/processor.rb +1 -0
- data/lib/relaton/xsf.rb +5 -1
- data/lib/relaton.rb +42 -0
- metadata +135 -24
- data/lib/relaton/ieee/pub_id.rb +0 -161
- data/lib/relaton/index/id_number.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37fab215eeedb21350f3e195a6a803d47680d35f75767d782600312cef05fa8e
|
|
4
|
+
data.tar.gz: c4542c9253678a25c5656f213ca39e12689bef778f816b70a383333c0db422d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd5901f08f8b7c4359598dc38eaa65411679884c4c860350b8b129943fa366a13dcb3f0bf91048a9922d199b364caeaf4f320cdc059898f78a5f8088364b30cd
|
|
7
|
+
data.tar.gz: ccc9c3ce79b02416dd0a0c31a8dab36fe13da7556e9812ed5d403d66bcdc1c4ecb938d766f2376148315e4c0c3590e243c1ef5c5e97488df8a526df934df3af3
|
data/README.adoc
CHANGED
|
@@ -6,7 +6,8 @@ image:https://github.com/relaton/relaton/actions/workflows/rake.yml/badge.svg["B
|
|
|
6
6
|
Gem for importing and caching bibliographic references to technical standards.
|
|
7
7
|
Every standards-body flavor ships inside this single gem; flavor code loads on
|
|
8
8
|
demand via `autoload`, and the `Relaton::Db` API routes a reference to the right
|
|
9
|
-
flavor by its prefix. The command-line interface,
|
|
9
|
+
flavor by its prefix. The command-line interface,
|
|
10
|
+
link:gems/relaton-cli/docs/README.adoc[`relaton-cli`], is a separate gem.
|
|
10
11
|
|
|
11
12
|
== Installation
|
|
12
13
|
|
|
@@ -420,6 +421,56 @@ db.load_entry("ISO(ISO 19011)")
|
|
|
420
421
|
=> nil
|
|
421
422
|
----
|
|
422
423
|
|
|
424
|
+
== Organization metadata
|
|
425
|
+
|
|
426
|
+
Besides bibliographic references, Relaton exposes a lightweight store of
|
|
427
|
+
standards-development-organization (SDO) metadata: an organization's names (with
|
|
428
|
+
translations) and its logos. This is a separate, non-flavor concern -- it does
|
|
429
|
+
not go through `Relaton::Db` -- reached through the top-level
|
|
430
|
+
`Relaton.organization` method.
|
|
431
|
+
|
|
432
|
+
The data (names, translations and logo variants) is served as an `index.yaml`
|
|
433
|
+
manifest by the https://github.com/relaton/relaton-data-sdo[`relaton-data-sdo`]
|
|
434
|
+
data repository, downloaded on first use and cached under `~/.relaton/sdo`.
|
|
435
|
+
|
|
436
|
+
[source,ruby]
|
|
437
|
+
----
|
|
438
|
+
org = Relaton.organization("ISO") # case-insensitive; nil if unknown
|
|
439
|
+
|
|
440
|
+
# Names (relaton-db#132) -- default, or a translation by language code
|
|
441
|
+
# (passed positionally or as the language: keyword)
|
|
442
|
+
org.name # => "International Organization for Standardization"
|
|
443
|
+
org.name("fr") # => "Organisation internationale de normalisation"
|
|
444
|
+
org.name(language: "fr") # => "Organisation internationale de normalisation"
|
|
445
|
+
|
|
446
|
+
# Logos (metanorma#346). A single organization can have several logo variants,
|
|
447
|
+
# distinguished by style (the primary discriminator), format and size.
|
|
448
|
+
# All arguments are optional; omitting one matches any value.
|
|
449
|
+
org.logo_query(format: "eps", size: "700x300", style: "default")
|
|
450
|
+
# => [#<Relaton::Sdo::Logo style="default" format="eps" size="700x300" url=...>, ...]
|
|
451
|
+
|
|
452
|
+
org.logo_query # => every logo variant for the organization
|
|
453
|
+
|
|
454
|
+
# Fetch one logo. Returns nil if nothing matches, the sole match if one does,
|
|
455
|
+
# and raises Relaton::Sdo::Error if the filter is ambiguous.
|
|
456
|
+
logo = org.logo(format: "eps", style: "default")
|
|
457
|
+
logo.content # raw binary content (fetched lazily, memoized)
|
|
458
|
+
logo.data_uri # "data:application/postscript;base64,..." -- ready to embed
|
|
459
|
+
logo.save # write to a filename derived from the URL; returns the path
|
|
460
|
+
logo.save("/tmp/iso.eps") # ...or to a custom path
|
|
461
|
+
----
|
|
462
|
+
|
|
463
|
+
The store is configurable -- the manifest URL, the cache directory, a swappable
|
|
464
|
+
storage backend (e.g. an S3-backed object), and the cache TTL:
|
|
465
|
+
|
|
466
|
+
[source,ruby]
|
|
467
|
+
----
|
|
468
|
+
Relaton::Sdo.configure do |config|
|
|
469
|
+
config.url = "https://example.org/my-index.yaml"
|
|
470
|
+
config.storage_dir = "/var/cache/relaton-sdo"
|
|
471
|
+
end
|
|
472
|
+
----
|
|
473
|
+
|
|
423
474
|
== Layout
|
|
424
475
|
|
|
425
476
|
----
|
|
@@ -430,6 +481,7 @@ lib/
|
|
|
430
481
|
├── version.rb # Relaton::VERSION — the single source of truth
|
|
431
482
|
├── db.rb, db/ # Relaton::Db: registry, cache, workers pool
|
|
432
483
|
├── core/ bib/ index/ logger/ # shared infrastructure
|
|
484
|
+
├── sdo/ # Relaton.organization: SDO org/logo store (non-flavor)
|
|
433
485
|
└── iso/ iec/ ietf/ … 3gpp/ # ~29 flavor plugins
|
|
434
486
|
spec/<flavor>/ # each flavor's spec suite
|
|
435
487
|
grammar/ # shared RelaxNG test schemas (test-only, not shipped)
|
|
@@ -480,6 +532,10 @@ link:lib/relaton/core/README.adoc[core],
|
|
|
480
532
|
link:lib/relaton/index/README.adoc[index],
|
|
481
533
|
link:lib/relaton/logger/README.adoc[logger].
|
|
482
534
|
|
|
535
|
+
Maintaining your own dataset? See
|
|
536
|
+
link:docs/data-repository-format.adoc[Relaton data repository format] for the
|
|
537
|
+
repository layout, index file specification, and GitHub Pages publishing contract.
|
|
538
|
+
|
|
483
539
|
|
|
484
540
|
== Development
|
|
485
541
|
|
data/bin/console
CHANGED
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
module Relaton
|
|
4
4
|
module ThreeGpp
|
|
5
|
-
# Methods for search
|
|
5
|
+
# Methods for search 3GPP standards.
|
|
6
6
|
module Bibliography
|
|
7
7
|
SOURCE = "https://raw.githubusercontent.com/relaton/relaton-data-3gpp/v2/"
|
|
8
8
|
|
|
9
9
|
# @param text [String]
|
|
10
|
-
# @return [
|
|
11
|
-
def search(text)
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
# @return [Relaton::ThreeGpp::ItemData, nil]
|
|
11
|
+
def search(text)
|
|
12
|
+
# An unrecognized reference raises; like ISO and ETSI we let it
|
|
13
|
+
# propagate — relaton-cli rescues Pubid::Errors::Error and renders
|
|
14
|
+
# "… is not a recognized standards identifier", and API callers rescue
|
|
15
|
+
# it themselves. The rescue below lists transport errors only, so it
|
|
16
|
+
# does not swallow the parse error.
|
|
17
|
+
pubid = ::Pubid::Tgpp::Identifier.parse text.to_s.strip
|
|
18
|
+
row = best_match pubid
|
|
14
19
|
return unless row
|
|
15
20
|
|
|
16
21
|
url = "#{SOURCE}#{row[:file]}"
|
|
@@ -26,10 +31,10 @@ module Relaton
|
|
|
26
31
|
raise Relaton::RequestError, e.message
|
|
27
32
|
end
|
|
28
33
|
|
|
29
|
-
# @param ref [String] the
|
|
34
|
+
# @param ref [String] the 3GPP standard Code to look up
|
|
30
35
|
# @param year [String, NilClass] not used
|
|
31
36
|
# @param opts [Hash] options
|
|
32
|
-
# @return [
|
|
37
|
+
# @return [Relaton::ThreeGpp::ItemData, nil]
|
|
33
38
|
def get(ref, _year = nil, _opts = {})
|
|
34
39
|
Util.info "Fetching from Relaton repository ...", key: ref
|
|
35
40
|
result = search(ref)
|
|
@@ -42,6 +47,76 @@ module Relaton
|
|
|
42
47
|
result
|
|
43
48
|
end
|
|
44
49
|
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Find the index row for a reference, newest version first.
|
|
54
|
+
#
|
|
55
|
+
# Passing the pubid to `Index::Type#search` is what enables the binary
|
|
56
|
+
# search on `id.root.number` — `Type#search_candidates` narrows only when
|
|
57
|
+
# its argument is NOT a String, so the plain text this used to pass
|
|
58
|
+
# disabled the narrowing however the index was built. With 88,464 rows in
|
|
59
|
+
# 3,767 number buckets that is the whole point of the index-v2 migration.
|
|
60
|
+
#
|
|
61
|
+
# The rows are selected with pubid's subset match `pubid === row`, the
|
|
62
|
+
# default of `Index::Type#search`. `release` and `version` are 3GPP's
|
|
63
|
+
# only optional components: when the reference omits one, it matches
|
|
64
|
+
# any value, so a bare `3GPP TS 23.207` still finds the `REL-19/19.0.0`
|
|
65
|
+
# row. pubid declares `suffix` and `parts` strict for 3GPP, because they
|
|
66
|
+
# are part of the document code (`TS 29.198-04-1`, `TR 00.01U`), not
|
|
67
|
+
# qualifiers. The document type is the identifier's class, and `===`
|
|
68
|
+
# requires the same class, so `TS 23.207` and `TR 23.207` never match.
|
|
69
|
+
#
|
|
70
|
+
# @param pubid [::Pubid::Tgpp::Identifier]
|
|
71
|
+
# @return [Hash, nil] the winning index row (`{ id:, file: }`)
|
|
72
|
+
#
|
|
73
|
+
def best_match(pubid)
|
|
74
|
+
index.search(pubid)
|
|
75
|
+
.max_by { |r| [version_key(r[:id].version), r[:id].to_s, r[:file]] }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Order key for a 3GPP version — the highest version wins.
|
|
80
|
+
#
|
|
81
|
+
# Versions are dotted strings, so they must be compared segment by
|
|
82
|
+
# segment as integers rather than as text: `19.0.0` is newer than
|
|
83
|
+
# `4.0.0` but loses as a string. This is a deliberate behaviour change.
|
|
84
|
+
# The previous key, `min_by { r[:id] }` over raw strings, returned
|
|
85
|
+
# `REL-10/10.0.0` for `3GPP TS 23.207` — neither the newest nor the
|
|
86
|
+
# oldest of its 37 rows, just whichever sorted first as text. Scored
|
|
87
|
+
# against each document's own publication date over 870 documents in 59
|
|
88
|
+
# multi-row groups, this key picks the newest published document 51/59
|
|
89
|
+
# (86%) of the time; the old one managed 1/59 (2%).
|
|
90
|
+
#
|
|
91
|
+
# No release key is layered on top. Ranking releases numerically is wrong
|
|
92
|
+
# (the chronological order is Ph1, Ph2, REL-96 … REL-99, Release 2000,
|
|
93
|
+
# UMTS, REL-4 … REL-21, so REL-99 would outrank REL-19) and a
|
|
94
|
+
# hand-maintained 27-token table would disagree with this key on only 9
|
|
95
|
+
# of 3,982 multi-row groups — all draft TRs carried into a later release
|
|
96
|
+
# at a lower version, where the release answer is not clearly better.
|
|
97
|
+
#
|
|
98
|
+
# An absent version sorts below every present one. Ties break on the
|
|
99
|
+
# rendered id and then the file path, because the index sort is not
|
|
100
|
+
# stable.
|
|
101
|
+
#
|
|
102
|
+
# @param version [String, nil]
|
|
103
|
+
# @return [Array<Integer>]
|
|
104
|
+
#
|
|
105
|
+
def version_key(version)
|
|
106
|
+
version.to_s.split(".").map(&:to_i)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The index is pubid-backed: `pubid_class:` is what makes Relaton::Index
|
|
110
|
+
# deserialize the rows into identifiers, sort them by `id.root.number`,
|
|
111
|
+
# and let `Type#search` bsearch. Without it the rows stay raw hashes,
|
|
112
|
+
# `FileIO#sorted` stays false, and every lookup scans all 88,464 of them.
|
|
113
|
+
def index
|
|
114
|
+
Relaton::Index.find_or_create(
|
|
115
|
+
"3GPP", url: "#{SOURCE}#{INDEXFILE}.zip", file: "#{INDEXFILE}.yaml",
|
|
116
|
+
pubid_class: ::Pubid::Tgpp::Identifier
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
45
120
|
extend Bibliography
|
|
46
121
|
end
|
|
47
122
|
end
|
|
@@ -14,8 +14,16 @@ module Relaton
|
|
|
14
14
|
Util.error msg
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
# The index is pubid-backed: `pubid_class:` makes Relaton::Index sort the
|
|
18
|
+
# rows by `id.root.number` on save and serialize each id to its
|
|
19
|
+
# `_type: pubid:3gpp:*` hash. Without it a v1-shaped file would be
|
|
20
|
+
# written under a v2 name, with no error and no narrowing — FileIO#save
|
|
21
|
+
# only calls `to_hash` when the value is an instance of `pubid_class`.
|
|
17
22
|
def index
|
|
18
|
-
@index ||= Relaton::Index.find_or_create
|
|
23
|
+
@index ||= Relaton::Index.find_or_create(
|
|
24
|
+
"3gpp", file: "#{INDEXFILE}.yaml",
|
|
25
|
+
pubid_class: ::Pubid::Tgpp::Identifier
|
|
26
|
+
)
|
|
19
27
|
end
|
|
20
28
|
|
|
21
29
|
#
|
|
@@ -104,17 +112,57 @@ module Relaton
|
|
|
104
112
|
return unless bib
|
|
105
113
|
|
|
106
114
|
bib1 = bib
|
|
107
|
-
|
|
115
|
+
# A DISTINCT docnumber that sanitizes to the same filename must not be
|
|
116
|
+
# merged into the other document — give it a path of its own. Only a
|
|
117
|
+
# genuine duplicate (same docnumber, same path) still merges.
|
|
118
|
+
file = unique_output_file(bib1.docnumber)
|
|
119
|
+
# A reserved path only ever belongs to one docnumber, so a hit here is
|
|
120
|
+
# the same document again and still merges. Checked FIRST: a
|
|
121
|
+
# disambiguated path stays != output_file forever, so gating the merge
|
|
122
|
+
# on that comparison would drop the merge enrichment on every repeat of
|
|
123
|
+
# a disambiguated docnumber.
|
|
108
124
|
if @files.include? file
|
|
109
125
|
bib1 = merge_duplication bib1, file
|
|
110
126
|
Util.warn "File #{file} already exists. Document: #{bib.docnumber}" if bib1.nil?
|
|
111
127
|
else
|
|
128
|
+
if file != output_file(bib1.docnumber)
|
|
129
|
+
Util.warn "File #{output_file bib1.docnumber} already exists. " \
|
|
130
|
+
"Document: #{bib.docnumber}. Writing #{file} instead."
|
|
131
|
+
end
|
|
112
132
|
@files << file
|
|
113
|
-
|
|
133
|
+
index_primary bib1.docidentifier&.detect(&:primary), file
|
|
114
134
|
end
|
|
115
135
|
File.write file, serialize(bib1), encoding: "UTF-8" unless bib1.nil?
|
|
116
136
|
end
|
|
117
137
|
|
|
138
|
+
#
|
|
139
|
+
# Add a document's primary id to the index.
|
|
140
|
+
#
|
|
141
|
+
# The pubid is already parsed on `Docidentifier`, so index it directly
|
|
142
|
+
# rather than re-parsing `docnumber`. `pubid.to_s` (no publisher token)
|
|
143
|
+
# reproduces the `docnumber` string this used to store byte-for-byte, so
|
|
144
|
+
# the index key does not move; `docnumber` still names the output file.
|
|
145
|
+
#
|
|
146
|
+
# An id pubid cannot rebuild is recorded in `@errors` — the inherited
|
|
147
|
+
# `report_errors` logs a String value as the message — and the row is
|
|
148
|
+
# skipped rather than indexed unparsed: `Relaton::Index` rejects the
|
|
149
|
+
# WHOLE index if a single row fails to deserialize, and its sort calls
|
|
150
|
+
# `.root.number` on every id. The data file is still written, so the
|
|
151
|
+
# document is unindexed, never lost. (The W3C precedent.)
|
|
152
|
+
#
|
|
153
|
+
# @param [Docidentifier, nil] docid the document's primary identifier
|
|
154
|
+
# @param [String] file path the document was written to
|
|
155
|
+
#
|
|
156
|
+
def index_primary(docid, file)
|
|
157
|
+
if docid&.pubid
|
|
158
|
+
index.add_or_update docid.pubid, file
|
|
159
|
+
return
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
id = docid&.content || file
|
|
163
|
+
@errors[id.to_s] = "Unparseable primary id `#{id}` was not indexed (#{file})"
|
|
164
|
+
end
|
|
165
|
+
|
|
118
166
|
#
|
|
119
167
|
# Merge duplication
|
|
120
168
|
#
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module Relaton
|
|
2
|
+
module ThreeGpp
|
|
3
|
+
# Structured 3GPP document identifier. `content` stays the canonical string
|
|
4
|
+
# (e.g. "3GPP TS 29.198-04-1:REL-5/5.0.0") and the parsed
|
|
5
|
+
# `Pubid::Tgpp::Identifier` is kept alongside it in `@pubid`.
|
|
6
|
+
#
|
|
7
|
+
# Without this subclass 3GPP items inherit `Bib::Docidentifier`, whose
|
|
8
|
+
# `remove_part!` / `remove_date!` / `to_all_parts!` all raise
|
|
9
|
+
# NotImplementedError — so `ItemData#to_all_parts` and
|
|
10
|
+
# `#to_most_recent_reference`, which broadcast to every docidentifier,
|
|
11
|
+
# raised on every 3GPP item.
|
|
12
|
+
class Docidentifier < Bib::Docidentifier
|
|
13
|
+
attr_reader :pubid
|
|
14
|
+
|
|
15
|
+
# Capture the inherited (LocalizedMarkedUpString) content setter before
|
|
16
|
+
# overriding #content=, so #refresh_content! can write the re-rendered
|
|
17
|
+
# string back WITHOUT re-parsing (a re-parse would rebuild @pubid from
|
|
18
|
+
# the string and discard the in-place mutations just made).
|
|
19
|
+
alias_method :store_content, :content=
|
|
20
|
+
|
|
21
|
+
def initialize(attrs = {}, options = {})
|
|
22
|
+
pubid = attrs.is_a?(Hash) ? attrs.delete(:pubid) : nil
|
|
23
|
+
attrs[:content] ||= render(pubid) if pubid
|
|
24
|
+
super
|
|
25
|
+
@pubid = pubid if pubid
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def content=(value)
|
|
29
|
+
super
|
|
30
|
+
return unless value
|
|
31
|
+
|
|
32
|
+
@pubid = begin
|
|
33
|
+
# Rescue LoadError so a missing pubid gem degrades to a plain string,
|
|
34
|
+
# and StandardError so non-3GPP or unparseable content just leaves
|
|
35
|
+
# @pubid nil rather than raising. Deserialization reaches this setter
|
|
36
|
+
# without the flavor entry file necessarily having been loaded, hence
|
|
37
|
+
# the local require.
|
|
38
|
+
require "pubid"
|
|
39
|
+
::Pubid::Tgpp::Identifier.parse(value.to_s)
|
|
40
|
+
rescue LoadError, StandardError
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# `Pubid::Tgpp::Identifier` models number/suffix/parts/release/version.
|
|
46
|
+
# It has no date, and `suffix` is folded into the document code, so:
|
|
47
|
+
#
|
|
48
|
+
# * #remove_part! clears `parts` — a real, separable component here
|
|
49
|
+
# (unlike IALA's, which is a no-op): "TS 29.198-04-1" -> "TS 29.198".
|
|
50
|
+
# * #remove_date! clears `release` AND `version`. 3GPP carries no date;
|
|
51
|
+
# those two are its version discriminators — the same pair
|
|
52
|
+
# `Bibliography#ignored` treats as omittable — so clearing both gives
|
|
53
|
+
# the version-agnostic ("most recent") reference "TS 23.207".
|
|
54
|
+
# * #to_all_parts! does both, then wraps `@pubid` in pubid's `AllParts`.
|
|
55
|
+
# `content` stays the plain stripped id — the Tgpp renderer has no
|
|
56
|
+
# "(all parts)" marker, and `content` is cached from the pre-wrap
|
|
57
|
+
# pubid on purpose. `#pubid` itself, read directly, now answers
|
|
58
|
+
# `all_parts? == true` and renders WITH pubid's generic marker
|
|
59
|
+
# (`#to_s`), since it's the wrapper.
|
|
60
|
+
#
|
|
61
|
+
# All three no-op safely when @pubid is nil (parse failed, or the pubid
|
|
62
|
+
# gem is unavailable), so ItemData#to_all_parts and
|
|
63
|
+
# #to_most_recent_reference never raise on 3GPP items.
|
|
64
|
+
|
|
65
|
+
def remove_part!
|
|
66
|
+
clear_attrs! :parts
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def remove_date!
|
|
70
|
+
clear_attrs! :release, :version
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def to_all_parts!
|
|
74
|
+
return if !@pubid || @pubid.all_parts?
|
|
75
|
+
|
|
76
|
+
# `#exclude` (no args) rebuilds a full independent copy — `remove_part!`
|
|
77
|
+
# / `remove_date!` mutate `@pubid` in place, so a bare reference here
|
|
78
|
+
# would lose the original part/version to that mutation too.
|
|
79
|
+
original = @pubid.exclude
|
|
80
|
+
remove_part!
|
|
81
|
+
remove_date!
|
|
82
|
+
@pubid = original.to_all_parts
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def clear_attrs!(*attrs)
|
|
88
|
+
return unless @pubid
|
|
89
|
+
|
|
90
|
+
cleared = attrs.select { |attr| @pubid.respond_to?("#{attr}=") }
|
|
91
|
+
return if cleared.empty?
|
|
92
|
+
|
|
93
|
+
# `parts` is a collection: empty it rather than nil it, so #code keeps
|
|
94
|
+
# rendering through `parts.map` instead of tripping over nil.
|
|
95
|
+
cleared.each do |attr|
|
|
96
|
+
@pubid.public_send("#{attr}=", attr == :parts ? [] : nil)
|
|
97
|
+
end
|
|
98
|
+
refresh_content!
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def refresh_content!
|
|
102
|
+
store_content(render(@pubid)) if @pubid
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# `Pubid::Tgpp::Identifier#to_s` defaults to OMITTING the "3GPP " token —
|
|
106
|
+
# deliberately, so it reproduces the index id. The stored docidentifier
|
|
107
|
+
# content carries the prefix ("3GPP TS 23.207:REL-4/4.0.0"), so every
|
|
108
|
+
# render here must opt back in or a mutation would silently strip it.
|
|
109
|
+
def render(pubid)
|
|
110
|
+
pubid.to_s(with_publisher: true)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/relaton/3gpp/item.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative "item_data"
|
|
2
2
|
require_relative "ext"
|
|
3
|
+
require_relative "docidentifier"
|
|
3
4
|
|
|
4
5
|
module Relaton
|
|
5
6
|
module ThreeGpp
|
|
@@ -7,6 +8,11 @@ module Relaton
|
|
|
7
8
|
model ItemData
|
|
8
9
|
|
|
9
10
|
attribute :ext, Ext
|
|
11
|
+
# Shadow the Bib::Docidentifier declaration in Bib::ItemShared so items
|
|
12
|
+
# carry the pubid-backed 3GPP identifier. Bibitem and Bibdata subclass
|
|
13
|
+
# Item, so this one declaration covers all three.
|
|
14
|
+
attribute :docidentifier, Docidentifier, collection: true,
|
|
15
|
+
initialize_empty: true
|
|
10
16
|
end
|
|
11
17
|
end
|
|
12
18
|
end
|
data/lib/relaton/3gpp/parser.rb
CHANGED
|
@@ -94,7 +94,7 @@ module Relaton
|
|
|
94
94
|
#
|
|
95
95
|
def parse_docid
|
|
96
96
|
@errors[:docid] &&= @row[0].nil? || @row[0].empty?
|
|
97
|
-
[
|
|
97
|
+
[Docidentifier.new(type: "3GPP", content: "3GPP #{number}", primary: true)]
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
#
|
|
@@ -10,6 +10,7 @@ module Relaton
|
|
|
10
10
|
@prefix = "3GPP"
|
|
11
11
|
@defaultprefix = %r{^3GPP\s}
|
|
12
12
|
@idtype = "3GPP"
|
|
13
|
+
@pubid_flavor = :Tgpp # global prefixes sourced from Pubid::Tgpp.prefixes
|
|
13
14
|
@datasets = %w[status-smg-3GPP status-smg-3GPP-force]
|
|
14
15
|
end
|
|
15
16
|
|
|
@@ -61,7 +62,9 @@ module Relaton
|
|
|
61
62
|
#
|
|
62
63
|
def remove_index_file
|
|
63
64
|
require_relative "../3gpp"
|
|
64
|
-
Relaton::Index.find_or_create(
|
|
65
|
+
Relaton::Index.find_or_create(
|
|
66
|
+
"3GPP", url: true, file: "#{INDEXFILE}.yaml"
|
|
67
|
+
).remove_file
|
|
65
68
|
end
|
|
66
69
|
end
|
|
67
70
|
end
|
data/lib/relaton/3gpp.rb
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
require "net/http"
|
|
2
|
+
# pubid loads with the flavor, for the ::Pubid::Tgpp::Identifier that the
|
|
3
|
+
# index code names. Processor#remove_index_file names no pubid class: the
|
|
4
|
+
# delete never reads the index (see lib/relaton/index/CLAUDE.md).
|
|
5
|
+
require "pubid"
|
|
2
6
|
require "relaton/index"
|
|
3
7
|
require "relaton/core"
|
|
4
8
|
require "relaton/bib"
|
|
@@ -11,7 +15,7 @@ require_relative "3gpp/bibliography"
|
|
|
11
15
|
|
|
12
16
|
module Relaton
|
|
13
17
|
module ThreeGpp
|
|
14
|
-
INDEXFILE = "index-
|
|
18
|
+
INDEXFILE = "index-v2".freeze
|
|
15
19
|
|
|
16
20
|
# Returns hash of XML reammar
|
|
17
21
|
# @return [String]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Adobe
|
|
5
|
+
# Retrieval front-end for the Adobe flavor. Parses a reference with
|
|
6
|
+
# Pubid::Adobe, looks it up in the `relaton-data-adobe` index, fetches the
|
|
7
|
+
# matching YAML record, and deserializes it into a Relaton::Adobe::Item.
|
|
8
|
+
# Modelled on Relaton::Oiml::Bibliography (pubid-backed, index via
|
|
9
|
+
# `pubid_class`); adapted because Adobe identifiers carry no edition
|
|
10
|
+
# year/language, so there is no per-edition selection — each reference maps
|
|
11
|
+
# to a single record.
|
|
12
|
+
module Bibliography
|
|
13
|
+
ENDPOINT = "https://raw.githubusercontent.com/relaton/relaton-data-adobe/main/".freeze
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
# Search for an Adobe publication by its identifier.
|
|
17
|
+
#
|
|
18
|
+
# @param text [String, Pubid::Adobe::Identifier] the Adobe reference to
|
|
19
|
+
# look up (e.g. "Adobe Technical Note #5014", "ATN5014",
|
|
20
|
+
# "Adobe Publication adobe-glyph-list")
|
|
21
|
+
# @param _year [String, nil] unused (Adobe ids carry no edition year)
|
|
22
|
+
# @param _opts [Hash] options (unused)
|
|
23
|
+
# @return [Relaton::Adobe::Item, nil]
|
|
24
|
+
def search(text, _year = nil, _opts = {})
|
|
25
|
+
pubid = pubid_for(text) or return
|
|
26
|
+
Util.info "Fetching from Relaton repository ...", key: pubid.to_s
|
|
27
|
+
# Tech notes narrow by number via binary search; publications have no
|
|
28
|
+
# number, so pass nil to scan (Relaton::Index::Type#search returns all
|
|
29
|
+
# rows for a nil id, then applies the block).
|
|
30
|
+
query = pubid.root.number ? pubid : nil
|
|
31
|
+
row = index.search(query) { |r| pubid_match?(r[:id], pubid) }.first
|
|
32
|
+
unless row
|
|
33
|
+
Util.info "Not found.", key: pubid.to_s
|
|
34
|
+
return
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
uri = URI("#{ENDPOINT}#{row[:file]}")
|
|
38
|
+
resp = Net::HTTP.get_response uri
|
|
39
|
+
unless resp.code == "200"
|
|
40
|
+
raise Relaton::RequestError, "Could not access #{uri}: HTTP #{resp.code}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
item = Relaton::Adobe::Item.from_yaml resp.body
|
|
44
|
+
Util.info "Found: `#{item.docidentifier.first&.content}`", key: pubid.to_s
|
|
45
|
+
item.tap { |i| i.fetched = Date.today.to_s }
|
|
46
|
+
rescue SocketError, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
|
47
|
+
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
|
48
|
+
Net::ProtocolError, Net::ReadTimeout, OpenSSL::SSL::SSLError,
|
|
49
|
+
Errno::ETIMEDOUT => e
|
|
50
|
+
raise Relaton::RequestError, "Could not access #{uri}: #{e.message}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def get(ref, year = nil, opts = {})
|
|
54
|
+
search(ref, year, opts)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Coerce a reference to a Pubid::Adobe identifier. A non-canonical or
|
|
60
|
+
# non-Adobe string (e.g. a title-cased "Adobe Glyph List") is a graceful
|
|
61
|
+
# miss (logged, returns nil) rather than a raised Parslet error — the
|
|
62
|
+
# ref reached here only because it matched the flavor's prefix regex.
|
|
63
|
+
def pubid_for(text)
|
|
64
|
+
return text unless text.is_a?(String)
|
|
65
|
+
|
|
66
|
+
::Pubid::Adobe.parse(text)
|
|
67
|
+
rescue StandardError
|
|
68
|
+
Util.info "Not found.", key: text
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def index
|
|
73
|
+
Relaton::Index.find_or_create(
|
|
74
|
+
:adobe,
|
|
75
|
+
url: "#{ENDPOINT}#{INDEXFILE}.zip",
|
|
76
|
+
file: "#{INDEXFILE}.yaml",
|
|
77
|
+
pubid_class: ::Pubid::Adobe::Identifier,
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Identity match on the human render: pubid renders a tech note as
|
|
82
|
+
# `Adobe TN <n>` (dropping the filename slug, so `ATN5014` and
|
|
83
|
+
# `Adobe Technical Note #5014` both match a record stored with its slug)
|
|
84
|
+
# and a publication as `Adobe Publication <slug>` including its version.
|
|
85
|
+
# Both `row_id` and `query` are Pubid::Adobe identifiers.
|
|
86
|
+
def pubid_match?(row_id, query)
|
|
87
|
+
row_id.to_s == query.to_s
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Relaton
|
|
2
|
+
module Adobe
|
|
3
|
+
# Structured Adobe document identifier. The docid string is the canonical
|
|
4
|
+
# form (e.g. "Adobe TN 5014", "Adobe Publication adobe-glyph-list"); its
|
|
5
|
+
# `content` is soft-parsed into a Pubid::Adobe identifier kept in `@pubid`
|
|
6
|
+
# (a TechNote or Publication), mirroring Relaton::Oiml::Docidentifier.
|
|
7
|
+
#
|
|
8
|
+
# Parsing is soft: a non-Adobe or non-canonical string (e.g. a title-cased
|
|
9
|
+
# "Adobe Glyph List") leaves `@pubid` nil rather than raising, so the plain
|
|
10
|
+
# `content` string still round-trips.
|
|
11
|
+
class Docidentifier < Bib::Docidentifier
|
|
12
|
+
attr_reader :pubid
|
|
13
|
+
|
|
14
|
+
def initialize(attrs = {}, options = {})
|
|
15
|
+
pubid = attrs.is_a?(Hash) ? attrs.delete(:pubid) : nil
|
|
16
|
+
attrs[:content] ||= pubid.to_s if pubid
|
|
17
|
+
super
|
|
18
|
+
@pubid = pubid if pubid
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def content=(value)
|
|
22
|
+
super
|
|
23
|
+
@pubid = ::Pubid::Adobe.parse(value) if value
|
|
24
|
+
rescue StandardError
|
|
25
|
+
@pubid = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Adobe identifiers carry no part/date/all-parts component, so the base
|
|
29
|
+
# class's abstract mutation hooks (which otherwise raise NotImplementedError)
|
|
30
|
+
# are implemented as safe no-ops over the wrapped pubid: they keep
|
|
31
|
+
# `Bib::ItemData#to_most_recent_reference` / `#to_all_parts` from raising on
|
|
32
|
+
# Adobe items, and never change the rendered `content`.
|
|
33
|
+
def remove_part!
|
|
34
|
+
@pubid&.part = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def remove_date!
|
|
38
|
+
return unless @pubid
|
|
39
|
+
|
|
40
|
+
@pubid.date = nil
|
|
41
|
+
self.content = @pubid.to_s
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_all_parts!
|
|
45
|
+
@pubid &&= @pubid.to_all_parts
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Relaton
|
|
2
|
+
module Adobe
|
|
3
|
+
# Adobe publication document types. The value is carried in the
|
|
4
|
+
# inherited `content` attribute (e.g. `tech-note`, `publication`).
|
|
5
|
+
# The list mirrors the categories Adobe publishes through this
|
|
6
|
+
# dataset (font tech notes and named publications).
|
|
7
|
+
class Doctype < Bib::Doctype
|
|
8
|
+
TYPES = %w[
|
|
9
|
+
tech-note
|
|
10
|
+
publication
|
|
11
|
+
].freeze
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|