pubid 2.0.0.pre.alpha.11 → 2.0.0.pre.alpha.13
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 +43 -1
- data/data/ieee/update_codes.yaml +17 -4
- data/data/nist/update_codes.yaml +7 -3
- data/lib/pubid/adobe/builder.rb +2 -0
- data/lib/pubid/all_parts.rb +201 -0
- data/lib/pubid/all_parts_identifier.rb +19 -0
- data/lib/pubid/amca/CLAUDE.md +47 -0
- data/lib/pubid/amca/builder.rb +3 -5
- data/lib/pubid/amca/identifiers/base.rb +10 -0
- data/lib/pubid/amca/identifiers/publication.rb +13 -0
- data/lib/pubid/amca/parser.rb +2 -1
- data/lib/pubid/amca/renderer.rb +22 -33
- data/lib/pubid/amca/urn_generator.rb +21 -2
- data/lib/pubid/amca/urn_parser.rb +36 -10
- data/lib/pubid/ansi/builder.rb +6 -0
- data/lib/pubid/api/CLAUDE.md +23 -0
- data/lib/pubid/api/builder.rb +2 -0
- data/lib/pubid/ashrae/CLAUDE.md +13 -0
- data/lib/pubid/ashrae/builder.rb +58 -14
- data/lib/pubid/ashrae/identifiers/errata.rb +14 -2
- data/lib/pubid/ashrae/identifiers/interpretation.rb +2 -10
- data/lib/pubid/ashrae/parser.rb +62 -28
- data/lib/pubid/ashrae/renderer.rb +32 -1
- data/lib/pubid/ashrae/urn_generator.rb +32 -9
- data/lib/pubid/asme/CLAUDE.md +25 -0
- data/lib/pubid/asme/builder.rb +16 -9
- data/lib/pubid/asme/components/code.rb +2 -0
- data/lib/pubid/asme/identifiers/standard.rb +6 -1
- data/lib/pubid/asme/parser.rb +41 -14
- data/lib/pubid/astm/CLAUDE.md +9 -0
- data/lib/pubid/astm/builder.rb +2 -0
- data/lib/pubid/astm/components/code.rb +2 -0
- data/lib/pubid/astm/parser.rb +4 -1
- data/lib/pubid/bipm/CLAUDE.md +11 -0
- data/lib/pubid/bipm/builder.rb +2 -0
- data/lib/pubid/bsi/CLAUDE.md +93 -0
- data/lib/pubid/bsi/builder.rb +13 -11
- data/lib/pubid/bsi/components/date.rb +10 -4
- data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -0
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +6 -54
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +5 -22
- data/lib/pubid/bsi/identifiers/amendment.rb +36 -12
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -1
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +2 -0
- data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +23 -26
- data/lib/pubid/bsi/identifiers/corrigendum.rb +29 -12
- data/lib/pubid/bsi/identifiers/expert_commentary.rb +6 -7
- data/lib/pubid/bsi/identifiers/handbook.rb +1 -1
- data/lib/pubid/bsi/identifiers/national_annex.rb +18 -20
- data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -1
- data/lib/pubid/bsi/identifiers/root_identity.rb +31 -0
- data/lib/pubid/bsi/identifiers/set.rb +2 -0
- data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -0
- data/lib/pubid/bsi/identifiers.rb +1 -0
- data/lib/pubid/bsi/parser.rb +8 -8
- data/lib/pubid/bsi/renderer.rb +20 -20
- data/lib/pubid/bsi/single_identifier.rb +11 -2
- data/lib/pubid/bsi/urn_generator.rb +28 -18
- data/lib/pubid/builder/base.rb +27 -0
- data/lib/pubid/calconnect/builder.rb +2 -0
- data/lib/pubid/calconnect/identifier.rb +4 -0
- data/lib/pubid/ccsds/builder.rb +2 -0
- data/lib/pubid/ccsds/identifier.rb +12 -0
- data/lib/pubid/ccsds/single_identifier.rb +14 -10
- data/lib/pubid/cen_cenelec/CLAUDE.md +59 -0
- data/lib/pubid/cen_cenelec/builder.rb +6 -1
- data/lib/pubid/cen_cenelec/identifier.rb +10 -27
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +3 -10
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +3 -10
- data/lib/pubid/cen_cenelec/parser.rb +11 -3
- data/lib/pubid/cie/CLAUDE.md +58 -0
- data/lib/pubid/cie/builder.rb +2 -0
- data/lib/pubid/cie/components/language.rb +2 -0
- data/lib/pubid/components/adoption.rb +2 -0
- data/lib/pubid/components/code.rb +2 -0
- data/lib/pubid/components/date.rb +8 -6
- data/lib/pubid/components/edition.rb +2 -0
- data/lib/pubid/components/iteration.rb +2 -0
- data/lib/pubid/components/language.rb +2 -0
- data/lib/pubid/components/locality.rb +2 -0
- data/lib/pubid/components/publisher.rb +2 -0
- data/lib/pubid/components/relationship.rb +2 -0
- data/lib/pubid/components/stage.rb +2 -0
- data/lib/pubid/components/supplement.rb +2 -0
- data/lib/pubid/components/type.rb +2 -0
- data/lib/pubid/components/typed_stage.rb +8 -0
- data/lib/pubid/csa/CLAUDE.md +41 -0
- data/lib/pubid/csa/builder.rb +5 -3
- data/lib/pubid/csa/identifier.rb +13 -1
- data/lib/pubid/csa/identifiers/bundled.rb +2 -2
- data/lib/pubid/csa/identifiers/cec.rb +1 -1
- data/lib/pubid/csa/renderer.rb +12 -12
- data/lib/pubid/csa/single_identifier.rb +18 -1
- data/lib/pubid/csa/urn_generator.rb +1 -1
- data/lib/pubid/doi/builder.rb +2 -0
- data/lib/pubid/easc/builder.rb +2 -0
- data/lib/pubid/ecma/CLAUDE.md +28 -0
- data/lib/pubid/ecma/builder.rb +2 -0
- data/lib/pubid/ecma/identifier.rb +7 -0
- data/lib/pubid/etsi/CLAUDE.md +34 -0
- data/lib/pubid/etsi/builder.rb +2 -0
- data/lib/pubid/etsi/components/code.rb +6 -0
- data/lib/pubid/etsi/components/version.rb +2 -0
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +7 -0
- data/lib/pubid/evs/CLAUDE.md +58 -0
- data/lib/pubid/evs/builder.rb +3 -1
- data/lib/pubid/evs/identifier.rb +6 -6
- data/lib/pubid/evs/identifiers/national_adoption.rb +7 -2
- data/lib/pubid/evs/renderer.rb +1 -1
- data/lib/pubid/evs/urn_generator.rb +1 -1
- data/lib/pubid/evs/urn_parser.rb +1 -1
- data/lib/pubid/gb/CLAUDE.md +140 -0
- data/lib/pubid/gb/builder.rb +21 -11
- data/lib/pubid/gb/identifier.rb +28 -7
- data/lib/pubid/gb/identifiers/all_parts.rb +17 -0
- data/lib/pubid/gb/identifiers.rb +1 -0
- data/lib/pubid/gb/parser.rb +4 -0
- data/lib/pubid/gb/renderer.rb +4 -4
- data/lib/pubid/gb.rb +1 -0
- data/lib/pubid/gost/CLAUDE.md +64 -0
- data/lib/pubid/gost/builder.rb +3 -1
- data/lib/pubid/gost/identifier.rb +5 -0
- data/lib/pubid/iala/CLAUDE.md +82 -0
- data/lib/pubid/iala/builder.rb +2 -0
- data/lib/pubid/iana/CLAUDE.md +7 -0
- data/lib/pubid/iana/builder.rb +2 -0
- data/lib/pubid/identifier.rb +172 -20
- data/lib/pubid/idf/builder.rb +6 -1
- data/lib/pubid/idf/identifier.rb +12 -0
- data/lib/pubid/idf/identifiers/all_parts.rb +17 -0
- data/lib/pubid/idf/identifiers/amendment.rb +1 -1
- data/lib/pubid/idf/identifiers/corrigendum.rb +1 -1
- data/lib/pubid/idf/identifiers/international_standard.rb +1 -1
- data/lib/pubid/idf/identifiers/reviewed_method.rb +1 -1
- data/lib/pubid/idf/identifiers.rb +1 -0
- data/lib/pubid/idf/single_identifier.rb +1 -1
- data/lib/pubid/iec/CLAUDE.md +31 -0
- data/lib/pubid/iec/builder.rb +7 -1
- data/lib/pubid/iec/components/consolidated_amendment.rb +4 -0
- data/lib/pubid/iec/components/sheet.rb +2 -0
- data/lib/pubid/iec/components/trf_info.rb +2 -0
- data/lib/pubid/iec/components/vap_suffix.rb +2 -0
- data/lib/pubid/iec/identifier.rb +7 -2
- data/lib/pubid/iec/identifiers/all_parts.rb +19 -0
- data/lib/pubid/iec/identifiers.rb +1 -0
- data/lib/pubid/iec/renderer.rb +0 -1
- data/lib/pubid/iec/urn_generator.rb +9 -1
- data/lib/pubid/iec/urn_parser.rb +3 -2
- data/lib/pubid/ieee/CLAUDE.md +97 -0
- data/lib/pubid/ieee/builder.rb +176 -7
- data/lib/pubid/ieee/components/code.rb +2 -0
- data/lib/pubid/ieee/components/draft.rb +35 -2
- data/lib/pubid/ieee/components/typed_stage.rb +2 -0
- data/lib/pubid/ieee/identifiers/base.rb +20 -0
- data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +9 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +17 -10
- data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +8 -1
- data/lib/pubid/ieee/identifiers/si_standard.rb +5 -2
- data/lib/pubid/ieee/ire/parser.rb +19 -1
- data/lib/pubid/ieee/parser.rb +337 -49
- data/lib/pubid/ieee/project_renderer.rb +46 -0
- data/lib/pubid/ieee/renderer.rb +46 -14
- data/lib/pubid/ieee/urn_generator.rb +31 -0
- data/lib/pubid/ieee.rb +2 -0
- data/lib/pubid/ietf/CLAUDE.md +7 -0
- data/lib/pubid/ietf/builder.rb +2 -0
- data/lib/pubid/iho/builder.rb +2 -0
- data/lib/pubid/isbn/builder.rb +2 -0
- data/lib/pubid/iso/CLAUDE.md +47 -0
- data/lib/pubid/iso/builder.rb +29 -16
- data/lib/pubid/iso/components/publisher.rb +2 -0
- data/lib/pubid/iso/components.rb +0 -1
- data/lib/pubid/iso/identifier.rb +17 -18
- data/lib/pubid/iso/identifiers/all_parts.rb +19 -0
- data/lib/pubid/iso/identifiers/directives.rb +7 -4
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -2
- data/lib/pubid/iso/identifiers/tc_document.rb +31 -46
- data/lib/pubid/iso/identifiers.rb +1 -0
- data/lib/pubid/iso/normalizer.rb +1 -1
- data/lib/pubid/iso/rendering_style.rb +0 -1
- data/lib/pubid/iso/urn_generator.rb +10 -10
- data/lib/pubid/iso.rb +5 -4
- data/lib/pubid/itu/CLAUDE.md +69 -0
- data/lib/pubid/itu/builder.rb +12 -0
- data/lib/pubid/itu/components/code.rb +2 -0
- data/lib/pubid/itu/components/designation.rb +2 -0
- data/lib/pubid/itu/components/sector.rb +2 -0
- data/lib/pubid/itu/components/series.rb +2 -0
- data/lib/pubid/itu/identifiers/base.rb +10 -0
- data/lib/pubid/itu/identifiers/contribution.rb +31 -0
- data/lib/pubid/itu/identifiers/supplement.rb +15 -0
- data/lib/pubid/itu/identifiers.rb +1 -0
- data/lib/pubid/itu/parser.rb +19 -2
- data/lib/pubid/jcgm/CLAUDE.md +7 -0
- data/lib/pubid/jcgm/builder.rb +2 -0
- data/lib/pubid/jcgm/components/publisher.rb +2 -0
- data/lib/pubid/jis/builder.rb +5 -1
- data/lib/pubid/jis/identifier.rb +5 -17
- data/lib/pubid/jis/identifiers/all_parts.rb +19 -0
- data/lib/pubid/jis/identifiers.rb +1 -0
- data/lib/pubid/jis/renderer.rb +0 -2
- data/lib/pubid/jis/urn_generator.rb +0 -1
- data/lib/pubid/nist/CLAUDE.md +56 -0
- data/lib/pubid/nist/builder.rb +14 -12
- data/lib/pubid/nist/components/edition.rb +2 -0
- data/lib/pubid/nist/components/issue_number.rb +2 -0
- data/lib/pubid/nist/components/part.rb +2 -0
- data/lib/pubid/nist/components/stage.rb +2 -0
- data/lib/pubid/nist/components/supplement.rb +2 -0
- data/lib/pubid/nist/components/translation.rb +2 -0
- data/lib/pubid/nist/components/update.rb +2 -0
- data/lib/pubid/nist/components/version.rb +2 -0
- data/lib/pubid/nist/components/volume.rb +2 -0
- data/lib/pubid/nist/identifiers/base.rb +34 -6
- data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
- data/lib/pubid/nist/identifiers/crpl_report.rb +5 -6
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +2 -2
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
- data/lib/pubid/nist/parser.rb +15 -2
- data/lib/pubid/nist/preprocessor.rb +53 -2
- data/lib/pubid/nist/series/ir.rb +3 -7
- data/lib/pubid/oasis/CLAUDE.md +19 -0
- data/lib/pubid/oasis/builder.rb +2 -0
- data/lib/pubid/oasis/identifier.rb +19 -0
- data/lib/pubid/ogc/CLAUDE.md +34 -0
- data/lib/pubid/ogc/builder.rb +2 -0
- data/lib/pubid/ogc/identifier.rb +11 -0
- data/lib/pubid/oiml/CLAUDE.md +189 -0
- data/lib/pubid/oiml/builder.rb +22 -2
- data/lib/pubid/oiml/components/code.rb +6 -0
- data/lib/pubid/oiml/identifier.rb +13 -0
- data/lib/pubid/oiml/identifiers/annex.rb +4 -0
- data/lib/pubid/oiml/identifiers/bulletin.rb +30 -36
- data/lib/pubid/oiml/identifiers/certification_system.rb +34 -0
- data/lib/pubid/oiml/identifiers/code_number.rb +10 -2
- data/lib/pubid/oiml/identifiers/dual_published.rb +174 -0
- data/lib/pubid/oiml/identifiers.rb +2 -0
- data/lib/pubid/oiml/parser.rb +41 -5
- data/lib/pubid/oiml/renderer.rb +26 -4
- data/lib/pubid/oiml/single_identifier.rb +5 -1
- data/lib/pubid/oiml/supplement_identifier.rb +7 -0
- data/lib/pubid/oiml/urn_generator.rb +32 -4
- data/lib/pubid/oiml.rb +5 -0
- data/lib/pubid/omg/CLAUDE.md +15 -0
- data/lib/pubid/omg/builder.rb +2 -0
- data/lib/pubid/parser/grammar.rb +23 -0
- data/lib/pubid/plateau/builder.rb +2 -0
- data/lib/pubid/plateau/identifiers/base.rb +4 -0
- data/lib/pubid/plateau/supplement_identifier.rb +14 -2
- data/lib/pubid/plateau/urn_generator.rb +7 -1
- data/lib/pubid/renderers/directives_renderer.rb +3 -1
- data/lib/pubid/renderers/human_readable.rb +0 -1
- data/lib/pubid/sae/builder.rb +3 -1
- data/lib/pubid/sae/components/date.rb +2 -0
- data/lib/pubid/sae/components/type.rb +2 -0
- data/lib/pubid/sae/identifiers/base.rb +4 -1
- data/lib/pubid/sae/urn_generator.rb +1 -1
- data/lib/pubid/subset_match.rb +197 -0
- data/lib/pubid/tgpp/CLAUDE.md +43 -0
- data/lib/pubid/tgpp/builder.rb +2 -0
- data/lib/pubid/tgpp/identifier.rb +14 -0
- data/lib/pubid/type_resolver.rb +14 -2
- data/lib/pubid/un/builder.rb +2 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/CLAUDE.md +7 -0
- data/lib/pubid/w3c/builder.rb +2 -0
- data/lib/pubid/xsf/CLAUDE.md +11 -0
- data/lib/pubid/xsf/builder.rb +2 -0
- data/lib/pubid.rb +16 -3
- data/lib/tasks/docs.rake +13 -11
- metadata +46 -4
- data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +0 -70
- data/lib/pubid/iso/components/code.rb +0 -24
|
@@ -33,49 +33,43 @@ module Pubid
|
|
|
33
33
|
# carried in the structured form and the roman volume in citations.
|
|
34
34
|
BASE_YEAR_OFFSET = 1959
|
|
35
35
|
|
|
36
|
-
#
|
|
37
|
-
# for the online-bulletin series). Always 2 digits.
|
|
38
|
-
|
|
36
|
+
# The issue: the zero-padded number within the volume ("01".."04",
|
|
37
|
+
# plus "07"/"10" for the online-bulletin series). Always 2 digits. The
|
|
38
|
+
# year is the volume and the issue is the number, as in the citation
|
|
39
|
+
# form "LXVII(2)".
|
|
40
|
+
#
|
|
41
|
+
# Declared as `number`, so it is the relaton index key
|
|
42
|
+
# (`id.root.number.to_s`) and every index row with an issue shows a
|
|
43
|
+
# `number`. The key puts the same issue number of all volumes in one
|
|
44
|
+
# bucket; the MR slug keeps each article distinct.
|
|
45
|
+
#
|
|
46
|
+
# Declared on this LEAF, which has no subclasses. It redefines the
|
|
47
|
+
# `Components::Code number` of ::Pubid::Identifier as a :string, and a
|
|
48
|
+
# redefinition on a class that other classes inherit is the
|
|
49
|
+
# multi-flavor determinism landmine (see Identifiers::CodeNumber).
|
|
50
|
+
#
|
|
51
|
+
# nil for a volume ("OIML Bulletin 1960") and for the bare periodical
|
|
52
|
+
# reference "OIML Bulletin", which name no issue.
|
|
53
|
+
attribute :number, :string
|
|
39
54
|
# Zero-padded sequence within the issue ("00" = editorial, "01"+ for
|
|
40
55
|
# articles). Always 2 digits.
|
|
41
56
|
attribute :sequence, :string
|
|
42
57
|
|
|
43
58
|
key_value do
|
|
44
|
-
map "
|
|
59
|
+
map "number", to: :number
|
|
45
60
|
map "sequence", to: :sequence
|
|
46
61
|
end
|
|
47
62
|
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# distinctness coming from the MR slug instead. That is the BIPM
|
|
53
|
-
# Metrologia-volume precedent recorded in CLAUDE.md.
|
|
54
|
-
#
|
|
55
|
-
# A DERIVED READER, deliberately not an attribute: storing it would
|
|
56
|
-
# duplicate `year` in every row, and the key_value block above maps no
|
|
57
|
-
# "number", so nothing is added to the wire format. Safe as a plain
|
|
58
|
-
# method because Bulletin declares no `number` attribute of its own
|
|
59
|
-
# (the ITU itu/identifiers/base.rb precedent).
|
|
60
|
-
#
|
|
61
|
-
# nil for the bare periodical reference "OIML Bulletin", which names no
|
|
62
|
-
# year — a deliberate gap, pinned in spec/pubid/oiml/root_number_spec.rb.
|
|
63
|
-
def number
|
|
64
|
-
date&.year&.to_s
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# The index key above is deliberately coarse — a whole volume in one
|
|
68
|
-
# bucket — which is only defensible because the MR slug stays
|
|
69
|
-
# per-article. The inherited hook reads through `code`, which Bulletin
|
|
70
|
-
# does not have, so it would return nil and collapse every article of a
|
|
71
|
-
# year onto `oiml.bulletin.<year>`; `to_slug` is an output FILENAME, so
|
|
72
|
-
# that is an overwrite. Emit the rest of the locator instead.
|
|
63
|
+
# The inherited hook reads through `code`, which Bulletin does not
|
|
64
|
+
# have, so it would return nil and collapse every article of a year
|
|
65
|
+
# onto `oiml.bulletin.<year>`; `to_slug` is an output FILENAME, so that
|
|
66
|
+
# is an overwrite. Emit the rest of the locator instead.
|
|
73
67
|
#
|
|
74
68
|
# The year is deliberately NOT included: Renderers::MrString already
|
|
75
69
|
# gives it its own segment (`mr_year`), so repeating it here would
|
|
76
70
|
# render `oiml.bulletin.1960-03-01.1960`.
|
|
77
71
|
def mr_number_with_part
|
|
78
|
-
segments = [
|
|
72
|
+
segments = [number, sequence].compact
|
|
79
73
|
return nil if segments.empty?
|
|
80
74
|
|
|
81
75
|
segments.join("-")
|
|
@@ -96,18 +90,18 @@ module Pubid
|
|
|
96
90
|
# Volume as a roman-numeral string ("LXVII"), derived from the year.
|
|
97
91
|
# nil when the year is absent.
|
|
98
92
|
def volume_roman
|
|
99
|
-
|
|
100
|
-
return nil unless
|
|
93
|
+
volume = volume_arabic&.to_i
|
|
94
|
+
return nil unless volume&.positive?
|
|
101
95
|
|
|
102
|
-
self.class.to_roman(
|
|
96
|
+
self.class.to_roman(volume)
|
|
103
97
|
end
|
|
104
98
|
|
|
105
99
|
# 8-digit oiml.org article id ("20260211"). Composed by concatenating
|
|
106
|
-
# year + issue + sequence. nil unless all three are present.
|
|
100
|
+
# year + issue (number) + sequence. nil unless all three are present.
|
|
107
101
|
def article_id
|
|
108
|
-
return nil unless date&.year &&
|
|
102
|
+
return nil unless date&.year && number && sequence
|
|
109
103
|
|
|
110
|
-
"#{date.year}#{
|
|
104
|
+
"#{date.year}#{number}#{sequence}"
|
|
111
105
|
end
|
|
112
106
|
|
|
113
107
|
class << self
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Oiml
|
|
5
|
+
module Identifiers
|
|
6
|
+
# OIML-CS certification-system documents ("OIML-CS PD-05 Edition 6").
|
|
7
|
+
# The number keeps its printed zero padding ("05"); family is the
|
|
8
|
+
# PD/OD/CID document class; the print states "Edition N" instead of a
|
|
9
|
+
# year, and may carry a parenthesized trailing amendment.
|
|
10
|
+
class CertificationSystem < SingleIdentifier
|
|
11
|
+
attribute :number, :string
|
|
12
|
+
attribute :family, :string
|
|
13
|
+
attribute :amendment, :string
|
|
14
|
+
# "PD 05" prints space-separated where "PD-05" is dash-joined.
|
|
15
|
+
attribute :space_separator, :boolean, default: false
|
|
16
|
+
|
|
17
|
+
key_value do
|
|
18
|
+
map "number", to: :number
|
|
19
|
+
map "family", to: :family
|
|
20
|
+
map "amendment", to: :amendment
|
|
21
|
+
map "space_separator", to: :space_separator
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.subset_ignored_attributes
|
|
25
|
+
super + [:space_separator]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def type_string
|
|
29
|
+
"CS"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -28,12 +28,13 @@ module Pubid
|
|
|
28
28
|
#
|
|
29
29
|
# Bulletin deliberately does NOT include this module. It carries no code
|
|
30
30
|
# at all (its locator is the year/issue/sequence tuple), so it would only
|
|
31
|
-
# gain
|
|
32
|
-
#
|
|
31
|
+
# gain permanently-nil part/subpart/suffix columns. It declares its own
|
|
32
|
+
# `number` (the issue) instead; see bulletin.rb.
|
|
33
33
|
module CodeNumber
|
|
34
34
|
def self.included(base)
|
|
35
35
|
install_attributes(base)
|
|
36
36
|
install_mappings(base)
|
|
37
|
+
install_subset_rules(base)
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
def self.install_attributes(base)
|
|
@@ -53,6 +54,13 @@ module Pubid
|
|
|
53
54
|
base.attribute :space_suffix, :boolean, default: -> { false }
|
|
54
55
|
end
|
|
55
56
|
|
|
57
|
+
# A nil `part`, `subpart` or `suffix` means the document has none of
|
|
58
|
+
# them: `OIML R 138` is not `OIML R 138-Amend`, which is its
|
|
59
|
+
# amendment. Declared on each leaf, beside the columns it governs.
|
|
60
|
+
def self.install_subset_rules(base)
|
|
61
|
+
base.subset_strict :part, :subpart, :suffix
|
|
62
|
+
end
|
|
63
|
+
|
|
56
64
|
# Merged by lutaml with the block SingleIdentifier declares, which
|
|
57
65
|
# carries publisher/year/edition/stage/iteration.
|
|
58
66
|
def self.install_mappings(base)
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Oiml
|
|
5
|
+
module Identifiers
|
|
6
|
+
# OIML sometimes co-publishes a document jointly with another SDO
|
|
7
|
+
# (ISO confirmed so far, per pubid issue #437). The printed reference
|
|
8
|
+
# carries both identifiers, joined by a bare "|":
|
|
9
|
+
#
|
|
10
|
+
# ISO 4064-1:2024|OIML R 49-1:2024
|
|
11
|
+
#
|
|
12
|
+
# A sibling of SingleIdentifier/SupplementIdentifier — like
|
|
13
|
+
# SupplementIdentifier, it inherits NOTHING from SingleIdentifier and
|
|
14
|
+
# must delegate every identity-bearing reader (code/type/stage/
|
|
15
|
+
# iteration/publisher, the mr_* MR-slug hooks, #root) itself. Without
|
|
16
|
+
# the mr_* delegations, #to_mr_string would silently come out "" (the
|
|
17
|
+
# same filename-collision gap already documented for
|
|
18
|
+
# Amendment/Errata/Annex in lib/pubid/oiml/CLAUDE.md) — this class closes
|
|
19
|
+
# that gap from day one instead of repeating it.
|
|
20
|
+
#
|
|
21
|
+
# `first`/`second` hold the two sides in their original left-to-right
|
|
22
|
+
# print order, each a real, independently-typed `::Pubid::Identifier`
|
|
23
|
+
# (never an attr_accessor — see IEEE's CsaDualPublished for the bug
|
|
24
|
+
# that pattern causes: to_hash/from_hash/#exclude silently drop it).
|
|
25
|
+
# Either side may be OIML; `#oiml_identifier`/`#external_identifier`
|
|
26
|
+
# pick the OIML-typed one out of the pair regardless of order.
|
|
27
|
+
class DualPublished < Identifier
|
|
28
|
+
attribute :first, ::Pubid::Identifier, polymorphic: true
|
|
29
|
+
attribute :second, ::Pubid::Identifier, polymorphic: true
|
|
30
|
+
|
|
31
|
+
# Declared locally (rather than left to the inherited default)
|
|
32
|
+
# because Oiml::Identifier's shared key_value block maps "language"
|
|
33
|
+
# and "parsed_format" to real attributes — without a local
|
|
34
|
+
# declaration here, to_hash/from_hash would call a getter/setter
|
|
35
|
+
# this class never defines. Mirrors SingleIdentifier/
|
|
36
|
+
# SupplementIdentifier, which do the same for the same reason.
|
|
37
|
+
attribute :language, :string
|
|
38
|
+
attribute :parsed_format, :string, default: -> { "short" }
|
|
39
|
+
|
|
40
|
+
key_value do
|
|
41
|
+
map "first", with: { to: :first_to_kv, from: :first_from_kv }
|
|
42
|
+
map "second", with: { to: :second_to_kv, from: :second_from_kv }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Either side may belong to any flavor, so (de)serialization goes
|
|
46
|
+
# through the generic top-level Pubid.from_hash/#to_hash, not the
|
|
47
|
+
# OIML-scoped Identifier.from_hash (which only resolves OIML types).
|
|
48
|
+
def first_to_kv(model, doc)
|
|
49
|
+
value = model.first
|
|
50
|
+
return unless value
|
|
51
|
+
|
|
52
|
+
doc.add_child(
|
|
53
|
+
Lutaml::KeyValue::DataModel::Element.new("first", value.to_hash),
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def first_from_kv(model, value)
|
|
58
|
+
model.first = ::Pubid.from_hash(value) if value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def second_to_kv(model, doc)
|
|
62
|
+
value = model.second
|
|
63
|
+
return unless value
|
|
64
|
+
|
|
65
|
+
doc.add_child(
|
|
66
|
+
Lutaml::KeyValue::DataModel::Element.new("second", value.to_hash),
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def second_from_kv(model, value)
|
|
71
|
+
model.second = ::Pubid.from_hash(value) if value
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The member that belongs to THIS flavor, wherever print order put
|
|
75
|
+
# it. relaton-index sorts on this side's root.number.
|
|
76
|
+
def oiml_identifier
|
|
77
|
+
[first, second].find { |member| member.is_a?(Oiml::Identifier) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The other SDO's identifier for the same document.
|
|
81
|
+
def external_identifier
|
|
82
|
+
[first, second].find { |member| !member.is_a?(Oiml::Identifier) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def root
|
|
86
|
+
oiml_identifier ? oiml_identifier.root : self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def code
|
|
90
|
+
oiml_identifier&.code
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def type
|
|
94
|
+
oiml_identifier&.type
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def stage
|
|
98
|
+
oiml_identifier&.stage
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def iteration
|
|
102
|
+
oiml_identifier&.iteration
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def publisher
|
|
106
|
+
oiml_identifier&.publisher
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def mr_publisher
|
|
110
|
+
oiml_identifier&.mr_publisher
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def mr_type
|
|
114
|
+
oiml_identifier&.mr_type
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def mr_number_with_part
|
|
118
|
+
oiml_identifier&.mr_number_with_part
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def mr_year
|
|
122
|
+
oiml_identifier&.mr_year
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Splits `identifier` on "|" and, if it looks like an OIML dual-
|
|
126
|
+
# published reference (exactly two non-empty sides, exactly one of
|
|
127
|
+
# which starts with an OIML prefix), parses each side through its
|
|
128
|
+
# own flavor and returns the wrapper. Returns nil for anything else,
|
|
129
|
+
# so the caller (Pubid::Oiml.parse) falls through to the ordinary
|
|
130
|
+
# grammar, which raises the standard Parslet::ParseFailed for a
|
|
131
|
+
# string containing "|" (the grammar defines no rule for it).
|
|
132
|
+
def self.build(identifier)
|
|
133
|
+
sides = split_sides(identifier)
|
|
134
|
+
return nil unless sides
|
|
135
|
+
|
|
136
|
+
left, right = parse_sides(*sides)
|
|
137
|
+
return nil unless left && right
|
|
138
|
+
|
|
139
|
+
new(first: left, second: right)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Two non-empty, stripped sides, or nil if `identifier` isn't
|
|
143
|
+
# shaped like "A|B".
|
|
144
|
+
def self.split_sides(identifier)
|
|
145
|
+
parts = identifier.split("|").map(&:strip)
|
|
146
|
+
return nil unless parts.length == 2
|
|
147
|
+
return nil if parts.any?(&:empty?)
|
|
148
|
+
|
|
149
|
+
parts
|
|
150
|
+
end
|
|
151
|
+
private_class_method :split_sides
|
|
152
|
+
|
|
153
|
+
# Parses each side through its own flavor, provided exactly one side
|
|
154
|
+
# looks like OIML (by prefix, not position). [nil, nil] otherwise.
|
|
155
|
+
def self.parse_sides(left, right)
|
|
156
|
+
left_is_oiml = Oiml::PREFIXES.any? { |p| left.start_with?(p) }
|
|
157
|
+
right_is_oiml = Oiml::PREFIXES.any? { |p| right.start_with?(p) }
|
|
158
|
+
return [nil, nil] if left_is_oiml == right_is_oiml
|
|
159
|
+
|
|
160
|
+
[parse_side(left, oiml: left_is_oiml),
|
|
161
|
+
parse_side(right, oiml: right_is_oiml)]
|
|
162
|
+
end
|
|
163
|
+
private_class_method :parse_sides
|
|
164
|
+
|
|
165
|
+
def self.parse_side(str, oiml:)
|
|
166
|
+
oiml ? Oiml.parse(str) : ::Pubid.parse(str)
|
|
167
|
+
rescue Parslet::ParseFailed, Pubid::Errors::InvalidInputError
|
|
168
|
+
nil
|
|
169
|
+
end
|
|
170
|
+
private_class_method :parse_side
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -7,8 +7,10 @@ module Pubid
|
|
|
7
7
|
autoload :Annex, "#{__dir__}/identifiers/annex"
|
|
8
8
|
autoload :BasicPublication, "#{__dir__}/identifiers/basic_publication"
|
|
9
9
|
autoload :Bulletin, "#{__dir__}/identifiers/bulletin"
|
|
10
|
+
autoload :CertificationSystem, "#{__dir__}/identifiers/certification_system"
|
|
10
11
|
autoload :CodeNumber, "#{__dir__}/identifiers/code_number"
|
|
11
12
|
autoload :Document, "#{__dir__}/identifiers/document"
|
|
13
|
+
autoload :DualPublished, "#{__dir__}/identifiers/dual_published"
|
|
12
14
|
autoload :Errata, "#{__dir__}/identifiers/errata"
|
|
13
15
|
autoload :ExpertReport, "#{__dir__}/identifiers/expert_report"
|
|
14
16
|
autoload :Guide, "#{__dir__}/identifiers/guide"
|
data/lib/pubid/oiml/parser.rb
CHANGED
|
@@ -20,14 +20,17 @@ module Pubid
|
|
|
20
20
|
rule(:identifier) do
|
|
21
21
|
amendment_identifier | amendment_short | annex_letter_identifier |
|
|
22
22
|
annex_identifier | plus_supplement_identifier |
|
|
23
|
-
trailing_supplement_identifier |
|
|
23
|
+
trailing_supplement_identifier | cs_identifier |
|
|
24
|
+
bulletin_identifier | base
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
# Publisher - always "OIML"
|
|
27
28
|
rule(:publisher) { str("OIML").as(:publisher) >> space }
|
|
28
29
|
|
|
29
|
-
# Document type - single letter
|
|
30
|
-
|
|
30
|
+
# Document type - single letter. Strict family set: OIML publishes
|
|
31
|
+
# R D B G E V S documents (the estate grammar's family letters);
|
|
32
|
+
# any other letter is a rejection, not a flavor.
|
|
33
|
+
rule(:doc_type) { match("[BDEGRSV]").as(:type) >> space }
|
|
31
34
|
|
|
32
35
|
# Bulletin locator — structured form. Year optionally followed by
|
|
33
36
|
# 2-digit issue and 2-digit sequence:
|
|
@@ -122,9 +125,14 @@ module Pubid
|
|
|
122
125
|
).as(:edition_format) # Wrap entire match to capture that Edition was used
|
|
123
126
|
end
|
|
124
127
|
|
|
125
|
-
# Date - year after colon
|
|
128
|
+
# Date - year after colon, the VIM's paren-year form ("OIML V 2-200
|
|
129
|
+
# (2000)" — space + (YYYY) instead of :YYYY, the shape #342 flags as
|
|
130
|
+
# the one real-world spelling that did not parse), OR edition portion
|
|
131
|
+
# (with optional space before year)
|
|
126
132
|
rule(:date) do
|
|
127
|
-
edition_portion |
|
|
133
|
+
edition_portion |
|
|
134
|
+
(space.maybe >> colon >> space.maybe >> year_digits.as(:year)) |
|
|
135
|
+
(space.maybe >> lparen >> year_digits.as(:year) >> rparen)
|
|
128
136
|
end
|
|
129
137
|
|
|
130
138
|
# Draft stage - WD or CD with optional iteration
|
|
@@ -162,10 +170,22 @@ module Pubid
|
|
|
162
170
|
match("[a-z]").repeat(2, 2) # Two letters: en, fr, etc.
|
|
163
171
|
end
|
|
164
172
|
|
|
173
|
+
# Full-word language markers as OIML prints them ("(Fra)", "(Eng)"),
|
|
174
|
+
# three or more letters, any case. Kept verbatim on the identifier;
|
|
175
|
+
# the URN lowercases.
|
|
176
|
+
rule(:lang_word) do
|
|
177
|
+
match("[A-Za-z]").repeat(3)
|
|
178
|
+
end
|
|
179
|
+
|
|
165
180
|
rule(:language_code) do
|
|
166
181
|
(
|
|
167
182
|
(lang_single >> slash >> lang_single) | # E/F
|
|
168
183
|
lang_multi_oiml | # PO, PT, PE, SR
|
|
184
|
+
lang_word | # Fra, eng, rus — before
|
|
185
|
+
# the letter rules: a
|
|
186
|
+
# committed "F" of "(Fra)"
|
|
187
|
+
# or "fr" of "(fra)" would
|
|
188
|
+
# never fall through
|
|
169
189
|
lang_single | # E, F, D, R, S, C, A, U, X
|
|
170
190
|
lang_multi # en, fr
|
|
171
191
|
).as(:language)
|
|
@@ -211,9 +231,25 @@ module Pubid
|
|
|
211
231
|
rule(:trailing_supplement_identifier) do
|
|
212
232
|
base_without_language.as(:base) >>
|
|
213
233
|
space >> (str("Amendment") | str("Errata")).as(:trailing_marker) >>
|
|
234
|
+
(space >> digits.as(:number)).maybe >>
|
|
214
235
|
language_portion.maybe.as(:language)
|
|
215
236
|
end
|
|
216
237
|
|
|
238
|
+
# OIML-CS certification-system documents. Two head spellings
|
|
239
|
+
# ("OIML-CS" / "OIML CS") and two family-number separators
|
|
240
|
+
# ("PD-05" / "PD 05"), an "Edition N" instead of a year, and an
|
|
241
|
+
# optional parenthesized trailing amendment - "(Amendment 1)".
|
|
242
|
+
rule(:cs_identifier) do
|
|
243
|
+
str("OIML").as(:publisher) >>
|
|
244
|
+
(dash >> str("CS") | space >> str("CS")).as(:cs_series) >> space >>
|
|
245
|
+
(str("PD") | str("OD") | str("CID")).as(:cs_family) >>
|
|
246
|
+
(dash | space).as(:cs_separator) >>
|
|
247
|
+
digits.as(:number) >>
|
|
248
|
+
space >> str("Edition") >> space >> digits.as(:edition) >>
|
|
249
|
+
(space >> lparen >> str("Amendment") >> space >>
|
|
250
|
+
digits.as(:cs_amendment) >> rparen).maybe
|
|
251
|
+
end
|
|
252
|
+
|
|
217
253
|
# Plus-joined supplement - "BASE:YEAR+Supplement:YEAR" form where both
|
|
218
254
|
# the base and the supplement carry their own year. Used for amendments
|
|
219
255
|
# and errata to dated bases (e.g. "OIML B 10:2011+Amendment:2012").
|
data/lib/pubid/oiml/renderer.rb
CHANGED
|
@@ -18,10 +18,14 @@ module Pubid
|
|
|
18
18
|
@context = context
|
|
19
19
|
|
|
20
20
|
case id
|
|
21
|
+
when Identifiers::DualPublished
|
|
22
|
+
render_dual_published(id)
|
|
21
23
|
when Identifiers::Annex
|
|
22
24
|
render_annex(id)
|
|
23
25
|
when Identifiers::Bulletin
|
|
24
26
|
render_bulletin(id)
|
|
27
|
+
when Identifiers::CertificationSystem
|
|
28
|
+
render_cs(id)
|
|
25
29
|
when SupplementIdentifier
|
|
26
30
|
render_supplement(id)
|
|
27
31
|
when SingleIdentifier
|
|
@@ -33,6 +37,16 @@ module Pubid
|
|
|
33
37
|
|
|
34
38
|
private
|
|
35
39
|
|
|
40
|
+
# Certification-system document: "OIML-CS PD-05 Edition 6 (Amendment 1)".
|
|
41
|
+
# The family-number separator keeps the parsed spelling; OIML CS
|
|
42
|
+
# documents state an edition instead of a year.
|
|
43
|
+
def render_cs(id)
|
|
44
|
+
result = "#{id.publisher}-CS #{id.family}" \
|
|
45
|
+
"#{id.space_separator ? ' ' : '-'}#{id.number} Edition #{id.edition}"
|
|
46
|
+
result += " (Amendment #{id.amendment})" if id.amendment
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
|
|
36
50
|
# Render the Bulletin in the requested or parsed form. Default is the
|
|
37
51
|
# structured "YYYY-II-SS" form (the dataset's primary docid). The
|
|
38
52
|
# citation form ("LXVII(2) 20260211") is emitted when the user asks
|
|
@@ -65,7 +79,7 @@ module Pubid
|
|
|
65
79
|
result = "#{id.publisher} Bulletin"
|
|
66
80
|
if id.date&.year
|
|
67
81
|
result += " #{id.date.year}"
|
|
68
|
-
result += "-#{id.
|
|
82
|
+
result += "-#{id.number}" if id.number
|
|
69
83
|
result += "-#{id.sequence}" if id.sequence
|
|
70
84
|
end
|
|
71
85
|
result += " (#{id.language})" if id.language
|
|
@@ -77,9 +91,9 @@ module Pubid
|
|
|
77
91
|
# structured since OIML's citation format doesn't define volume-only
|
|
78
92
|
# or issue-only variants.
|
|
79
93
|
def render_bulletin_citation(id)
|
|
80
|
-
return render_bulletin_structured(id) unless id.date&.year && id.
|
|
94
|
+
return render_bulletin_structured(id) unless id.date&.year && id.number && id.sequence
|
|
81
95
|
|
|
82
|
-
"#{id.publisher} Bulletin #{id.volume_roman}(#{id.
|
|
96
|
+
"#{id.publisher} Bulletin #{id.volume_roman}(#{id.number.to_i}) #{id.article_id}"
|
|
83
97
|
end
|
|
84
98
|
|
|
85
99
|
def effective_format(id)
|
|
@@ -93,6 +107,12 @@ module Pubid
|
|
|
93
107
|
str.sub(/\s*\([^)]+\)\s*$/, "").strip
|
|
94
108
|
end
|
|
95
109
|
|
|
110
|
+
# Bare "|", original left-to-right print order, e.g.
|
|
111
|
+
# "ISO 4064-1:2024|OIML R 49-1:2024".
|
|
112
|
+
def render_dual_published(id)
|
|
113
|
+
"#{id.first}|#{id.second}"
|
|
114
|
+
end
|
|
115
|
+
|
|
96
116
|
def render_single(id)
|
|
97
117
|
format = effective_format(id)
|
|
98
118
|
|
|
@@ -147,10 +167,12 @@ module Pubid
|
|
|
147
167
|
|
|
148
168
|
# Trailing-word shorthand: "BASE Amendment" / "BASE Errata" with the
|
|
149
169
|
# publication year kept on the base identifier. The word comes from the
|
|
150
|
-
# concrete supplement class
|
|
170
|
+
# concrete supplement class; an ordinal, when printed ("Amendment 1"),
|
|
171
|
+
# follows it.
|
|
151
172
|
if id.trailing
|
|
152
173
|
base_str = strip_language(id.base.to_s)
|
|
153
174
|
result = "#{base_str} #{id.supplement_type}"
|
|
175
|
+
result += " #{id.number}" if id.number
|
|
154
176
|
result += " (#{id.language})" if id.language
|
|
155
177
|
return result
|
|
156
178
|
end
|
|
@@ -14,6 +14,10 @@ module Pubid
|
|
|
14
14
|
"short"
|
|
15
15
|
} # Track parsed format
|
|
16
16
|
|
|
17
|
+
# A nil `language` means the document states none: `OIML R 126:2015
|
|
18
|
+
# Errata` is not `OIML R 126:2015 Errata (E)`, its English edition.
|
|
19
|
+
subset_strict :language
|
|
20
|
+
|
|
17
21
|
# Serialization delta on top of Oiml::Identifier's shared block. The
|
|
18
22
|
# `date` (year) component is flattened to a top-level key rather than a
|
|
19
23
|
# nested hash, mirroring ISO (lib/pubid/iso/identifier.rb). `type` is
|
|
@@ -24,7 +28,7 @@ module Pubid
|
|
|
24
28
|
# concrete leaf, because redefining the inherited `number` on this class
|
|
25
29
|
# — which every leaf inherits — is the multi-flavor determinism landmine.
|
|
26
30
|
# Keeping the mapping with the attribute is also what lets Bulletin, the
|
|
27
|
-
# one leaf with no code,
|
|
31
|
+
# one leaf with no code, declare its own `number` (the issue) and map it.
|
|
28
32
|
key_value do
|
|
29
33
|
map "publisher", to: :publisher
|
|
30
34
|
map "year", with: { to: :year_to_kv, from: :year_from_kv }
|
|
@@ -7,8 +7,14 @@ module Pubid
|
|
|
7
7
|
# These wrap a base identifier like ISO amendments
|
|
8
8
|
attribute :base, Oiml::Identifier, polymorphic: true
|
|
9
9
|
attribute :year, :string
|
|
10
|
+
# Ordinal of the trailing-word form ("OIML R 138:2009 Amendment 1").
|
|
11
|
+
attribute :number, :string
|
|
10
12
|
attribute :language, :string
|
|
11
13
|
|
|
14
|
+
# A nil `language` means the document states none, mirroring
|
|
15
|
+
# SingleIdentifier's rule.
|
|
16
|
+
subset_strict :language
|
|
17
|
+
|
|
12
18
|
# Delegate the document code to the wrapped standard, mirroring
|
|
13
19
|
# Pubid::Etsi::Identifiers::SupplementIdentifier#code.
|
|
14
20
|
#
|
|
@@ -54,6 +60,7 @@ module Pubid
|
|
|
54
60
|
map "base",
|
|
55
61
|
with: { to: :base_to_kv, from: :base_from_kv }
|
|
56
62
|
map "year", to: :year
|
|
63
|
+
map "number", to: :number
|
|
57
64
|
map "trailing", to: :trailing
|
|
58
65
|
map "joined", to: :joined
|
|
59
66
|
end
|
|
@@ -27,6 +27,25 @@ module Pubid
|
|
|
27
27
|
identifier.language&.to_s&.downcase
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# DualPublished declares no `date` attribute of its own (it lives on
|
|
31
|
+
# whichever side is OIML), so the shared Base#urn_year — which gates
|
|
32
|
+
# on `identifier.class.attributes.key?(:date)` — would silently drop
|
|
33
|
+
# the year. Read it through the OIML side instead.
|
|
34
|
+
def urn_year
|
|
35
|
+
if identifier.is_a?(Identifiers::DualPublished)
|
|
36
|
+
oiml_date = identifier.oiml_identifier&.date
|
|
37
|
+
return oiml_date&.year&.to_s
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
year = super
|
|
41
|
+
return year if year
|
|
42
|
+
|
|
43
|
+
# The trailing-word form keeps the publication year on the base
|
|
44
|
+
# ("R 138:2009 Amendment 1"); the supplement itself carries only the
|
|
45
|
+
# ordinal.
|
|
46
|
+
identifier.base&.date&.year&.to_s if identifier.is_a?(SupplementIdentifier)
|
|
47
|
+
end
|
|
48
|
+
|
|
30
49
|
def generate
|
|
31
50
|
# Bulletin issues carry no code; the (year, issue, sequence) tuple
|
|
32
51
|
# is the locator. URNs are canonical regardless of how the input was
|
|
@@ -39,6 +58,15 @@ module Pubid
|
|
|
39
58
|
return parts.join(":")
|
|
40
59
|
end
|
|
41
60
|
|
|
61
|
+
# Certification-system documents: the family-number pair is the
|
|
62
|
+
# document identity ("cs:pd-05"); the printed edition and trailing
|
|
63
|
+
# amendment are print states, not URN segments.
|
|
64
|
+
if identifier.is_a?(Identifiers::CertificationSystem)
|
|
65
|
+
parts = ["urn", "oiml", "cs",
|
|
66
|
+
"#{identifier.family.downcase}-#{identifier.number}"]
|
|
67
|
+
return parts.join(":")
|
|
68
|
+
end
|
|
69
|
+
|
|
42
70
|
parts = ["urn", "oiml"]
|
|
43
71
|
parts << urn_type
|
|
44
72
|
parts << urn_number if urn_number
|
|
@@ -64,12 +92,12 @@ module Pubid
|
|
|
64
92
|
end
|
|
65
93
|
|
|
66
94
|
# Structured locator "YYYY-II-SS" (or "YYYY-II" / "YYYY") for a Bulletin.
|
|
67
|
-
# Built directly from the date year and the issue
|
|
68
|
-
# the URN is identical regardless of whether the
|
|
69
|
-
# or citation form.
|
|
95
|
+
# Built directly from the date year and the number (the issue) and
|
|
96
|
+
# sequence attributes so the URN is identical regardless of whether the
|
|
97
|
+
# input was the structured or citation form.
|
|
70
98
|
def bulletin_locator
|
|
71
99
|
locator = identifier.date.year.to_s
|
|
72
|
-
locator += "-#{identifier.
|
|
100
|
+
locator += "-#{identifier.number}" if identifier.number
|
|
73
101
|
locator += "-#{identifier.sequence}" if identifier.sequence
|
|
74
102
|
locator
|
|
75
103
|
end
|
data/lib/pubid/oiml.rb
CHANGED
|
@@ -29,6 +29,11 @@ module Pubid
|
|
|
29
29
|
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
if identifier.include?("|")
|
|
33
|
+
dual = Identifiers::DualPublished.build(identifier)
|
|
34
|
+
return dual if dual
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
parser = Parser.new
|
|
33
38
|
builder = Builder.new
|
|
34
39
|
|