pubid 2.0.1 → 2.0.3
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/data/ieee/update_codes.yaml +2 -2
- data/data/parg/adobe.json +1 -1
- data/data/parg/aiee.json +1 -1
- data/data/parg/aiee.parg +99 -9
- data/data/parg/amca.json +1 -1
- data/data/parg/ansi.json +1 -1
- data/data/parg/api.json +1 -1
- data/data/parg/ashrae.json +1 -1
- data/data/parg/asme.json +1 -1
- data/data/parg/astm.json +1 -1
- data/data/parg/bipm.json +1 -1
- data/data/parg/bsi.json +1 -1
- data/data/parg/ccsds.json +1 -1
- data/data/parg/cen_cenelec.json +1 -1
- data/data/parg/cie.json +1 -1
- data/data/parg/csa.json +1 -1
- data/data/parg/ecma.json +1 -1
- data/data/parg/etsi.json +1 -1
- data/data/parg/evs.json +1 -1
- data/data/parg/gost.json +1 -1
- data/data/parg/iala.json +1 -1
- data/data/parg/iana.json +1 -1
- data/data/parg/idf.json +1 -1
- data/data/parg/iec.json +1 -1
- data/data/parg/ieee.json +1 -1
- data/data/parg/iho.json +1 -0
- data/data/parg/ire.json +1 -1
- data/data/parg/ire.parg +51 -12
- data/data/parg/isbn.json +1 -1
- data/data/parg/iso.json +1 -1
- data/data/parg/iso.parg +751 -0
- data/data/parg/itu.json +1 -1
- data/data/parg/jcgm.json +1 -1
- data/data/parg/jis.json +1 -1
- data/data/parg/nesc.json +1 -1
- data/data/parg/nesc.parg +97 -12
- data/data/parg/nist.json +1 -1
- data/data/parg/oiml.json +1 -1
- data/data/parg/omg.json +1 -1
- data/data/parg/parg.json +1 -1
- data/data/parg/plateau.json +1 -1
- data/data/parg/tgpp.json +1 -1
- data/data/parg/un.json +1 -1
- data/lib/pubid/adobe/identifier.rb +1 -1
- data/lib/pubid/adobe/parser.rb +2 -113
- data/lib/pubid/amca/identifiers/base.rb +1 -1
- data/lib/pubid/amca/parser.rb +1 -145
- data/lib/pubid/ansi/identifier.rb +1 -1
- data/lib/pubid/ansi/parser.rb +1 -82
- data/lib/pubid/api/builder.rb +32 -1
- data/lib/pubid/api/identifier.rb +1 -1
- data/lib/pubid/api/parser.rb +1 -131
- data/lib/pubid/ashrae/identifiers/base.rb +1 -1
- data/lib/pubid/ashrae/parser.rb +3 -710
- data/lib/pubid/asme/builder.rb +6 -4
- data/lib/pubid/asme/identifier.rb +1 -2
- data/lib/pubid/asme/parser.rb +1 -328
- data/lib/pubid/astm/builder.rb +12 -3
- data/lib/pubid/astm/identifier.rb +1 -2
- data/lib/pubid/astm/parser.rb +1 -227
- data/lib/pubid/bipm/identifier.rb +8 -1
- data/lib/pubid/bipm/parser.rb +2 -224
- data/lib/pubid/bsi/builder.rb +2 -4
- data/lib/pubid/bsi/parser.rb +1 -666
- data/lib/pubid/bsi/single_identifier.rb +38 -1
- data/lib/pubid/calconnect/parser.rb +2 -40
- data/lib/pubid/ccsds/identifier.rb +1 -1
- data/lib/pubid/ccsds/parser.rb +1 -66
- data/lib/pubid/cen_cenelec/identifier.rb +16 -1
- data/lib/pubid/cen_cenelec/parser.rb +3 -136
- data/lib/pubid/cie/identifier.rb +1 -1
- data/lib/pubid/cie/parser.rb +3 -378
- data/lib/pubid/conformance.rb +1 -1
- data/lib/pubid/csa/builder.rb +41 -18
- data/lib/pubid/csa/identifier.rb +12 -4
- data/lib/pubid/csa/identifiers/amendment.rb +28 -0
- data/lib/pubid/csa/identifiers.rb +1 -0
- data/lib/pubid/csa/parser.rb +16 -397
- data/lib/pubid/doi/parser.rb +2 -37
- data/lib/pubid/easc/builder.rb +1 -1
- data/lib/pubid/easc/parser.rb +2 -70
- data/lib/pubid/ecma/CLAUDE.md +8 -1
- data/lib/pubid/ecma/identifier.rb +13 -8
- data/lib/pubid/ecma/parser.rb +2 -54
- data/lib/pubid/ecma/renderer.rb +3 -7
- data/lib/pubid/errors.rb +18 -13
- data/lib/pubid/etsi/builder.rb +8 -5
- data/lib/pubid/etsi/identifiers/base.rb +1 -1
- data/lib/pubid/etsi/parser.rb +1 -132
- data/lib/pubid/evs/identifier.rb +7 -0
- data/lib/pubid/evs/parser.rb +1 -8
- data/lib/pubid/evs.rb +1 -1
- data/lib/pubid/gb/identifier.rb +6 -0
- data/lib/pubid/gb/parser.rb +2 -51
- data/lib/pubid/gost/identifier.rb +9 -1
- data/lib/pubid/gost/parser.rb +4 -81
- data/lib/pubid/iala/builder.rb +48 -39
- data/lib/pubid/iala/identifier.rb +1 -1
- data/lib/pubid/iala/parser.rb +2 -121
- data/lib/pubid/iana/identifier.rb +1 -1
- data/lib/pubid/iana/parser.rb +2 -24
- data/lib/pubid/identifier.rb +78 -1
- data/lib/pubid/idf/builder.rb +42 -0
- data/lib/pubid/idf/identifier.rb +1 -1
- data/lib/pubid/idf/parser.rb +1 -137
- data/lib/pubid/idf.rb +1 -2
- data/lib/pubid/iec/builder.rb +158 -50
- data/lib/pubid/iec/identifier.rb +1 -1
- data/lib/pubid/iec/parser.rb +3 -430
- data/lib/pubid/ieee/CLAUDE.md +2 -0
- data/lib/pubid/ieee/aiee/identifier.rb +2 -1
- data/lib/pubid/ieee/aiee.rb +0 -1
- data/lib/pubid/ieee/builder.rb +177 -30
- data/lib/pubid/ieee/components/code.rb +46 -7
- data/lib/pubid/ieee/identifiers/base.rb +5 -2
- data/lib/pubid/ieee/identifiers/joint_development.rb +7 -3
- data/lib/pubid/ieee/ire/identifier.rb +2 -1
- data/lib/pubid/ieee/ire.rb +0 -1
- data/lib/pubid/ieee/nesc/builder.rb +1 -1
- data/lib/pubid/ieee/nesc.rb +0 -1
- data/lib/pubid/ieee/parser.rb +1 -1257
- data/lib/pubid/ieee/project_renderer.rb +5 -1
- data/lib/pubid/ieee/renderer.rb +4 -2
- data/lib/pubid/ieee/urn_generator.rb +4 -1
- data/lib/pubid/ietf/identifiers/base.rb +17 -1
- data/lib/pubid/ietf/parser.rb +2 -47
- data/lib/pubid/ietf/renderer.rb +17 -2
- data/lib/pubid/iho/CLAUDE.md +98 -0
- data/lib/pubid/iho/builder.rb +4 -1
- data/lib/pubid/iho/identifiers/base.rb +28 -2
- data/lib/pubid/iho/renderer.rb +8 -0
- data/lib/pubid/iho/urn_generator.rb +14 -1
- data/lib/pubid/iho/urn_parser.rb +45 -32
- data/lib/pubid/iho.rb +0 -1
- data/lib/pubid/isbn/identifier.rb +1 -1
- data/lib/pubid/isbn/parser.rb +2 -31
- data/lib/pubid/iso/CLAUDE.md +66 -0
- data/lib/pubid/iso/builder.rb +229 -15
- data/lib/pubid/iso/identifier.rb +22 -12
- data/lib/pubid/iso/identifiers/directives.rb +6 -3
- data/lib/pubid/iso/identifiers/guide.rb +6 -3
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
- data/lib/pubid/iso/normalizer.rb +5 -4
- data/lib/pubid/iso/parser.rb +1 -539
- data/lib/pubid/iso/supplement_identifier.rb +6 -3
- data/lib/pubid/iso/urn_parser.rb +13 -8
- data/lib/pubid/iso/utilities.rb +4 -5
- data/lib/pubid/iso.rb +1 -19
- data/lib/pubid/itu/builder.rb +36 -20
- data/lib/pubid/itu/identifiers/base.rb +15 -2
- data/lib/pubid/itu/parser.rb +1 -775
- data/lib/pubid/jcgm/builder.rb +35 -0
- data/lib/pubid/jcgm/parser.rb +1 -151
- data/lib/pubid/jcgm.rb +1 -2
- data/lib/pubid/jis/CLAUDE.md +36 -0
- data/lib/pubid/jis/builder.rb +30 -41
- data/lib/pubid/jis/identifier.rb +12 -2
- data/lib/pubid/jis/identifiers/welding_engineering_standard.rb +35 -0
- data/lib/pubid/jis/identifiers.rb +2 -0
- data/lib/pubid/jis/parser.rb +1 -128
- data/lib/pubid/jis/renderer.rb +1 -1
- data/lib/pubid/jis/supplement_identifier.rb +5 -5
- data/lib/pubid/jis/urn_parser.rb +2 -1
- data/lib/pubid/jis.rb +3 -2
- data/lib/pubid/nist/builder.rb +5 -1
- data/lib/pubid/nist/caster.rb +13 -3
- data/lib/pubid/nist/identifiers/base.rb +37 -2
- data/lib/pubid/nist/identifiers/circular.rb +2 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
- data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
- data/lib/pubid/nist/identifiers/handbook.rb +2 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
- data/lib/pubid/nist/identifiers/monograph.rb +2 -2
- data/lib/pubid/nist/identifiers/report.rb +2 -2
- data/lib/pubid/nist/parser.rb +19 -775
- data/lib/pubid/nist/router.rb +4 -1
- data/lib/pubid/nist/supplement_identifier.rb +2 -2
- data/lib/pubid/oasis/parser.rb +2 -16
- data/lib/pubid/ogc/parser.rb +2 -26
- data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
- data/lib/pubid/oiml/parser.rb +1 -303
- data/lib/pubid/oiml.rb +1 -2
- data/lib/pubid/omg/identifier.rb +6 -1
- data/lib/pubid/omg/parser.rb +2 -76
- data/lib/pubid/parser.rb +5 -4
- data/lib/pubid/parsers/mr_string.rb +1 -1
- data/lib/pubid/plateau/parser.rb +1 -66
- data/lib/pubid/plateau.rb +1 -2
- data/lib/pubid/renderers/directives_renderer.rb +1 -1
- data/lib/pubid/renderers/iwa_renderer.rb +1 -1
- data/lib/pubid/renderers/publisher_stripper.rb +82 -0
- data/lib/pubid/renderers/supplement_renderer.rb +1 -1
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/sae/parser.rb +1 -48
- data/lib/pubid/tgpp/identifier.rb +1 -1
- data/lib/pubid/tgpp/parser.rb +2 -59
- data/lib/pubid/un/identifier.rb +1 -1
- data/lib/pubid/un/parser.rb +1 -18
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/parser.rb +2 -27
- data/lib/pubid/xsf/identifier.rb +10 -6
- data/lib/pubid/xsf/parser.rb +3 -31
- data/lib/pubid/xsf/renderer.rb +2 -4
- data/lib/pubid.rb +8 -9
- metadata +9 -23
- data/lib/pubid/ieee/aiee/parser.rb +0 -130
- data/lib/pubid/ieee/ire/parser.rb +0 -109
- data/lib/pubid/ieee/nesc/parser.rb +0 -155
- data/lib/pubid/iho/parser.rb +0 -68
- data/lib/pubid/parser/common_parse_methods.rb +0 -13
- data/lib/pubid/parser/common_parse_rules.rb +0 -56
- data/lib/pubid/parser/grammar.rb +0 -96
data/lib/pubid/iec/parser.rb
CHANGED
|
@@ -1,437 +1,14 @@
|
|
|
1
|
-
require "parslet"
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
module Pubid
|
|
5
4
|
module Iec
|
|
6
|
-
class Parser
|
|
7
|
-
include ::Pubid::Parser::CommonParseRules
|
|
8
|
-
include ::Pubid::Parser::CommonParseMethods
|
|
9
|
-
|
|
5
|
+
class Parser
|
|
10
6
|
DASH_CHARS = ["-", "‑", "‐"].freeze
|
|
11
7
|
|
|
12
|
-
# We need to sort by length to match longest first because that's how Parslet works
|
|
13
|
-
TYPED_STAGES = Pubid::Iec.all_typed_stages
|
|
14
|
-
.map(&:abbr).flatten.sort_by(&:length).reverse
|
|
15
|
-
TYPED_STAGES_SUPPLEMENTS = TYPED_STAGES
|
|
16
|
-
|
|
17
|
-
root :identifier
|
|
18
|
-
|
|
19
|
-
rule(:identifier) do
|
|
20
|
-
working_programme |
|
|
21
|
-
technical_group |
|
|
22
|
-
working_document |
|
|
23
|
-
sheet_supplement_identifier |
|
|
24
|
-
sheet_identifier |
|
|
25
|
-
supplement_supplement_identifier |
|
|
26
|
-
standalone_supplement |
|
|
27
|
-
supplement_identifier |
|
|
28
|
-
joint_identifier |
|
|
29
|
-
identifier_copublishers
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Technical Group identifier — names a committee rather than a document.
|
|
33
|
-
# Examples: "IEC TC 1", "ISO/IEC JTC 1", "ISO/IEC JTC 1/SC 7",
|
|
34
|
-
# "IEC SC 100A", "CISPR", "CIS/A".
|
|
35
|
-
rule(:technical_group) do
|
|
36
|
-
technical_group_with_publisher | technical_group_bare
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
rule(:technical_group_with_publisher) do
|
|
40
|
-
prefix_sole_publisher >> copublishers.maybe >> space >>
|
|
41
|
-
tc_body.as(:technical_committee) >>
|
|
42
|
-
(str("/") >> space? >> sc_body).as(:subcommittee).maybe
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
rule(:technical_group_bare) do
|
|
46
|
-
# CISPR / CIS-letter forms and bare TYPE NUMBER forms both default
|
|
47
|
-
# publisher to "IEC" via the Base class default.
|
|
48
|
-
tc_body.as(:technical_committee) >>
|
|
49
|
-
(str("/") >> space? >> sc_body).as(:subcommittee).maybe
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Committee body forms accepted by the parser. Order matters: longer
|
|
53
|
-
# or more specific patterns first so they win the ordered choice.
|
|
54
|
-
rule(:tc_body) do
|
|
55
|
-
str("CISPR") |
|
|
56
|
-
(str("CIS") >> str("/") >> match("[A-Z]")) |
|
|
57
|
-
(tc_type >> space >> digits >> match("[A-Z]").maybe)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
rule(:sc_body) do
|
|
61
|
-
str("SC") >> space >> digits >> match("[A-Z]").maybe
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
rule(:tc_type) do
|
|
65
|
-
str("JTC") | str("JPC") | str("TC") | str("SC") | str("PC")
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Working Programme format: [PWI|PNW] [TR] number edition
|
|
69
|
-
# Examples: "PWI TR 100-36 ED1", "PWI 100-44 ED1", "PNW 65-915 ED1"
|
|
70
|
-
# TC-style names: "PWI TR SYCSMARTENERGY-1", "PWI SyCLVDC-1 ED1"
|
|
71
|
-
rule(:working_programme) do
|
|
72
|
-
(str("PWI") | str("PNW")).as(:wp_stage) >>
|
|
73
|
-
space >>
|
|
74
|
-
(
|
|
75
|
-
(str("TR") >> space) |
|
|
76
|
-
(str("TS") >> space) |
|
|
77
|
-
(str("SRD") >> space)
|
|
78
|
-
).maybe.as(:wp_type) >>
|
|
79
|
-
wp_number >>
|
|
80
|
-
(space >> edition).maybe
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Working programme numbers can be digits or TC names
|
|
84
|
-
rule(:wp_number) do
|
|
85
|
-
# TC-style: SYCSMARTENERGY-1, SyCLVDC-125
|
|
86
|
-
(match("[A-Za-z]").repeat(1) >> match('[A-Za-z\d]').repeat >> (dash >> match('\d').repeat(1)).maybe).as(:number_with_part) |
|
|
87
|
-
# Regular numeric: 100-36
|
|
88
|
-
number_with_part
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Working Document format: TC/number/stage
|
|
92
|
-
# TC can be: slashes (CIS/D), hyphens (JTC1-SC41), simple (100, 86B, ACEA, SyCSmartEnergy)
|
|
93
|
-
# Examples: "CIS/D/468A/CC", "JTC1-SC41/251/FDIS", "100/3705(F)/FDIS", "86B/4347A/CC"
|
|
94
|
-
rule(:working_document) do
|
|
95
|
-
# TC patterns: digits (100), letters (ACEA), letters/letters (CIS/D), or complex (JTC1-SC41)
|
|
96
|
-
(
|
|
97
|
-
# Try specific patterns first
|
|
98
|
-
(str("JTC1-SC") >> match('\d').repeat(1)) | # JTC1-SC41
|
|
99
|
-
(match("[A-Z]").repeat(1) >> str("/") >> match("[A-Z]").repeat(1)) | # CIS/D
|
|
100
|
-
match('[A-Za-z\d]').repeat(1) # Simple: 100, 86B, ACEA, SyCSmartEnergy
|
|
101
|
-
).as(:technical_committee) >>
|
|
102
|
-
str("/") >>
|
|
103
|
-
match('[A-Za-z\d]').repeat(1).as(:wd_number) >>
|
|
104
|
-
(str("(") >> match("[A-Z]").as(:wd_language) >> str(")")).maybe >>
|
|
105
|
-
(str("/") >> match("[A-Z]").repeat(1).as(:wd_stage)).maybe
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# IEC 60038:2009
|
|
109
|
-
# ISO/IEC 17025:2017
|
|
110
|
-
# CISPR 11:2015 (special IEC publisher)
|
|
111
|
-
# IECQ 080000:2017 (special IEC publisher)
|
|
112
|
-
# IECEE (IEC System for Conformity Assessment)
|
|
113
|
-
# IECEx (IEC System for Certification to Standards)
|
|
114
|
-
# IEC CA (IEC Conformity Assessment)
|
|
115
|
-
# IECQ CS (IECQ Component Specifications)
|
|
116
|
-
# IECQ OD (IECQ Operational Documents)
|
|
117
|
-
rule(:prefix_sole_publisher) do
|
|
118
|
-
(
|
|
119
|
-
str("IECQ OD") |
|
|
120
|
-
str("IECQ CS") |
|
|
121
|
-
str("IEC CAB") |
|
|
122
|
-
str("IEC CA") |
|
|
123
|
-
str("IECRE") |
|
|
124
|
-
str("CISPR") |
|
|
125
|
-
str("IECEE") |
|
|
126
|
-
str("IECEx") |
|
|
127
|
-
str("IECQ") |
|
|
128
|
-
str("IEC") |
|
|
129
|
-
str("ISO")
|
|
130
|
-
).as(:publisher)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# ISO/IEC or IEC
|
|
134
|
-
rule(:prefix_with_copublishers) do
|
|
135
|
-
prefix_sole_publisher >> space? >> copublishers.maybe
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
ORGANIZATIONS = %w[
|
|
139
|
-
IEC ISO IEEE CIW SAE CIE ASME ASTM OECD HL7 CEI UNDP
|
|
140
|
-
].freeze
|
|
141
|
-
rule(:copublishers) do
|
|
142
|
-
(str("/") >> space? >> array_to_str(ORGANIZATIONS).as(:copublisher)).repeat.as(:copublishers)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
rule(:number_with_part) do
|
|
146
|
-
(number >> part_and_subpart.maybe).as(:number_with_part)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# For TRF with organization prefix: "CISPR 14-1G" where CISPR is part of the number
|
|
150
|
-
rule(:trf_org_number) do
|
|
151
|
-
(str("CISPR") >> space).as(:trf_org) >> number_with_part
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
rule(:number) do
|
|
155
|
-
# ISO/IEC Directives: "DIR", "DIR 1", "DIR 1 IEC SUP", "DIR 2 IEC", "DIR IEC SUP"
|
|
156
|
-
# Captured as a flat number (no part/subpart) so it round-trips to the input
|
|
157
|
-
# and class-matches the IEC index. Must come before the IECEE [A-Z]{2,4} branch,
|
|
158
|
-
# which would otherwise match "DIR" alone and leave the trailing tokens unconsumed.
|
|
159
|
-
(str("DIR") >> (space >> match('[A-Z\d]').repeat(1)).repeat) |
|
|
160
|
-
# Special case for VIM publication
|
|
161
|
-
str("VIM") |
|
|
162
|
-
# Special case for SYMBOL publication
|
|
163
|
-
str("SYMBOL") |
|
|
164
|
-
# IECEx TRF version notation: 62784v1a_ds, 62784v1A
|
|
165
|
-
(match('\d').repeat(1,
|
|
166
|
-
6) >> str("v") >> match('\d').repeat(1) >> match("[a-zA-Z]").repeat >> (str("_") >> match("[a-zA-Z]").repeat).maybe) |
|
|
167
|
-
# IECEE letter-based numbers: AD-001, GD-2053, OD-1000, CAB-G01, 01-S
|
|
168
|
-
# Pattern: 2-4 letter prefix followed by optional dash and number
|
|
169
|
-
# The suffix uses [A-Z\d] but not space to properly separate from edition
|
|
170
|
-
(match("[A-Z]").repeat(2, 4) >> (
|
|
171
|
-
dash >> match('\d').repeat(1)
|
|
172
|
-
).maybe >> match('[A-Z\d]').repeat) |
|
|
173
|
-
# Can be 5-6 digits for TRF: 60065, 610091
|
|
174
|
-
# Can have letter suffix: 60065N, 610091A
|
|
175
|
-
# Can have letter + underscore + letters: 61215F_SE
|
|
176
|
-
(match('\d').repeat(1, 6) >> (
|
|
177
|
-
match("[a-zA-Z]") >> (str("_") >> match("[a-zA-Z]").repeat).maybe
|
|
178
|
-
).maybe)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
rule(:date) do
|
|
182
|
-
# :2005-02 or :-- (undated reference — ISO/IEC undated-reference form,
|
|
183
|
-
# e.g. IEC 60050:--, also accepted as the em-dash variant IEC 60050:—)
|
|
184
|
-
(str(":") | dash) >>
|
|
185
|
-
(
|
|
186
|
-
(str("--") | str("—")).as(:undated_marker) |
|
|
187
|
-
(year_digits >>
|
|
188
|
-
(dash >> month_digits).maybe >>
|
|
189
|
-
(dash >> day_digits).maybe
|
|
190
|
-
).as(:date)
|
|
191
|
-
)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
rule(:part_and_subpart) do
|
|
195
|
-
# Parts can have:
|
|
196
|
-
# - Dashes: 60038-1
|
|
197
|
-
# - Complex: 29110-5-1-1
|
|
198
|
-
# - TRF ampersand: 60086-1&2A
|
|
199
|
-
# - TRF underscore: 60127-2-IA_I, 61215F_SE
|
|
200
|
-
# - TRF lowercase: 60127-2-iD_I
|
|
201
|
-
# - TRF commas: 60309-1,2G or 60335-1-14,15G
|
|
202
|
-
|
|
203
|
-
# the "space?" needed to handle potential spaces
|
|
204
|
-
(dash | str(",")) >> space? >>
|
|
205
|
-
# matches a part with special TRF characters including commas
|
|
206
|
-
match('[\w&_,]').repeat >>
|
|
207
|
-
# matches subparts
|
|
208
|
-
((dash | str(",")) >> match('[\w&_,]').repeat).repeat.maybe
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
rule(:all_parts) do
|
|
212
|
-
str("(all parts)").as(:all_parts)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
rule(:type_with_stage) do
|
|
216
|
-
# "DTR"
|
|
217
|
-
# "TS"
|
|
218
|
-
# "Guide"
|
|
219
|
-
# Also includes supplement stages like "CDCor" for standalone draft corrigenda
|
|
220
|
-
array_to_str(TYPED_STAGES + TYPED_STAGES_SUPPLEMENTS).as(:type_with_stage) >>
|
|
221
|
-
(match('\d').as(:stage_iteration) >> space).maybe
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
rule(:language) do
|
|
225
|
-
# IEC 60038:2009(en,fr)
|
|
226
|
-
# IEC 60038:2009(en-fr) (house style, pubid#491)
|
|
227
|
-
# IEC 60038:2009(E/F)
|
|
228
|
-
str("(") >>
|
|
229
|
-
(
|
|
230
|
-
# parse 2-char language codes: ru,en,fr,de,ar,es
|
|
231
|
-
(match["a-z"].repeat(1) >> (str(",") | str("-")).maybe) |
|
|
232
|
-
# parse single language codes: R/E/F
|
|
233
|
-
(match["EFARDS"] >> str("/").maybe)
|
|
234
|
-
).repeat.as(:languages) >>
|
|
235
|
-
str(")")
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
EDITION_STRINGS = %w[Edition Ed. ED Ed].freeze
|
|
239
|
-
rule(:edition) do
|
|
240
|
-
# We ignore the case where there is "Ed" but no number
|
|
241
|
-
# Handle decimal editions like ED1.2
|
|
242
|
-
array_to_str(EDITION_STRINGS) >> space? >>
|
|
243
|
-
(digits >> (str(".") >> digits).maybe).maybe.as(:edition)
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
rule(:stage_iteration) do
|
|
247
|
-
# "IEC 11243.1"
|
|
248
|
-
str(".") >> match('\d').as(:stage_iteration)
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# Sheet notation: /1:1994 (sheet 1 from year 1994)
|
|
252
|
-
# IEC 60695-2-1/1:1994
|
|
253
|
-
rule(:sheet_notation) do
|
|
254
|
-
str("/") >>
|
|
255
|
-
match('\d').repeat(1).as(:sheet_number) >>
|
|
256
|
-
str(":") >>
|
|
257
|
-
year_digits.as(:sheet_year)
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
# Sheet notation without year: /1 (sheet 1 without year)
|
|
261
|
-
# IEC 60695-2-1/1
|
|
262
|
-
rule(:sheet_notation_no_year) do
|
|
263
|
-
str("/") >>
|
|
264
|
-
match('\d').repeat(1).as(:sheet_number)
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
# Fragment notation: /FRAG2 or /FRAGC1 (fragment of amendment/corrigendum)
|
|
268
|
-
# IEC 60050-191/AMD2/FRAG2
|
|
269
|
-
# IEC 60050-191/COR1/FRAGC1
|
|
270
|
-
rule(:fragment_notation) do
|
|
271
|
-
str("/") >>
|
|
272
|
-
(str("FRAGC") | str("FRAG")).as(:fragment_type) >>
|
|
273
|
-
match('\d').repeat(1).as(:fragment_number)
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
# Sheet identifier: base identifier followed by /N:YEAR
|
|
277
|
-
# IEC 60695-2-1/1:1994 (sheet 1 from year 1994)
|
|
278
|
-
# IEC 60695-2-1/1 (sheet 1 without year)
|
|
279
|
-
rule(:sheet_identifier) do
|
|
280
|
-
identifier_copublishers_no_third.as(:base) >>
|
|
281
|
-
(sheet_notation | sheet_notation_no_year)
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
# Sheet identifier followed by supplement: base/sheet/supplement
|
|
285
|
-
# IEC 60695-2-1/1:1994/COR1:1995
|
|
286
|
-
rule(:sheet_supplement_identifier) do
|
|
287
|
-
identifier_copublishers_no_third.as(:base) >>
|
|
288
|
-
sheet_notation >>
|
|
289
|
-
str("/") >> supplement_type_with_stage >>
|
|
290
|
-
space? >> second_part >> third_part
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
# VAP suffix for consolidated/version types
|
|
294
|
-
# CSV = Consolidated version (with Supplements)
|
|
295
|
-
# CMV = Commented Version
|
|
296
|
-
# RLV = Redline Version (shows changes)
|
|
297
|
-
# SER = Serial version
|
|
298
|
-
# EXV = Example version
|
|
299
|
-
# PAC = Package
|
|
300
|
-
# PRV = Preview version
|
|
301
|
-
# Internal helper (no `.as`): a single VAP code. The capture key stays
|
|
302
|
-
# :vap_suffix below; this rule just lets the suffix be one or more codes.
|
|
303
|
-
rule(:vap_code) do
|
|
304
|
-
str("CSV") |
|
|
305
|
-
str("CMV") |
|
|
306
|
-
str("RLV") |
|
|
307
|
-
str("SER") |
|
|
308
|
-
str("EXV") |
|
|
309
|
-
str("PAC") |
|
|
310
|
-
str("PRV")
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
# One or more VAP codes joined by "-", captured whole, e.g. "CSV" or
|
|
314
|
-
# "EXV-CMV"; the builder splits it into the VapIdentifier `vap` array.
|
|
315
|
-
rule(:vap_suffix) do
|
|
316
|
-
space >> (vap_code >> (str("-") >> vap_code).repeat).as(:vap_suffix)
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# Database suffix: " DB"
|
|
320
|
-
# IEC 60617:2012 DB
|
|
321
|
-
rule(:database_suffix) do
|
|
322
|
-
space >> str("DB").as(:database)
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
# Consolidated amendments: +AMD1:2016+AMD2:2019
|
|
326
|
-
# Also supports without dates: +AMD1+AMD2
|
|
327
|
-
# Creates ConsolidatedIdentifier with array of amendments
|
|
328
|
-
rule(:consolidated_supplement) do
|
|
329
|
-
str("+") >>
|
|
330
|
-
(str("AMD") | str("COR")).as(:supplement_type) >>
|
|
331
|
-
match('\d').repeat(1).as(:supplement_number) >>
|
|
332
|
-
(str(":") >> year_digits.as(:supplement_year)).maybe
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
rule(:consolidated_supplements) do
|
|
336
|
-
consolidated_supplement.repeat(1).as(:consolidated_supplements)
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
rule(:second_part) do
|
|
340
|
-
# Try TRF organization number first, fallback to regular number
|
|
341
|
-
(trf_org_number | number_with_part) >>
|
|
342
|
-
stage_iteration.maybe >>
|
|
343
|
-
(space? >> date).maybe >>
|
|
344
|
-
consolidated_supplements.maybe >>
|
|
345
|
-
(vap_suffix | database_suffix).maybe
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
rule(:third_part_edition) do
|
|
349
|
-
space? >> edition.maybe
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
rule(:third_part) do
|
|
353
|
-
# End of the identifier, we can have language, edition, fragment, or all parts
|
|
354
|
-
third_part_edition >> language.maybe >> fragment_notation.maybe >> all_parts.maybe
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
# prefix sole or copublishers with type and stage
|
|
358
|
-
# IEC/TR 60038
|
|
359
|
-
# ISO/IEC TS 20594-1
|
|
360
|
-
# IEC/FDIS 60038
|
|
361
|
-
rule(:identifier_copublishers) do
|
|
362
|
-
identifier_copublishers_no_third >> third_part
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
rule(:guide_prefix) do
|
|
366
|
-
str("Guide") | str("GUIDE")
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
rule(:identifier_copublishers_no_third) do
|
|
370
|
-
# Guide IEC 51:1999
|
|
371
|
-
(guide_prefix.as(:type_with_stage_fr) >> space).maybe >>
|
|
372
|
-
prefix_with_copublishers.maybe >> space? >> str("/").maybe >>
|
|
373
|
-
type_with_stage.maybe >>
|
|
374
|
-
space.maybe >>
|
|
375
|
-
second_part >> third_part_edition
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
# For joint identifiers (ISO/IEC)
|
|
379
|
-
# ISO/IEC 17025:2017 handles copublisher in copublishers rule
|
|
380
|
-
# We handle this in identifier_copublishers already
|
|
381
|
-
rule(:joint_identifier) do
|
|
382
|
-
identifier_copublishers_no_third.as(:base) >>
|
|
383
|
-
space? >> str("|") >> space? >>
|
|
384
|
-
scope { iso_identifier }.as(:joint_identifier)
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
rule(:iso_identifier) do
|
|
388
|
-
Pubid::Iso.joint_grammar_atom(:identifier)
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
rule(:supplement_type_with_stage) do
|
|
392
|
-
# "DAM"
|
|
393
|
-
# "Amd"
|
|
394
|
-
# "FRAG" (fragments of amendments)
|
|
395
|
-
# "FRAGC" (fragments of corrigenda)
|
|
396
|
-
(array_to_str(TYPED_STAGES_SUPPLEMENTS) | str("FRAGC") | str("FRAG")).as(:type_with_stage)
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
# Standalone draft supplement (no base identifier)
|
|
400
|
-
# IEC/FDAM 60038-1
|
|
401
|
-
# IEC/FDCOR 12345
|
|
402
|
-
rule(:standalone_supplement) do
|
|
403
|
-
prefix_with_copublishers >> str("/") >>
|
|
404
|
-
supplement_type_with_stage >>
|
|
405
|
-
space >> second_part >> third_part
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
# IEC 60038:2009/Amd 1:2011
|
|
409
|
-
rule(:supplement_identifier_no_third) do
|
|
410
|
-
identifier_copublishers_no_third.as(:base) >>
|
|
411
|
-
str("/") >> supplement_type_with_stage >>
|
|
412
|
-
space? >> second_part
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
rule(:supplement_identifier) do
|
|
416
|
-
supplement_identifier_no_third >> third_part
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
# IEC 60038:2009/Amd 1:2011/Cor 1:2012
|
|
420
|
-
rule(:supplement_supplement_identifier) do
|
|
421
|
-
supplement_identifier_no_third.as(:base) >>
|
|
422
|
-
str("/") >> supplement_type_with_stage >>
|
|
423
|
-
space? >> second_part >> third_part
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
rule(:dash) do
|
|
427
|
-
DASH_CHARS.map { |char| str(char) }.reduce(:|)
|
|
428
|
-
end
|
|
429
|
-
|
|
430
8
|
IEV_SHORTHAND = /\AIEV(?=\z|[\s-])/
|
|
431
9
|
|
|
432
|
-
# Pre-parse ingestion normalizations (R2): every parse path
|
|
433
|
-
#
|
|
434
|
-
# normalized string.
|
|
10
|
+
# Pre-parse ingestion normalizations (R2): every parse path feeds
|
|
11
|
+
# the grammar the same normalized string.
|
|
435
12
|
def self.normalize_input(input)
|
|
436
13
|
# Normalize tab-separated editions: "IECEE AD-001\tED1.6" -> "IECEE AD-001 ED1.6"
|
|
437
14
|
normalized = input.gsub("\t", " ")
|
|
@@ -440,10 +17,6 @@ module Pubid
|
|
|
440
17
|
# Expand IEV shorthand: "IEV" / "IEV-351" -> "IEC 60050" / "IEC 60050-351"
|
|
441
18
|
normalized.sub(IEV_SHORTHAND, "IEC 60050")
|
|
442
19
|
end
|
|
443
|
-
|
|
444
|
-
def parse(input)
|
|
445
|
-
super(self.class.normalize_input(input))
|
|
446
|
-
end
|
|
447
20
|
end
|
|
448
21
|
end
|
|
449
22
|
end
|
data/lib/pubid/ieee/CLAUDE.md
CHANGED
|
@@ -97,3 +97,5 @@ The lesson BSI paid for: a wrapper's hand-written `#number` delegation makes the
|
|
|
97
97
|
- **The project designator format, and the bare-P parse that dropped it (pubid#18).** IEEE's own draft documents are cited by their short designator — "P1201/D0.3", "P10000/D1.2" — and metanorma-ieee had to post-process the full rendering to produce it. Two edits. **(1) `format: :project`** registers `Pubid::Ieee::ProjectRenderer` in the IEEE format registry: the code (with parts), a PREPENDED "P" when the identifier is a project but the code does not already carry it, and "/D<draft>"; no publisher, no type word, no date. "Project" is detected in all three places a marker can live depending on the building path — `code_obj.prefix` (the bare spelling), the "P" type code, or a `typed_stage` with `project_status` (D1-D6). **(2) The bare-P data loss**: `ieee_p_identifier` consumed its leading "P" with a bare `str("P")`, so "P1201/D0.3" parsed WITHOUT its P anywhere (the number was "1201", prefix nil) — the issue's complaint verbatim. The rule now lets `number` capture the P (the #318 pattern), so `code.prefix` survives and the designator has something to read. The DEFAULT rendering is unchanged — the corpus keeps the P in every unapproved-draft canonical, and #318's idempotence work locked that; the issue's suggestion that the default drop the P predates the corpus and is not adopted. A published (non-project) id renders its bare number under `:project` — the format is a draft-designator view.
|
|
98
98
|
|
|
99
99
|
- **Joint stage-first forms are lead ISO, and the ISO face is lossless (pubid#477)**: a stage word printed in the ISO position (`IEEE FCD 15026.3:2010`, `IEEE/IEC CD2 P62582-2017-05`) parses as printed (#469): `Builder#build_joint_development` sets `lead_party "ISO"` whatever the publisher order, so `canonical_format` is `:iso`. PR #472 had made the lead the first printed publisher and rendered an IEEE-first form in the `D=` face — but the grammar artifact cannot parse most of those renders (`D=FCD`, `D=CD.2`, a non-P number, a month), and `D=CD-2020` parses into a *different* id (`ieee_draft`, no `iso_stage`), so 19 published `relaton-data-ieee` rows stopped matching themselves. The `D=` face now prints only for an id that carries a `D=` designator, or on an explicit `to_s(format: :ieee)`. `JointDevelopment#to_iso_format` prints `iso_stage` as stored (`DIS2`, `CD4` — #472's bare `CD` lost the iteration) and the date in the spelling that parses back (`#iso_date_suffix`: `:2018`, `-2018-05`, `, April 2019`). **The test is `parse(to_s) == id`, not a stable `to_s`**: a lossy render reaches a fixed point and round-trips its *hash* (`iso_stage_spellings_spec` held both while dropping `CD4`→`CD`), yet the reparse is a different identifier. Measured over the 118 joint stage rows of `relaton-data-ieee`: `to_s` stable 100 → 118, `==` 51 → 106; the other 12 carry an `ieee_draft` or an edition that the ISO face still drops. **PARG separator-in-capture, again (#471)**: the draft `revision` capture is `".12"`, and `Draft#to_s` adds its own dot, so `handle_draft` strips the leading dot (`D2022.10.12` rendered `D2022.10..12`). Check every capture a renderer re-joins with a separator. Locked by `spec/pubid/ieee/joint_stage_roundtrip_spec.rb` (stored index hashes → `parse(to_s) == row`).
|
|
100
|
+
|
|
101
|
+
- **IEEE parses through the edition-2 artifact's typed model bindings (the last converter wave)**: the three `Backend.parse` sites (`identifiers/base.rb` `parse_single`, `Aiee::Identifier.parse`, `Ire::Identifier.parse`) route through `Pubid::Parg::Model.bound` — the grammar's `bindings` block produces the builder-ready hash at the engine, replacing the tree normalization. The grammar side (pubid-grammar `grammars/{ieee,nesc}.parg` edition 2 + bindings, plus a class-ref inlining pass over the merged `aiee.parg`/`ire.parg`) keeps every capture the builder reads: leaf scalars bind `(string)`; the branch/wrapper captures the builder dispatches on (`draft`, `parameters`, `publishers`, `base`, `relationship_type`, `related_ids`, the aiee/ire/nesc wrappers, …) bind `(raw)` — raw subtrees carry `Parsanol::Slice` leaves whose `to_s`/`==` behave like strings, so `extract_value` and the `.is_a?(Hash)` probes are unchanged. **Load-bearing grammar deviations** (documented in the `.parg` headers): the zero-width markers are re-spelled as real-token captures (`printed_dash_year`/`printed_month_year` capture their branch's leading separator, `iec_label_dash` the dash, `iso_published` the whole joint head choice — every read sits behind a nil-`iso_stage` gate, so the wider presence set is inert exactly where v1's was narrow); the `([dash]) as draft_dash` / `([rev_sep] as rev_sep)` capture-over-OPTIONAL landmines are `[ (x) as y ]` (parsanol-ruby#394); nested-only captures that collide with a top-level name rename with the builder (`draft_date_month/year/day`, `draft_version_dash_*`, `fdraft_month/year`, and `reaffirmed_year` — unbound, because binding it would have surfaced the reaffirmation year v1 kept absent). **Class RULE refs (`digit`/`lower`/`upper`, and multi-char ones like `alnum_char`/`identifier_string`'s `non_nl`) materialize per-token named nodes inside captures when the runtime recompiles the `use`-importing source — the vendored `data/parg/{aiee,ire,nesc}.parg` copies are the live import sources, so they must be re-vendored together with the artifacts** (a stale `.parg` beside a fresh `.json` silently parses through the old grammar). **Builder accommodations** (all dual-key with the v1 spellings as fallback, so HEAD trees and bound maps read alike): the renamed nested keys; and the multi-segment draft-version normalization at the top of `build_single_identifier` — edition-2 trees materialize a "D2.1.1" designator as per-token nodes with no `:draft_version`, where v1 degraded to a whole-clause leaf (reconstructed: the leaf string → `Draft.parse` inverse) or to a date-only hash when a draft date follows (no draft built). **Measured**: fixture-corpus parity (old artifact + tree backend + builder vs new artifact + bound + builder) over all 9,054 pass-fixture inputs → 1 diff, and standalone aiee/ire/nesc sweeps → 0 diffs each. **The one residue is an engine wall, documented not chased**: `IEC/IEEE PC37.60/P62271-111_D6.1` (testsuite case `ieee.project_draft_identifier.0946`, one corpus input, one `draft_compact_convergence` example) — v1's edition-1 tree degraded its whole draft clause ("DP62271-111_D6.1, Aug 2016", two P-numbers plus date) into a single leaf, and edition-2's fully-named trees cannot reproduce that collapse at any binding spelling (isolated rule probes + programmatic branch bisect); the row is one of the two-P-number joint one-offs already recorded as deferred above. The conversion also **fixed** two testsuite rows (`ieee.project_draft_identifier.9263` "ISO/IEC/IEEE P42010.2019/D4" / "P42010.WD4:2019(E)" — the lettered `draft_iso_iteration` capture now binds, so the D= face composes), at the cost of the 0946 residue above.
|