relaton 2.2.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/{docs/README.adoc → README.adoc} +165 -38
- data/bin/console +0 -1
- data/lib/relaton/3gpp/bibdata.rb +9 -0
- data/lib/relaton/3gpp/bibitem.rb +9 -0
- data/lib/relaton/3gpp/bibliography.rb +123 -0
- data/lib/relaton/3gpp/data_fetcher.rb +303 -0
- data/lib/relaton/3gpp/docidentifier.rb +114 -0
- data/lib/relaton/3gpp/doctype.rb +9 -0
- data/lib/relaton/3gpp/ext.rb +31 -0
- data/lib/relaton/3gpp/item.rb +18 -0
- data/lib/relaton/3gpp/item_data.rb +15 -0
- data/lib/relaton/3gpp/parser.rb +400 -0
- data/lib/relaton/3gpp/processor.rb +71 -0
- data/lib/relaton/3gpp/release.rb +34 -0
- data/lib/relaton/3gpp/util.rb +8 -0
- data/lib/relaton/3gpp.rb +29 -0
- 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/converter/asciibib/to_asciibib.rb +663 -0
- data/lib/relaton/bib/converter/asciibib.rb +13 -0
- data/lib/relaton/bib/converter/bibtex/from_bibtex.rb +245 -0
- data/lib/relaton/bib/converter/bibtex/to_bibtex.rb +341 -0
- data/lib/relaton/bib/converter/bibtex.rb +23 -0
- data/lib/relaton/bib/converter/bibxml/from_rfcxml.rb +386 -0
- data/lib/relaton/bib/converter/bibxml/from_rfcxml_referencegroup.rb +71 -0
- data/lib/relaton/bib/converter/bibxml/to_rfcxml.rb +308 -0
- data/lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup.rb +52 -0
- data/lib/relaton/bib/converter/bibxml.rb +51 -0
- data/lib/relaton/bib/hash_parser_v1.rb +767 -0
- data/lib/relaton/bib/item_data.rb +229 -0
- data/lib/relaton/bib/model/abstract.rb +16 -0
- data/lib/relaton/bib/model/address.rb +22 -0
- data/lib/relaton/bib/model/affiliation.rb +16 -0
- data/lib/relaton/bib/model/bibdata.rb +11 -0
- data/lib/relaton/bib/model/bibdata_shared.rb +12 -0
- data/lib/relaton/bib/model/bibitem.rb +11 -0
- data/lib/relaton/bib/model/bibitem_shared.rb +12 -0
- data/lib/relaton/bib/model/contact.rb +18 -0
- data/lib/relaton/bib/model/contribution_info.rb +15 -0
- data/lib/relaton/bib/model/contributor.rb +29 -0
- data/lib/relaton/bib/model/copyright.rb +27 -0
- data/lib/relaton/bib/model/date.rb +31 -0
- data/lib/relaton/bib/model/depiction.rb +16 -0
- data/lib/relaton/bib/model/docidentifier.rb +49 -0
- data/lib/relaton/bib/model/doctype.rb +14 -0
- data/lib/relaton/bib/model/edition.rb +14 -0
- data/lib/relaton/bib/model/ext.rb +39 -0
- data/lib/relaton/bib/model/extent.rb +16 -0
- data/lib/relaton/bib/model/formattedref.rb +43 -0
- data/lib/relaton/bib/model/full_name_type.rb +64 -0
- data/lib/relaton/bib/model/fullname.rb +11 -0
- data/lib/relaton/bib/model/ics.rb +49 -0
- data/lib/relaton/bib/model/image.rb +28 -0
- data/lib/relaton/bib/model/item.rb +96 -0
- data/lib/relaton/bib/model/item_base.rb +20 -0
- data/lib/relaton/bib/model/item_shared.rb +88 -0
- data/lib/relaton/bib/model/keyword.rb +30 -0
- data/lib/relaton/bib/model/locality.rb +18 -0
- data/lib/relaton/bib/model/locality_stack.rb +14 -0
- data/lib/relaton/bib/model/localized_string.rb +48 -0
- data/lib/relaton/bib/model/localized_string_attrs.rb +24 -0
- data/lib/relaton/bib/model/logo.rb +14 -0
- data/lib/relaton/bib/model/medium.rb +22 -0
- data/lib/relaton/bib/model/note.rb +16 -0
- data/lib/relaton/bib/model/organization.rb +13 -0
- data/lib/relaton/bib/model/organization_type.rb +42 -0
- data/lib/relaton/bib/model/person.rb +36 -0
- data/lib/relaton/bib/model/phone.rb +14 -0
- data/lib/relaton/bib/model/place.rb +33 -0
- data/lib/relaton/bib/model/price.rb +14 -0
- data/lib/relaton/bib/model/relation.rb +43 -0
- data/lib/relaton/bib/model/series.rb +34 -0
- data/lib/relaton/bib/model/size.rb +23 -0
- data/lib/relaton/bib/model/source_locality_stack.rb +14 -0
- data/lib/relaton/bib/model/status.rb +27 -0
- data/lib/relaton/bib/model/structured_identifier.rb +49 -0
- data/lib/relaton/bib/model/subdivision.rb +16 -0
- data/lib/relaton/bib/model/title.rb +56 -0
- data/lib/relaton/bib/model/type/plain_date.rb +16 -0
- data/lib/relaton/bib/model/type/string_date.rb +48 -0
- data/lib/relaton/bib/model/uri.rb +18 -0
- data/lib/relaton/bib/model/validity.rb +16 -0
- data/lib/relaton/bib/model/version.rb +43 -0
- data/lib/relaton/bib/namespace_helper.rb +21 -0
- data/lib/relaton/bib/sanitizer.rb +264 -0
- data/lib/relaton/bib/util.rb +18 -0
- data/lib/relaton/bib/versions.json +35 -0
- data/lib/relaton/bib.rb +46 -0
- data/lib/relaton/bipm/bibliography.rb +231 -0
- data/lib/relaton/bipm/converter/asciibib.rb +64 -0
- data/lib/relaton/bipm/data_fetcher.rb +81 -0
- data/lib/relaton/bipm/data_outcomes_parser.rb +656 -0
- data/lib/relaton/bipm/id_parser.rb +278 -0
- data/lib/relaton/bipm/item_data.rb +47 -0
- data/lib/relaton/bipm/model/bibdata.rb +9 -0
- data/lib/relaton/bipm/model/bibitem.rb +9 -0
- data/lib/relaton/bipm/model/comment_period.rb +13 -0
- data/lib/relaton/bipm/model/doctype.rb +12 -0
- data/lib/relaton/bipm/model/ext.rb +38 -0
- data/lib/relaton/bipm/model/item.rb +11 -0
- data/lib/relaton/bipm/model/structured_identifier.rb +36 -0
- data/lib/relaton/bipm/processor.rb +69 -0
- data/lib/relaton/bipm/rawdata_bipm_metrologia/affiliations.rb +111 -0
- data/lib/relaton/bipm/rawdata_bipm_metrologia/fetcher.rb +172 -0
- data/lib/relaton/bipm/rawdata_bipm_metrologia/niso_jats_parser.rb +353 -0
- data/lib/relaton/bipm/si_brochure_parser.rb +188 -0
- data/lib/relaton/bipm/util.rb +8 -0
- data/lib/relaton/bipm.rb +38 -0
- data/lib/relaton/bsi/bibliography.rb +196 -0
- data/lib/relaton/bsi/hit.rb +28 -0
- data/lib/relaton/bsi/hit_collection.rb +113 -0
- data/lib/relaton/bsi/item_data.rb +13 -0
- data/lib/relaton/bsi/model/bibdata.rb +8 -0
- data/lib/relaton/bsi/model/bibitem.rb +8 -0
- data/lib/relaton/bsi/model/docidentifier.rb +107 -0
- data/lib/relaton/bsi/model/doctype.rb +14 -0
- data/lib/relaton/bsi/model/ext.rb +17 -0
- data/lib/relaton/bsi/model/item.rb +17 -0
- data/lib/relaton/bsi/model/item_base.rb +22 -0
- data/lib/relaton/bsi/model/relation.rb +9 -0
- data/lib/relaton/bsi/processor.rb +43 -0
- data/lib/relaton/bsi/schema.json +24882 -0
- data/lib/relaton/bsi/scraper.rb +288 -0
- data/lib/relaton/bsi/util.rb +8 -0
- data/lib/relaton/bsi.rb +25 -0
- data/lib/relaton/calconnect/bibliography.rb +93 -0
- data/lib/relaton/calconnect/data_fetcher.rb +174 -0
- data/lib/relaton/calconnect/docidentifier.rb +80 -0
- data/lib/relaton/calconnect/hit.rb +14 -0
- data/lib/relaton/calconnect/hit_collection.rb +92 -0
- data/lib/relaton/calconnect/item_data.rb +12 -0
- data/lib/relaton/calconnect/model/bibdata.rb +8 -0
- data/lib/relaton/calconnect/model/bibitem.rb +8 -0
- data/lib/relaton/calconnect/model/doctype.rb +11 -0
- data/lib/relaton/calconnect/model/ext.rb +11 -0
- data/lib/relaton/calconnect/model/item.rb +20 -0
- data/lib/relaton/calconnect/processor.rb +72 -0
- data/lib/relaton/calconnect/scraper.rb +87 -0
- data/lib/relaton/calconnect/util.rb +8 -0
- data/lib/relaton/calconnect.rb +36 -0
- data/lib/relaton/ccsds/bibliography.rb +63 -0
- data/lib/relaton/ccsds/data/fetcher.rb +252 -0
- data/lib/relaton/ccsds/data/iso_references.rb +30 -0
- data/lib/relaton/ccsds/data/parser.rb +194 -0
- data/lib/relaton/ccsds/hit.rb +24 -0
- data/lib/relaton/ccsds/hit_collection.rb +47 -0
- data/lib/relaton/ccsds/item_data.rb +9 -0
- data/lib/relaton/ccsds/model/bibdata.rb +8 -0
- data/lib/relaton/ccsds/model/bibitem.rb +8 -0
- data/lib/relaton/ccsds/model/docidentifier.rb +121 -0
- data/lib/relaton/ccsds/model/doctype.rb +9 -0
- data/lib/relaton/ccsds/model/ext.rb +19 -0
- data/lib/relaton/ccsds/model/item.rb +15 -0
- data/lib/relaton/ccsds/processor.rb +68 -0
- data/lib/relaton/ccsds/util.rb +10 -0
- data/lib/relaton/ccsds.rb +33 -0
- data/lib/relaton/cen/bibliography.rb +149 -0
- data/lib/relaton/cen/committees.yaml +66 -0
- data/lib/relaton/cen/hit.rb +31 -0
- data/lib/relaton/cen/hit_collection.rb +116 -0
- data/lib/relaton/cen/item_data.rb +7 -0
- data/lib/relaton/cen/model/bibdata.rb +8 -0
- data/lib/relaton/cen/model/bibitem.rb +8 -0
- data/lib/relaton/cen/model/docidentifier.rb +100 -0
- data/lib/relaton/cen/model/ext.rb +11 -0
- data/lib/relaton/cen/model/item.rb +14 -0
- data/lib/relaton/cen/model/structured_identifier.rb +9 -0
- data/lib/relaton/cen/processor.rb +45 -0
- data/lib/relaton/cen/scraper.rb +218 -0
- data/lib/relaton/cen/util.rb +8 -0
- data/lib/relaton/cen.rb +30 -0
- data/lib/relaton/cie/bibdata.rb +8 -0
- data/lib/relaton/cie/bibitem.rb +8 -0
- data/lib/relaton/cie/bibliography.rb +31 -0
- data/lib/relaton/cie/data_fetcher.rb +540 -0
- data/lib/relaton/cie/ext.rb +7 -0
- data/lib/relaton/cie/item.rb +11 -0
- data/lib/relaton/cie/item_data.rb +6 -0
- data/lib/relaton/cie/processor.rb +68 -0
- data/lib/relaton/cie/scrapper.rb +52 -0
- data/lib/relaton/cie/util.rb +8 -0
- data/lib/relaton/cie.rb +29 -0
- data/lib/relaton/core/array_wrapper.rb +20 -0
- data/lib/relaton/core/data_fetcher.rb +244 -0
- data/lib/relaton/core/date_parser.rb +42 -0
- data/lib/relaton/core/governor.rb +320 -0
- data/lib/relaton/core/hash_keys_sybolizer.rb +19 -0
- data/lib/relaton/core/hit.rb +49 -0
- data/lib/relaton/core/hit_collection.rb +118 -0
- data/lib/relaton/core/pacer.rb +134 -0
- data/lib/relaton/core/processor.rb +67 -0
- data/lib/relaton/core/request_error.rb +14 -0
- data/lib/relaton/core/workers_pool.rb +45 -0
- data/lib/relaton/core.rb +12 -0
- data/lib/relaton/db/registry.rb +44 -4
- data/lib/relaton/db.rb +0 -1
- data/lib/relaton/doi/crossref.rb +89 -0
- data/lib/relaton/doi/parser.rb +921 -0
- data/lib/relaton/doi/processor.rb +65 -0
- data/lib/relaton/doi/util.rb +8 -0
- data/lib/relaton/doi.rb +20 -0
- 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/bibdata.rb +8 -0
- data/lib/relaton/ecma/bibitem.rb +8 -0
- data/lib/relaton/ecma/bibliography.rb +149 -0
- data/lib/relaton/ecma/data_fetcher.rb +162 -0
- data/lib/relaton/ecma/data_parser.rb +49 -0
- data/lib/relaton/ecma/docidentifier.rb +124 -0
- data/lib/relaton/ecma/edition_parser.rb +80 -0
- data/lib/relaton/ecma/ext.rb +7 -0
- data/lib/relaton/ecma/item.rb +13 -0
- data/lib/relaton/ecma/item_data.rb +6 -0
- data/lib/relaton/ecma/memento_parser.rb +60 -0
- data/lib/relaton/ecma/page_fetcher.rb +39 -0
- data/lib/relaton/ecma/parser_common.rb +33 -0
- data/lib/relaton/ecma/processor.rb +69 -0
- data/lib/relaton/ecma/standard_parser.rb +134 -0
- data/lib/relaton/ecma/util.rb +8 -0
- data/lib/relaton/ecma.rb +33 -0
- data/lib/relaton/etsi/bibdata.rb +10 -0
- data/lib/relaton/etsi/bibitem.rb +10 -0
- data/lib/relaton/etsi/bibliography.rb +111 -0
- data/lib/relaton/etsi/data_fetcher.rb +167 -0
- data/lib/relaton/etsi/data_parser.rb +208 -0
- data/lib/relaton/etsi/doctype.rb +30 -0
- data/lib/relaton/etsi/ext.rb +31 -0
- data/lib/relaton/etsi/item.rb +15 -0
- data/lib/relaton/etsi/item_data.rb +6 -0
- data/lib/relaton/etsi/processor.rb +71 -0
- data/lib/relaton/etsi/pubid.rb +37 -0
- data/lib/relaton/etsi/status.rb +13 -0
- data/lib/relaton/etsi/util.rb +8 -0
- data/lib/relaton/etsi.rb +26 -0
- data/lib/relaton/gb/bibdata.rb +8 -0
- data/lib/relaton/gb/bibitem.rb +8 -0
- data/lib/relaton/gb/bibliography.rb +171 -0
- data/lib/relaton/gb/ccs.rb +14 -0
- data/lib/relaton/gb/committee.rb +13 -0
- data/lib/relaton/gb/docidentifier.rb +72 -0
- data/lib/relaton/gb/doctype.rb +9 -0
- data/lib/relaton/gb/ext.rb +36 -0
- data/lib/relaton/gb/gb_scraper.rb +61 -0
- data/lib/relaton/gb/gb_type.rb +20 -0
- data/lib/relaton/gb/hit.rb +48 -0
- data/lib/relaton/gb/hit_collection.rb +19 -0
- data/lib/relaton/gb/item.rb +13 -0
- data/lib/relaton/gb/item_data.rb +6 -0
- data/lib/relaton/gb/processor.rb +49 -0
- data/lib/relaton/gb/project_number.rb +38 -0
- data/lib/relaton/gb/scraper.rb +221 -0
- data/lib/relaton/gb/sec_scraper.rb +92 -0
- data/lib/relaton/gb/stage_name.rb +13 -0
- data/lib/relaton/gb/structured_identifier.rb +26 -0
- data/lib/relaton/gb/t_scraper.rb +126 -0
- data/lib/relaton/gb/util.rb +8 -0
- data/lib/relaton/gb/yaml/prefixes.yaml +200 -0
- data/lib/relaton/gb.rb +33 -0
- 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/bibdata.rb +8 -0
- data/lib/relaton/iana/bibitem.rb +8 -0
- data/lib/relaton/iana/bibliography.rb +100 -0
- data/lib/relaton/iana/data_fetcher.rb +101 -0
- data/lib/relaton/iana/item.rb +7 -0
- data/lib/relaton/iana/item_data.rb +6 -0
- data/lib/relaton/iana/parser.rb +146 -0
- data/lib/relaton/iana/processor.rb +70 -0
- data/lib/relaton/iana/util.rb +8 -0
- data/lib/relaton/iana.rb +40 -0
- data/lib/relaton/iec/bibliography.rb +283 -0
- data/lib/relaton/iec/data_fetcher.rb +222 -0
- data/lib/relaton/iec/data_parser.rb +391 -0
- data/lib/relaton/iec/hit.rb +26 -0
- data/lib/relaton/iec/hit_collection.rb +138 -0
- data/lib/relaton/iec/item_data.rb +7 -0
- data/lib/relaton/iec/model/bibdata.rb +8 -0
- data/lib/relaton/iec/model/bibitem.rb +8 -0
- data/lib/relaton/iec/model/docidentifier.rb +135 -0
- data/lib/relaton/iec/model/doctype.rb +12 -0
- data/lib/relaton/iec/model/ext.rb +53 -0
- data/lib/relaton/iec/model/item.rb +20 -0
- data/lib/relaton/iec/model/item_base.rb +12 -0
- data/lib/relaton/iec/model/relation.rb +7 -0
- data/lib/relaton/iec/model/stage_name.rb +13 -0
- data/lib/relaton/iec/processor.rb +74 -0
- data/lib/relaton/iec/statuses.yml +199 -0
- data/lib/relaton/iec/util.rb +8 -0
- data/lib/relaton/iec.rb +98 -0
- data/lib/relaton/ieee/balloting_group.rb +13 -0
- data/lib/relaton/ieee/bibdata.rb +8 -0
- data/lib/relaton/ieee/bibitem.rb +8 -0
- data/lib/relaton/ieee/bibliography.rb +73 -0
- data/lib/relaton/ieee/converter/bibxml/from_rfcxml.rb +10 -0
- data/lib/relaton/ieee/converter/bibxml/from_rfcxml_referencegroup.rb +10 -0
- data/lib/relaton/ieee/converter/bibxml.rb +20 -0
- data/lib/relaton/ieee/data_fetcher.rb +771 -0
- data/lib/relaton/ieee/doctype.rb +9 -0
- data/lib/relaton/ieee/editorial_group.rb +19 -0
- data/lib/relaton/ieee/ext.rb +36 -0
- data/lib/relaton/ieee/idams_parser.rb +330 -0
- data/lib/relaton/ieee/item.rb +11 -0
- data/lib/relaton/ieee/item_data.rb +7 -0
- data/lib/relaton/ieee/processor.rb +71 -0
- data/lib/relaton/ieee/rawbib_id_parser.rb +753 -0
- data/lib/relaton/ieee/util.rb +8 -0
- data/lib/relaton/ieee.rb +30 -0
- data/lib/relaton/ietf/bibdata.rb +8 -0
- data/lib/relaton/ietf/bibitem.rb +8 -0
- data/lib/relaton/ietf/bibliography.rb +35 -0
- data/lib/relaton/ietf/bibxml_parser.rb +232 -0
- data/lib/relaton/ietf/data_fetcher.rb +561 -0
- data/lib/relaton/ietf/doctype.rb +9 -0
- data/lib/relaton/ietf/ext.rb +63 -0
- data/lib/relaton/ietf/item.rb +16 -0
- data/lib/relaton/ietf/item_base.rb +18 -0
- data/lib/relaton/ietf/item_data.rb +6 -0
- data/lib/relaton/ietf/processing_instructions.rb +79 -0
- data/lib/relaton/ietf/processor.rb +72 -0
- data/lib/relaton/ietf/relation.rb +9 -0
- data/lib/relaton/ietf/rfc/abstract.rb +19 -0
- data/lib/relaton/ietf/rfc/author.rb +21 -0
- data/lib/relaton/ietf/rfc/entry.rb +446 -0
- data/lib/relaton/ietf/rfc/entry_date.rb +21 -0
- data/lib/relaton/ietf/rfc/format.rb +19 -0
- data/lib/relaton/ietf/rfc/index.rb +46 -0
- data/lib/relaton/ietf/rfc/is_also.rb +21 -0
- data/lib/relaton/ietf/rfc/keywords.rb +19 -0
- data/lib/relaton/ietf/rfc/rfc_index_namespace.rb +11 -0
- data/lib/relaton/ietf/scraper.rb +101 -0
- data/lib/relaton/ietf/util.rb +8 -0
- data/lib/relaton/ietf/wg_name_resolver.rb +42 -0
- data/lib/relaton/ietf.rb +30 -0
- data/lib/relaton/iho/bibdata.rb +8 -0
- data/lib/relaton/iho/bibitem.rb +8 -0
- data/lib/relaton/iho/bibliography.rb +114 -0
- data/lib/relaton/iho/comment_period.rb +13 -0
- data/lib/relaton/iho/docidentifier.rb +31 -0
- data/lib/relaton/iho/doctype.rb +10 -0
- data/lib/relaton/iho/ext.rb +20 -0
- data/lib/relaton/iho/hash_parser_v1.rb +144 -0
- data/lib/relaton/iho/item.rb +20 -0
- data/lib/relaton/iho/item_base.rb +18 -0
- data/lib/relaton/iho/item_data.rb +6 -0
- data/lib/relaton/iho/processor.rb +54 -0
- data/lib/relaton/iho/relation.rb +9 -0
- data/lib/relaton/iho/structured_identifier.rb +20 -0
- data/lib/relaton/iho/util.rb +8 -0
- data/lib/relaton/iho.rb +27 -0
- data/lib/relaton/index/config.rb +52 -0
- data/lib/relaton/index/file_io.rb +305 -0
- data/lib/relaton/index/file_storage.rb +66 -0
- data/lib/relaton/index/pool.rb +46 -0
- data/lib/relaton/index/shard_source.rb +201 -0
- data/lib/relaton/index/type.rb +210 -0
- data/lib/relaton/index/util.rb +18 -0
- data/lib/relaton/index.rb +61 -0
- data/lib/relaton/isbn/isbn.rb +61 -0
- data/lib/relaton/isbn/open_library.rb +43 -0
- data/lib/relaton/isbn/parser.rb +88 -0
- data/lib/relaton/isbn/processor.rb +48 -0
- data/lib/relaton/isbn/util.rb +8 -0
- data/lib/relaton/isbn.rb +19 -0
- data/lib/relaton/iso/bibliography.rb +412 -0
- data/lib/relaton/iso/data_fetcher.rb +338 -0
- data/lib/relaton/iso/data_parser.rb +458 -0
- data/lib/relaton/iso/hash_parser_v1.rb +177 -0
- data/lib/relaton/iso/hit.rb +57 -0
- data/lib/relaton/iso/hit_collection.rb +196 -0
- data/lib/relaton/iso/item_data.rb +50 -0
- data/lib/relaton/iso/model/bibdata.rb +10 -0
- data/lib/relaton/iso/model/bibitem.rb +8 -0
- data/lib/relaton/iso/model/contributor.rb +6 -0
- data/lib/relaton/iso/model/contributor_info.rb +9 -0
- data/lib/relaton/iso/model/docidentifier.rb +146 -0
- data/lib/relaton/iso/model/doctype.rb +13 -0
- data/lib/relaton/iso/model/ext.rb +35 -0
- data/lib/relaton/iso/model/item.rb +17 -0
- data/lib/relaton/iso/model/item_base.rb +22 -0
- data/lib/relaton/iso/model/organization.rb +9 -0
- data/lib/relaton/iso/model/project_number.rb +22 -0
- data/lib/relaton/iso/model/relation.rb +9 -0
- data/lib/relaton/iso/model/stagename.rb +14 -0
- data/lib/relaton/iso/model/structured_identifier.rb +31 -0
- data/lib/relaton/iso/processor.rb +85 -0
- data/lib/relaton/iso/scraper.rb +635 -0
- data/lib/relaton/iso/type/pubid.rb +50 -0
- data/lib/relaton/iso/util.rb +8 -0
- data/lib/relaton/iso.rb +30 -0
- data/lib/relaton/itu/bibliography.rb +95 -0
- data/lib/relaton/itu/data_crawler_r.rb +664 -0
- data/lib/relaton/itu/data_fetcher.rb +550 -0
- data/lib/relaton/itu/data_merge_r.rb +149 -0
- data/lib/relaton/itu/data_parser_r.rb +214 -0
- 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 +28 -0
- data/lib/relaton/itu/hit_collection.rb +299 -0
- data/lib/relaton/itu/item_data.rb +6 -0
- data/lib/relaton/itu/model/approval_stage.rb +13 -0
- data/lib/relaton/itu/model/bibdata.rb +8 -0
- data/lib/relaton/itu/model/bibitem.rb +8 -0
- data/lib/relaton/itu/model/docidentifier.rb +75 -0
- data/lib/relaton/itu/model/doctype.rb +13 -0
- data/lib/relaton/itu/model/ext.rb +47 -0
- data/lib/relaton/itu/model/item.rb +13 -0
- data/lib/relaton/itu/model/meeting.rb +13 -0
- data/lib/relaton/itu/model/meeting_date.rb +15 -0
- data/lib/relaton/itu/model/question.rb +13 -0
- data/lib/relaton/itu/model/recommendation_status.rb +11 -0
- data/lib/relaton/itu/model/structured_identifier.rb +38 -0
- data/lib/relaton/itu/processor.rb +72 -0
- data/lib/relaton/itu/pubid.rb +199 -0
- data/lib/relaton/itu/radio_regulations_parser.rb +70 -0
- data/lib/relaton/itu/recommendation_fields.rb +334 -0
- data/lib/relaton/itu/recommendation_parser.rb +30 -0
- data/lib/relaton/itu/scraper.rb +203 -0
- data/lib/relaton/itu/util.rb +8 -0
- data/lib/relaton/itu.rb +34 -0
- 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/bibdata.rb +8 -0
- data/lib/relaton/jis/bibitem.rb +8 -0
- data/lib/relaton/jis/bibliography.rb +73 -0
- data/lib/relaton/jis/data_fetcher.rb +183 -0
- data/lib/relaton/jis/docidentifier.rb +120 -0
- data/lib/relaton/jis/doctype.rb +9 -0
- data/lib/relaton/jis/ext.rb +13 -0
- data/lib/relaton/jis/hit.rb +88 -0
- data/lib/relaton/jis/hit_collection.rb +128 -0
- data/lib/relaton/jis/item.rb +22 -0
- data/lib/relaton/jis/item_base.rb +26 -0
- data/lib/relaton/jis/item_data.rb +8 -0
- data/lib/relaton/jis/processor.rb +55 -0
- data/lib/relaton/jis/relation.rb +11 -0
- data/lib/relaton/jis/scraper.rb +232 -0
- data/lib/relaton/jis/structured_identifier.rb +13 -0
- data/lib/relaton/jis/util.rb +8 -0
- data/lib/relaton/jis.rb +32 -0
- data/lib/relaton/logger/channels/gh_issue.rb +143 -0
- data/lib/relaton/logger/config.rb +34 -0
- data/lib/relaton/logger/formatter_json.rb +8 -0
- data/lib/relaton/logger/formatter_string.rb +12 -0
- data/lib/relaton/logger/log.rb +64 -0
- data/lib/relaton/logger/log_device.rb +27 -0
- data/lib/relaton/logger/pool.rb +24 -0
- data/lib/relaton/logger.rb +18 -0
- data/lib/relaton/nist/bibdata.rb +8 -0
- data/lib/relaton/nist/bibitem.rb +8 -0
- data/lib/relaton/nist/bibliography.rb +191 -0
- data/lib/relaton/nist/comment_period.rb +15 -0
- data/lib/relaton/nist/data_fetcher.rb +134 -0
- data/lib/relaton/nist/date.rb +7 -0
- data/lib/relaton/nist/docidentifier.rb +165 -0
- data/lib/relaton/nist/doctype.rb +7 -0
- data/lib/relaton/nist/ext.rb +16 -0
- data/lib/relaton/nist/hit.rb +18 -0
- data/lib/relaton/nist/hit_collection.rb +362 -0
- data/lib/relaton/nist/item.rb +19 -0
- data/lib/relaton/nist/item_base.rb +16 -0
- data/lib/relaton/nist/item_data.rb +6 -0
- data/lib/relaton/nist/mods_parser.rb +302 -0
- data/lib/relaton/nist/processor.rb +69 -0
- data/lib/relaton/nist/pubs_export.rb +69 -0
- data/lib/relaton/nist/relation.rb +10 -0
- data/lib/relaton/nist/scraper.rb +293 -0
- data/lib/relaton/nist/series.yaml +49 -0
- data/lib/relaton/nist/util.rb +8 -0
- data/lib/relaton/nist.rb +34 -0
- data/lib/relaton/oasis/bibdata.rb +8 -0
- data/lib/relaton/oasis/bibitem.rb +8 -0
- data/lib/relaton/oasis/bibliography.rb +201 -0
- data/lib/relaton/oasis/browser_agent.rb +71 -0
- data/lib/relaton/oasis/data_fetcher.rb +130 -0
- data/lib/relaton/oasis/data_parser.rb +305 -0
- data/lib/relaton/oasis/data_parser_utils.rb +330 -0
- data/lib/relaton/oasis/data_part_parser.rb +239 -0
- data/lib/relaton/oasis/docidentifier.rb +54 -0
- data/lib/relaton/oasis/doctype.rb +7 -0
- data/lib/relaton/oasis/ext.rb +19 -0
- data/lib/relaton/oasis/item.rb +14 -0
- data/lib/relaton/oasis/item_data.rb +6 -0
- data/lib/relaton/oasis/processor.rb +74 -0
- data/lib/relaton/oasis/util.rb +8 -0
- data/lib/relaton/oasis.rb +41 -0
- data/lib/relaton/ogc/bibdata.rb +8 -0
- data/lib/relaton/ogc/bibitem.rb +8 -0
- data/lib/relaton/ogc/bibliography.rb +64 -0
- data/lib/relaton/ogc/data_fetcher.rb +131 -0
- data/lib/relaton/ogc/docidentifier.rb +111 -0
- data/lib/relaton/ogc/doctype.rb +12 -0
- data/lib/relaton/ogc/ext.rb +15 -0
- data/lib/relaton/ogc/hit.rb +18 -0
- data/lib/relaton/ogc/hit_collection.rb +111 -0
- data/lib/relaton/ogc/item.rb +13 -0
- data/lib/relaton/ogc/item_data.rb +6 -0
- data/lib/relaton/ogc/processor.rb +59 -0
- data/lib/relaton/ogc/scraper.rb +225 -0
- data/lib/relaton/ogc/util.rb +8 -0
- data/lib/relaton/ogc.rb +30 -0
- data/lib/relaton/oiml/bibdata.rb +8 -0
- data/lib/relaton/oiml/bibitem.rb +8 -0
- data/lib/relaton/oiml/bibliography.rb +169 -0
- data/lib/relaton/oiml/docidentifier.rb +48 -0
- data/lib/relaton/oiml/doctype.rb +13 -0
- data/lib/relaton/oiml/ext.rb +42 -0
- data/lib/relaton/oiml/item.rb +20 -0
- data/lib/relaton/oiml/item_base.rb +18 -0
- data/lib/relaton/oiml/item_data.rb +6 -0
- data/lib/relaton/oiml/processor.rb +54 -0
- data/lib/relaton/oiml/relation.rb +9 -0
- data/lib/relaton/oiml/util.rb +8 -0
- data/lib/relaton/oiml.rb +24 -0
- data/lib/relaton/omg/bibdata.rb +8 -0
- data/lib/relaton/omg/bibitem.rb +8 -0
- data/lib/relaton/omg/bibliography.rb +31 -0
- data/lib/relaton/omg/docidentifier.rb +67 -0
- data/lib/relaton/omg/ext.rb +7 -0
- data/lib/relaton/omg/item.rb +9 -0
- data/lib/relaton/omg/item_data.rb +6 -0
- data/lib/relaton/omg/processor.rb +35 -0
- data/lib/relaton/omg/scraper.rb +186 -0
- data/lib/relaton/omg/util.rb +8 -0
- data/lib/relaton/omg.rb +25 -0
- data/lib/relaton/plateau/bibdata.rb +8 -0
- data/lib/relaton/plateau/bibitem.rb +8 -0
- data/lib/relaton/plateau/bibliography.rb +31 -0
- data/lib/relaton/plateau/data_fetcher.rb +176 -0
- data/lib/relaton/plateau/doctype.rb +7 -0
- data/lib/relaton/plateau/ext.rb +23 -0
- data/lib/relaton/plateau/handbook_parser.rb +102 -0
- data/lib/relaton/plateau/hit.rb +21 -0
- data/lib/relaton/plateau/hit_collection.rb +79 -0
- data/lib/relaton/plateau/item.rb +12 -0
- data/lib/relaton/plateau/item_data.rb +6 -0
- data/lib/relaton/plateau/parser.rb +101 -0
- data/lib/relaton/plateau/processor.rb +51 -0
- data/lib/relaton/plateau/technical_report_parser.rb +98 -0
- data/lib/relaton/plateau/util.rb +8 -0
- data/lib/relaton/plateau.rb +29 -0
- 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/un/bibdata.rb +8 -0
- data/lib/relaton/un/bibitem.rb +8 -0
- data/lib/relaton/un/bibliography.rb +48 -0
- data/lib/relaton/un/doctype.rb +10 -0
- data/lib/relaton/un/ext.rb +30 -0
- data/lib/relaton/un/hit.rb +56 -0
- data/lib/relaton/un/hit_collection.rb +61 -0
- data/lib/relaton/un/item.rb +11 -0
- data/lib/relaton/un/item_data.rb +6 -0
- data/lib/relaton/un/parser.rb +108 -0
- data/lib/relaton/un/processor.rb +38 -0
- data/lib/relaton/un/session.rb +25 -0
- data/lib/relaton/un/token_generator.rb +105 -0
- data/lib/relaton/un/util.rb +8 -0
- data/lib/relaton/un/wasm/decoder.rb +434 -0
- data/lib/relaton/un/wasm/instance.rb +101 -0
- data/lib/relaton/un/wasm/interpreter.rb +613 -0
- data/lib/relaton/un/wasm/memory.rb +112 -0
- data/lib/relaton/un/wasm/module.rb +47 -0
- data/lib/relaton/un/wasm.rb +17 -0
- data/lib/relaton/un/wasm_v_bg.wasm +0 -0
- data/lib/relaton/un.rb +28 -0
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/w3c/bibdata.rb +8 -0
- data/lib/relaton/w3c/bibitem.rb +8 -0
- data/lib/relaton/w3c/bibliography.rb +174 -0
- data/lib/relaton/w3c/data_fetcher.rb +487 -0
- data/lib/relaton/w3c/data_parser.rb +379 -0
- data/lib/relaton/w3c/docidentifier.rb +48 -0
- data/lib/relaton/w3c/doctype.rb +7 -0
- data/lib/relaton/w3c/ext.rb +11 -0
- data/lib/relaton/w3c/governor.rb +32 -0
- data/lib/relaton/w3c/item.rb +15 -0
- data/lib/relaton/w3c/item_data.rb +6 -0
- data/lib/relaton/w3c/processor.rb +49 -0
- data/lib/relaton/w3c/pubid.rb +85 -0
- data/lib/relaton/w3c/safe_realize.rb +148 -0
- data/lib/relaton/w3c/util.rb +8 -0
- data/lib/relaton/w3c.rb +36 -0
- data/lib/relaton/xsf/bibdata.rb +8 -0
- data/lib/relaton/xsf/bibitem.rb +8 -0
- data/lib/relaton/xsf/bibliography.rb +84 -0
- data/lib/relaton/xsf/data_fetcher.rb +106 -0
- data/lib/relaton/xsf/docidentifier.rb +46 -0
- data/lib/relaton/xsf/hit.rb +17 -0
- data/lib/relaton/xsf/hit_collection.rb +52 -0
- data/lib/relaton/xsf/item.rb +13 -0
- data/lib/relaton/xsf/item_data.rb +6 -0
- data/lib/relaton/xsf/processor.rb +51 -0
- data/lib/relaton/xsf/util.rb +9 -0
- data/lib/relaton/xsf.rb +34 -0
- data/lib/relaton-core.rb +1 -0
- data/lib/relaton.rb +85 -0
- metadata +775 -161
- data/.github/workflows/rake.yml +0 -14
- data/.github/workflows/release.yml +0 -24
- data/.github/workflows/rubocop.yml +0 -48
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/CLAUDE.md +0 -78
- data/Gemfile +0 -29
- data/Rakefile +0 -6
- data/docs/CHANGELOG.adoc +0 -16
- data/docs/VERSIONING_POLICY.adoc +0 -38
- data/docs/navigation.adoc +0 -6
- data/lib/relaton/db/version.rb +0 -5
- data/relaton.gemspec +0 -72
- data/spec/relaton/config_spec.rb +0 -10
- data/spec/relaton/db_cache_spec.rb +0 -51
- data/spec/relaton/db_spec.rb +0 -567
- data/spec/relaton/registry_spec.rb +0 -178
- data/spec/relaton/util_spec.rb +0 -3
- data/spec/relaton_meta_spec.rb +0 -25
- data/spec/relaton_spec.rb +0 -800
- data/spec/spec_helper.rb +0 -45
- data/spec/support/gb_t_20223_2006.xml +0 -33
- data/spec/support/iso_111111119115_1.xml +0 -0
- data/spec/support/iso_19115_1.xml +0 -115
- data/spec/support/iso_19115_2.xml +0 -95
- data/spec/support/rfc_8341.xml +0 -46
- data/spec/vcr_cassetes/api_relaton_org.yml +0 -121
- data/spec/vcr_cassetes/api_relaton_org_unavailable.yml +0 -140
- data/spec/vcr_cassetes/cc_dir_10005_2019.yml +0 -202
- data/spec/vcr_cassetes/cipm_meeting_43.yml +0 -1505
- data/spec/vcr_cassetes/gb_t_20223_2006.yml +0 -729
- data/spec/vcr_cassetes/iso_111111119115_1.yml +0 -12951
- data/spec/vcr_cassetes/iso_19115_1.yml +0 -17334
- data/spec/vcr_cassetes/iso_19115_1_2.yml +0 -322
- data/spec/vcr_cassetes/iso_19115_1_std.yml +0 -17334
- data/spec/vcr_cassetes/iso_19115_all_parts.yml +0 -185
- data/spec/vcr_cassetes/iso_19133_2005.yml +0 -144
- data/spec/vcr_cassetes/iso_combined_applied.yml +0 -318
- data/spec/vcr_cassetes/iso_combined_included.yml +0 -318
- data/spec/vcr_cassetes/ogc_19_025r1.yml +0 -374
- data/spec/vcr_cassetes/omg_ami4ccm_1_0.yml +0 -317
- data/spec/vcr_cassetes/rfc_8341.yml +0 -1278
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
require "relaton/core"
|
|
2
|
+
require "w3c_api"
|
|
3
|
+
require_relative "../w3c"
|
|
4
|
+
require_relative "safe_realize"
|
|
5
|
+
require_relative "data_parser"
|
|
6
|
+
|
|
7
|
+
module Relaton
|
|
8
|
+
module W3c
|
|
9
|
+
class DataFetcher < Core::DataFetcher
|
|
10
|
+
include Relaton::W3c::SafeRealize
|
|
11
|
+
|
|
12
|
+
# Raised when pagination over the specifications index stops before the
|
|
13
|
+
# last page (e.g. a page fetch fails after retries, or the API reports
|
|
14
|
+
# more pages than were reached). It aborts the whole crawl so a truncated
|
|
15
|
+
# dataset is never saved or committed — see #fetch and #enqueue_specs.
|
|
16
|
+
class CrawlIncompleteError < StandardError; end
|
|
17
|
+
|
|
18
|
+
# Conservative default: too many parallel workers burst the per-spec
|
|
19
|
+
# version-history requests fast enough to trip the W3C API rate limiter
|
|
20
|
+
# (429s), which is what silently truncated the dataset before the crawl
|
|
21
|
+
# learned to abort on incomplete pagination. Raise it via the env var on
|
|
22
|
+
# a faster/shallower run; lower it further if 429s still appear.
|
|
23
|
+
DEFAULT_CONCURRENCY = 4
|
|
24
|
+
|
|
25
|
+
# How many times #fetch_specifications_page retries a transient failure
|
|
26
|
+
# (rate-limit/connection) before giving up and aborting the crawl.
|
|
27
|
+
PAGE_FETCH_ATTEMPTS = 3
|
|
28
|
+
|
|
29
|
+
# How many resources may be lost to rate limiting before the dataset is
|
|
30
|
+
# considered too incomplete to save. Deliberately low: crawls are bimodal
|
|
31
|
+
# — a healthy run loses none (Aug 17 2026: 0), a rate-limited one loses
|
|
32
|
+
# hundreds (Aug 19 2026: 1,412) — so there is no middle ground to protect.
|
|
33
|
+
# Genuinely broken resources (permanent skips from 404s/5xx) are counted
|
|
34
|
+
# separately and stay tolerated.
|
|
35
|
+
DEFAULT_MAX_THROTTLED_LOSSES = 25
|
|
36
|
+
|
|
37
|
+
# Retry policy pushed into w3c_api. Its defaults spend ~31s (1+2+4+8+16)
|
|
38
|
+
# inside lutaml-hal before a 429 ever reaches us, which just delays the
|
|
39
|
+
# shared back-pressure that actually works; this compresses the same chain
|
|
40
|
+
# to ~11s (0.5+1+2+4+4) so the Governor can open its pool-wide cooldown
|
|
41
|
+
# while the ban window is still young.
|
|
42
|
+
#
|
|
43
|
+
# `max_retries` deliberately stays at 5. lutaml-hal applies one retry count
|
|
44
|
+
# to both 429 and 5xx, and unlike a 429 a 5xx is still a *permanent* skip
|
|
45
|
+
# here — cutting its attempts would blacklist a burst of resources on a
|
|
46
|
+
# brief upstream wobble that the old policy rode out, and `skipped` is not
|
|
47
|
+
# counted by guard_throttle_budget, so that loss would be invisible.
|
|
48
|
+
#
|
|
49
|
+
# `max_retry_after` matches `max_delay` because a server-instructed wait
|
|
50
|
+
# must not outlive the compressed chain either. Left unset, lutaml-hal's
|
|
51
|
+
# DEFAULT_MAX_RETRY_AFTER (300 s) applies, and a large Retry-After on a
|
|
52
|
+
# 429 parks one thread inside the HTTP layer for up to 5 x 300 s with the
|
|
53
|
+
# governor hearing nothing — the very thing the compression prevents. The
|
|
54
|
+
# hint is not discarded, it moves to where it belongs: Governor.retry_after
|
|
55
|
+
# reads it off the same error and uses it as the FLOOR of the pool-wide
|
|
56
|
+
# cooldown, under the governor's own 900 s cap.
|
|
57
|
+
UPSTREAM_RATE_LIMITING = {
|
|
58
|
+
max_retries: 5, base_delay: 0.5, max_delay: 4.0, backoff_factor: 2.0,
|
|
59
|
+
max_retry_after: 4.0
|
|
60
|
+
}.freeze
|
|
61
|
+
|
|
62
|
+
# Ceiling on resources dropped to rate limiting before the crawl refuses
|
|
63
|
+
# to save. Tunable via env var for a deliberately partial run; 0 is a
|
|
64
|
+
# meaningful setting (tolerate nothing), so it is accepted here unlike in
|
|
65
|
+
# the governor's duration knobs.
|
|
66
|
+
def self.max_throttled_losses
|
|
67
|
+
value = ENV["RELATON_W3C_MAX_THROTTLED"].to_s.strip
|
|
68
|
+
value.match?(/\A\d+\z/) ? value.to_i : DEFAULT_MAX_THROTTLED_LOSSES
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Number of fetch_spec worker threads. Tunable via env var so CI or
|
|
72
|
+
# local runs can dial it up for speed or down to lighten load on
|
|
73
|
+
# api.w3.org (or for debugging).
|
|
74
|
+
def self.concurrency
|
|
75
|
+
(ENV["RELATON_W3C_FETCH_CONCURRENCY"] || DEFAULT_CONCURRENCY).to_i
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Whether to crawl each specification's version history (version_history,
|
|
79
|
+
# predecessor_versions, successor_versions). Enabled by default for a
|
|
80
|
+
# complete dataset. Set RELATON_W3C_FETCH_VERSIONS=false for a faster,
|
|
81
|
+
# shallower crawl that emits only the top-level specifications and skips
|
|
82
|
+
# the per-spec version fan-out (the bulk of the API requests).
|
|
83
|
+
def self.fetch_versions?
|
|
84
|
+
val = ENV["RELATON_W3C_FETCH_VERSIONS"]
|
|
85
|
+
return true if val.nil? || val.empty?
|
|
86
|
+
|
|
87
|
+
!%w[0 false no off].include?(val.strip.downcase)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def initialize(*args)
|
|
91
|
+
super
|
|
92
|
+
@mutex = Mutex.new
|
|
93
|
+
@interrupted = false
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# The index is pubid-backed: `pubid_class:` makes Relaton::Index sort the
|
|
97
|
+
# rows by `id.root.number` on save and serialize each id to its
|
|
98
|
+
# `_type: pubid:w3c:*` hash. Without it a v1-shaped file would be written
|
|
99
|
+
# under a v2 name, with no error and no narrowing.
|
|
100
|
+
def index
|
|
101
|
+
@index ||= Relaton::Index.find_or_create(
|
|
102
|
+
:W3C, file: "#{INDEXFILE}.yaml", pubid_class: ::Pubid::W3c::Identifier
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def log_error(msg)
|
|
107
|
+
Util.error msg
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def client
|
|
111
|
+
@client ||= W3cApi::Client.new
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
# Parse documents in parallel. The crawler is heavily I/O-bound on
|
|
116
|
+
# api.w3.org round-trips (~30-50k requests per run), so a small thread
|
|
117
|
+
# pool gives a near-linear speedup. Pagination still happens serially:
|
|
118
|
+
# each page's `next?` flag gates whether the next page is requested.
|
|
119
|
+
#
|
|
120
|
+
# A SIGINT (Ctrl-C) is handled gracefully: the producer stops queuing and
|
|
121
|
+
# the workers stop processing after their in-flight spec, then the index
|
|
122
|
+
# of everything fetched so far is saved rather than the run being lost.
|
|
123
|
+
#
|
|
124
|
+
def fetch(_source = nil)
|
|
125
|
+
SafeRealize.reset!
|
|
126
|
+
configure_upstream_rate_limiting
|
|
127
|
+
n_workers = self.class.concurrency
|
|
128
|
+
queue = SizedQueue.new(n_workers * 4)
|
|
129
|
+
workers = Array.new(n_workers) { spawn_worker(queue) }
|
|
130
|
+
|
|
131
|
+
with_interrupt_handler do
|
|
132
|
+
# The poison pills + join run in `ensure` so an exception raised while
|
|
133
|
+
# enqueuing (e.g. CrawlIncompleteError) still unblocks the producer
|
|
134
|
+
# and drains the workers instead of deadlocking on queue.pop.
|
|
135
|
+
begin
|
|
136
|
+
enqueue_specs(queue)
|
|
137
|
+
ensure
|
|
138
|
+
n_workers.times { queue << nil } # poison pills
|
|
139
|
+
workers.each(&:join)
|
|
140
|
+
end
|
|
141
|
+
if @interrupted
|
|
142
|
+
# Ctrl-C means "give me what you have", so the completeness guards
|
|
143
|
+
# below are deliberately not applied to an interrupted crawl.
|
|
144
|
+
Util.warn "Crawl interrupted — saving progress collected so far."
|
|
145
|
+
else
|
|
146
|
+
guard_rate_limited
|
|
147
|
+
guard_throttle_budget
|
|
148
|
+
end
|
|
149
|
+
index.save
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
report_errors
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Abort when the governor concluded we are banned rather than briefly
|
|
156
|
+
# throttled. Everything fetched so far is discarded on purpose: a partial
|
|
157
|
+
# dataset must never be saved (crawler.rb wipes data/ first, so saving one
|
|
158
|
+
# commits mass deletions).
|
|
159
|
+
def guard_rate_limited
|
|
160
|
+
return unless SafeRealize.governor.exhausted?
|
|
161
|
+
|
|
162
|
+
# #give_up_rounds, not #throttle_rounds: the latter is live and a
|
|
163
|
+
# straggler success resets it, which is how a give-up at round 5 got
|
|
164
|
+
# reported as "after 2 consecutive backoffs".
|
|
165
|
+
rounds = SafeRealize.governor.give_up_rounds ||
|
|
166
|
+
SafeRealize.governor.throttle_rounds
|
|
167
|
+
raise CrawlIncompleteError,
|
|
168
|
+
"crawl is rate-limited: gave up after " \
|
|
169
|
+
"#{rounds} consecutive backoffs " \
|
|
170
|
+
"(#{SafeRealize.governor.throttle_count} rate-limited responses); " \
|
|
171
|
+
"refusing to save a partial dataset"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# The per-resource counterpart to guard_complete_pagination: pagination can
|
|
175
|
+
# complete cleanly while rate limiting has quietly hollowed out the
|
|
176
|
+
# documents behind it.
|
|
177
|
+
def guard_throttle_budget
|
|
178
|
+
lost = SafeRealize.throttled.size
|
|
179
|
+
budget = self.class.max_throttled_losses
|
|
180
|
+
return if lost <= budget
|
|
181
|
+
|
|
182
|
+
raise CrawlIncompleteError,
|
|
183
|
+
"#{lost} resources were dropped to rate limiting (budget #{budget}); " \
|
|
184
|
+
"refusing to save a partial dataset"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
#
|
|
188
|
+
# Page through the specifications index, feeding each spec (paired with
|
|
189
|
+
# its embedded page) to the worker queue. Returns early when interrupted.
|
|
190
|
+
#
|
|
191
|
+
# embed: true inlines each specification's full payload into the index
|
|
192
|
+
# page's `_embedded` block, so a spec link realizes from that page in
|
|
193
|
+
# memory instead of making its own HTTP request — one request per page
|
|
194
|
+
# rather than one per specification. The page is queued alongside each
|
|
195
|
+
# link so the worker can hand it back to realize as the parent_resource.
|
|
196
|
+
#
|
|
197
|
+
def enqueue_specs(queue)
|
|
198
|
+
specs = client.specifications(embed: true)
|
|
199
|
+
expected_pages = specs.pages
|
|
200
|
+
last_page = nil
|
|
201
|
+
loop do
|
|
202
|
+
page = specs
|
|
203
|
+
page.links.specifications.each do |spec|
|
|
204
|
+
break if stopping?
|
|
205
|
+
|
|
206
|
+
queue << [spec, page]
|
|
207
|
+
end
|
|
208
|
+
break if stopping?
|
|
209
|
+
|
|
210
|
+
last_page = page.page
|
|
211
|
+
break unless page.next?
|
|
212
|
+
|
|
213
|
+
# Fetch the next page through the client's fetch path rather than
|
|
214
|
+
# realizing the `next` link: only fetch populates the page's
|
|
215
|
+
# embedded_data, so this keeps embed working past page 1. Realizing
|
|
216
|
+
# the `next` link drops `_embedded` and forces a per-spec HTTP
|
|
217
|
+
# request for every specification on every later page.
|
|
218
|
+
next_page = fetch_specifications_page(page.page + 1)
|
|
219
|
+
# A nil here means the page fetch failed after retries (not the end
|
|
220
|
+
# of the list — that is `!page.next?` above). Aborting rather than
|
|
221
|
+
# `break`ing prevents a rate-limit blip from silently truncating the
|
|
222
|
+
# dataset: a partial crawl must never be saved/committed.
|
|
223
|
+
unless next_page
|
|
224
|
+
# When the governor gave up, the page didn't fail — we stopped
|
|
225
|
+
# asking. Let guard_rate_limited report that with the accurate
|
|
226
|
+
# reason instead of dressing it up as a pagination fault.
|
|
227
|
+
break if SafeRealize.governor.exhausted?
|
|
228
|
+
|
|
229
|
+
raise CrawlIncompleteError,
|
|
230
|
+
"specifications pagination stopped at page #{page.page}: " \
|
|
231
|
+
"failed to fetch page #{page.page + 1}"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
specs = next_page
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
return if stopping?
|
|
238
|
+
|
|
239
|
+
guard_complete_pagination(last_page, expected_pages)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Reasons to stop feeding the queue: a Ctrl-C (save what we have) or the
|
|
243
|
+
# governor concluding the crawl is banned (abort). Both need the producer
|
|
244
|
+
# to stop; #fetch decides which of the two it was.
|
|
245
|
+
def stopping?
|
|
246
|
+
@interrupted || SafeRealize.governor.exhausted?
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# The mid-spec back-out, and deliberately NOT #stopping?. The two stop
|
|
250
|
+
# reasons want opposite things of a spec already in flight:
|
|
251
|
+
#
|
|
252
|
+
# - Ctrl-C means "give me what you have". The index IS saved, so the
|
|
253
|
+
# in-flight spec must finish, or a half-parsed document is written.
|
|
254
|
+
# - A latched give-up means the run is lost — guard_rate_limited raises
|
|
255
|
+
# and nothing is saved — and the host has banned us. Abandon at once.
|
|
256
|
+
def abandoned?
|
|
257
|
+
SafeRealize.governor.exhausted?
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Defense in depth: even when no page fetch raised, make sure pagination
|
|
261
|
+
# actually reached the last page the API advertised. Catches truncation
|
|
262
|
+
# modes other than a failed fetch (e.g. a `next` link that goes missing).
|
|
263
|
+
# Only enforced when the index reported a positive page count.
|
|
264
|
+
def guard_complete_pagination(last_page, expected_pages)
|
|
265
|
+
return unless expected_pages.is_a?(Integer) && expected_pages.positive?
|
|
266
|
+
return unless last_page.is_a?(Integer) && last_page < expected_pages
|
|
267
|
+
|
|
268
|
+
raise CrawlIncompleteError,
|
|
269
|
+
"specifications pagination ended at page #{last_page} of " \
|
|
270
|
+
"#{expected_pages}; refusing to save a partial dataset"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def fetch_spec(unrealized_spec, page = nil)
|
|
274
|
+
# When `page` came from an embed:true fetch, realizing against it as the
|
|
275
|
+
# parent_resource serves the spec from embedded data (no HTTP request).
|
|
276
|
+
spec = realize(unrealized_spec, parent_resource: page)
|
|
277
|
+
return unless spec
|
|
278
|
+
# The latch can land while this spec is in flight. Nothing this crawl
|
|
279
|
+
# produces is saved any more, so stop before the parse and the write
|
|
280
|
+
# too, not only before the requests.
|
|
281
|
+
return if abandoned?
|
|
282
|
+
|
|
283
|
+
local_errors = Hash.new(true)
|
|
284
|
+
save_doc DataParser.parse(spec, local_errors)
|
|
285
|
+
|
|
286
|
+
fetch_versions(spec) if self.class.fetch_versions?
|
|
287
|
+
|
|
288
|
+
@mutex.synchronize { local_errors.each { |k, v| @errors[k] &&= v } }
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
#
|
|
292
|
+
# Crawl a specification's version history: its dated editions plus the
|
|
293
|
+
# predecessor/successor version chains. Each entry is a separate HTTP
|
|
294
|
+
# request, so this is the bulk of a run and can be skipped via
|
|
295
|
+
# RELATON_W3C_FETCH_VERSIONS=false (see .fetch_versions?).
|
|
296
|
+
#
|
|
297
|
+
def fetch_versions(spec)
|
|
298
|
+
if spec.links.respond_to?(:version_history) && spec.links.version_history
|
|
299
|
+
version_history = realize spec.links.version_history
|
|
300
|
+
version_history&.links&.spec_versions&.each { |version| parse_and_save version }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
if spec.links.respond_to?(:predecessor_versions) && spec.links.predecessor_versions
|
|
304
|
+
predecessor_versions = realize spec.links.predecessor_versions
|
|
305
|
+
predecessor_versions&.links&.predecessor_versions&.each { |version| parse_and_save version }
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
return unless spec.links.respond_to?(:successor_versions) && spec.links.successor_versions
|
|
309
|
+
|
|
310
|
+
successor_versions = realize spec.links.successor_versions
|
|
311
|
+
successor_versions&.links&.successor_versions&.each { |version| parse_and_save version }
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
#
|
|
315
|
+
# Save document to file
|
|
316
|
+
#
|
|
317
|
+
# @param [Relaton::W3c::ItemData, nil] bib bibliographic item
|
|
318
|
+
#
|
|
319
|
+
def save_doc(bib, warn_duplicate: true)
|
|
320
|
+
return unless bib
|
|
321
|
+
|
|
322
|
+
file = file_name(bib.docnumber)
|
|
323
|
+
@mutex.synchronize do
|
|
324
|
+
if @files.include?(file)
|
|
325
|
+
Util.warn "File #{file} already exists. Document: #{bib.docnumber}" if warn_duplicate
|
|
326
|
+
else
|
|
327
|
+
index_primary bib.docidentifier&.detect(&:primary), file
|
|
328
|
+
@files << file
|
|
329
|
+
end
|
|
330
|
+
File.write file, serialize(bib), encoding: "UTF-8"
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
#
|
|
335
|
+
# Add a document's primary id to the index.
|
|
336
|
+
#
|
|
337
|
+
# Every W3C id is expected to parse. One that does not is recorded in
|
|
338
|
+
# `@errors`, so the inherited `report_errors` logs it at ERROR and raises
|
|
339
|
+
# a tracked GitHub issue at the end of the crawl, and the row is skipped
|
|
340
|
+
# rather than indexed unparsed: `Relaton::Index` rejects the WHOLE index
|
|
341
|
+
# if a single row fails to deserialize, and its sort calls
|
|
342
|
+
# `.root.number` on every id. The data file is still written, so the
|
|
343
|
+
# document is unindexed, never lost.
|
|
344
|
+
#
|
|
345
|
+
# Keyed by the ID rather than the output path: the id is the defect, the
|
|
346
|
+
# file is only where it landed, and one broken id reaching several files
|
|
347
|
+
# must still report once.
|
|
348
|
+
#
|
|
349
|
+
# @param [Docidentifier, nil] docid the document's primary identifier
|
|
350
|
+
# @param [String] file path the document was written to
|
|
351
|
+
#
|
|
352
|
+
def index_primary(docid, file)
|
|
353
|
+
if docid&.pubid
|
|
354
|
+
index.add_or_update docid.pubid, file
|
|
355
|
+
return
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
id = docid&.content || file
|
|
359
|
+
@errors[id.to_s] = "Unparseable primary id `#{id}` was not indexed (#{file})"
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def to_xml(bib)
|
|
363
|
+
bib.to_xml(bibdata: true)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def to_yaml(bib)
|
|
367
|
+
bib.to_yaml
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def to_bibxml(bib)
|
|
371
|
+
bib.to_xml
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
#
|
|
375
|
+
# Generate file name
|
|
376
|
+
#
|
|
377
|
+
# @param [String] id document id
|
|
378
|
+
#
|
|
379
|
+
# @return [String] file name
|
|
380
|
+
#
|
|
381
|
+
def file_name(id)
|
|
382
|
+
name = id.sub(/^W3C\s/, "").gsub(/[\s,:\/+]/, "_").squeeze("_").downcase
|
|
383
|
+
File.join @output, "#{name}.#{@ext}"
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
private
|
|
387
|
+
|
|
388
|
+
# Install a SIGINT handler for the duration of the crawl so Ctrl-C sets
|
|
389
|
+
# the @interrupted flag (observed by the producer loop and the workers)
|
|
390
|
+
# instead of killing the process mid-write. The trap body is kept minimal
|
|
391
|
+
# (no I/O or locking) because trap context is restricted; the user-facing
|
|
392
|
+
# notice is printed from the main thread once the crawl winds down. The
|
|
393
|
+
# previous handler is restored on the way out so the trap doesn't leak
|
|
394
|
+
# into the host process.
|
|
395
|
+
def with_interrupt_handler
|
|
396
|
+
previous = Signal.trap("INT") { @interrupted = true }
|
|
397
|
+
yield
|
|
398
|
+
ensure
|
|
399
|
+
Signal.trap("INT", previous || "DEFAULT")
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Fetch one page of the specifications index with embed enabled. Goes
|
|
403
|
+
# through the client (the register's fetch path) so the page's
|
|
404
|
+
# embedded_data is populated. Transient 403/5xx/connection failures are
|
|
405
|
+
# already retried upstream (w3c_api/lutaml-hal), but losing an index page
|
|
406
|
+
# drops every spec on it, so retry a few more times here with backoff to
|
|
407
|
+
# ride out a brief wobble. Rate limiting is handled separately, by the
|
|
408
|
+
# governor. Returns nil once the attempts are exhausted (or the crawl is
|
|
409
|
+
# declared banned); the caller turns that into a CrawlIncompleteError so
|
|
410
|
+
# the crawl aborts instead of committing a truncated dataset.
|
|
411
|
+
def fetch_specifications_page(number)
|
|
412
|
+
attempt = 0
|
|
413
|
+
begin
|
|
414
|
+
SafeRealize.governor.wait
|
|
415
|
+
page = client.specifications(embed: true, page: number)
|
|
416
|
+
SafeRealize.governor.succeeded!
|
|
417
|
+
page
|
|
418
|
+
rescue *Governor::THROTTLE_ERRORS => e
|
|
419
|
+
# How long to keep trying a rate-limited page is the governor's call,
|
|
420
|
+
# not this counter's: PAGE_FETCH_ATTEMPTS would give up after ~3
|
|
421
|
+
# minutes and report a *pagination* fault, hiding the real reason and
|
|
422
|
+
# pre-empting the escalation ladder. Retry until the governor declares
|
|
423
|
+
# the crawl banned; #wait above paces each attempt, and returns
|
|
424
|
+
# immediately once it has, so this cannot spin.
|
|
425
|
+
log_error "Rate-limited fetching specifications page #{number}: #{e.message}"
|
|
426
|
+
return nil if SafeRealize.governor.throttled!(retry_after: Governor.retry_after(e))
|
|
427
|
+
|
|
428
|
+
retry
|
|
429
|
+
rescue Lutaml::Hal::Error, Faraday::Error => e
|
|
430
|
+
attempt += 1
|
|
431
|
+
log_error "Failed to fetch specifications page #{number} " \
|
|
432
|
+
"(attempt #{attempt}/#{PAGE_FETCH_ATTEMPTS}): " \
|
|
433
|
+
"#{e.class}: #{e.message}"
|
|
434
|
+
if attempt < PAGE_FETCH_ATTEMPTS
|
|
435
|
+
sleep(2**attempt)
|
|
436
|
+
retry
|
|
437
|
+
end
|
|
438
|
+
nil
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Point w3c_api's rate limiter at UPSTREAM_RATE_LIMITING. This mutates
|
|
443
|
+
# w3c_api's process-wide singleton and is not restored afterwards — the
|
|
444
|
+
# crawler is a standalone script, and a shorter inner retry is the right
|
|
445
|
+
# setting for any caller that has the governor in front of it anyway.
|
|
446
|
+
# Best-effort: the setter is w3c_api's only public knob and is not part of
|
|
447
|
+
# a stable contract, so losing it must not fail the run.
|
|
448
|
+
def configure_upstream_rate_limiting
|
|
449
|
+
hal = W3cApi::Hal.instance
|
|
450
|
+
return unless hal.respond_to?(:configure_rate_limiting)
|
|
451
|
+
|
|
452
|
+
# w3c_api >= 0.3.3 cascades this through reset_client -> rebuild_register
|
|
453
|
+
# itself, so the register no longer goes on serving the old policy.
|
|
454
|
+
# Do NOT add a reset_register call after this: rebuild_register
|
|
455
|
+
# re-registers eagerly on purpose (Link#realize raises when the name is
|
|
456
|
+
# absent from lutaml-hal's GlobalRegister), and tearing it back down
|
|
457
|
+
# would break realize for every model fetched before this point.
|
|
458
|
+
hal.configure_rate_limiting(UPSTREAM_RATE_LIMITING)
|
|
459
|
+
rescue StandardError => e
|
|
460
|
+
Util.warn "Could not configure w3c_api rate limiting: #{e.class}: #{e.message}"
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def spawn_worker(queue)
|
|
464
|
+
Thread.new do
|
|
465
|
+
while (item = queue.pop)
|
|
466
|
+
# Once stopping, drain the queue without processing so the producer
|
|
467
|
+
# unblocks and the pool reaches its poison pills quickly.
|
|
468
|
+
next if stopping?
|
|
469
|
+
|
|
470
|
+
spec, page = item
|
|
471
|
+
begin
|
|
472
|
+
fetch_spec spec, page
|
|
473
|
+
rescue StandardError => e
|
|
474
|
+
log_error "fetch_spec failed: #{e.class}: #{e.message}\n" \
|
|
475
|
+
"#{e.backtrace.first(5).join("\n")}"
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
def parse_and_save(version)
|
|
482
|
+
realized = realize version
|
|
483
|
+
save_doc DataParser.parse(realized) if realized
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
end
|