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
data/lib/pubid/ieee/renderer.rb
CHANGED
|
@@ -115,26 +115,33 @@ module Pubid
|
|
|
115
115
|
parts << id.draft_status if id.draft_status
|
|
116
116
|
|
|
117
117
|
# Type - only render for IEEE/AIEE publishers, and only for non-projects.
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
118
|
+
# A status word ("Unapproved") already marks the document as a draft,
|
|
119
|
+
# so the WHOLE type word is dropped — not just "Std" (pubid#318: the
|
|
120
|
+
# half-strip left "Draft" in the render, the re-parse dropped it, and
|
|
121
|
+
# to_s needed three rounds to converge while losing the type).
|
|
121
122
|
should_render_type = id.publisher&.match?(/^(IEEE|AIEE)/)
|
|
122
123
|
|
|
123
|
-
if should_render_type && !id.typed_stage&.project_status && id.type && !id.type.to_s.strip.empty? && id.type != "P"
|
|
124
|
+
if should_render_type && !id.typed_stage&.project_status && id.type && !id.type.to_s.strip.empty? && id.type != "P" &&
|
|
125
|
+
!id.draft_status.to_s.match?(/unapproved/i)
|
|
124
126
|
type_str = id.type.dup
|
|
125
127
|
type_str = type_str.sub(/^P/, "") if type_str.start_with?("P")
|
|
126
|
-
if id.draft_status.to_s.match?(/unapproved/i)
|
|
127
|
-
type_str = type_str.gsub(/\bStd\b/i, "").squeeze(" ").strip
|
|
128
|
-
end
|
|
129
128
|
parts << type_str unless type_str.strip.empty?
|
|
130
129
|
end
|
|
131
130
|
|
|
132
|
-
# Code - with P prefix for projects (concatenated, not separated)
|
|
131
|
+
# Code - with P prefix for projects (concatenated, not separated).
|
|
132
|
+
# IEEE semantics (normative): P = project = the document is a
|
|
133
|
+
# draft; no P = it has become a standard. The P-state is
|
|
134
|
+
# identity-bearing, so the renderer never adds or drops it —
|
|
135
|
+
# whatever the source spelling carries round-trips.
|
|
133
136
|
if id.code_obj
|
|
134
137
|
result = id.code_obj.to_s
|
|
135
138
|
|
|
136
|
-
# Prepend P if this is a project AND code doesn't already have P
|
|
137
|
-
|
|
139
|
+
# Prepend P if this is a project AND code doesn't already have P.
|
|
140
|
+
# A recorded project marker (the source spelled the P on a
|
|
141
|
+
# non-IEEE-led publisher) prints regardless of the publisher.
|
|
142
|
+
if (id.typed_stage&.project_status && should_render_type ||
|
|
143
|
+
id.is_a?(Identifiers::ProjectDraftIdentifier) &&
|
|
144
|
+
id.project_marker) && !result.start_with?("P")
|
|
138
145
|
result = "P#{result}"
|
|
139
146
|
end
|
|
140
147
|
|
|
@@ -143,6 +150,7 @@ module Pubid
|
|
|
143
150
|
result += mark(id.code_obj.number, id.code_obj.prefix,
|
|
144
151
|
publishers: publishers_of(id))
|
|
145
152
|
|
|
153
|
+
|
|
146
154
|
# Only attach year to code if there's no edition, no month, and no draft
|
|
147
155
|
result += "-#{id.year}" if id.year && !id.draft_obj && !id.edition && !id.month
|
|
148
156
|
|
|
@@ -151,9 +159,29 @@ module Pubid
|
|
|
151
159
|
# ("P802.16Rev2/D3"). Keeps a revision distinct from its base standard.
|
|
152
160
|
result += "Rev#{id.revision}" if id.revision
|
|
153
161
|
|
|
154
|
-
# Append draft to code - with or without space based on original
|
|
162
|
+
# Append draft to code - with or without space based on original
|
|
163
|
+
# format. An exactly-IEC/IEEE co-published reference prints only the
|
|
164
|
+
# draft DESIGNATOR - a comma-separated project date ("IEC/IEEE
|
|
165
|
+
# 61886-1/D2, May 2020" prints as "…/D2") is catalogue metadata, not
|
|
166
|
+
# identity. Wider sets ("IEC/ISO/IEEE P82079-1/D1, June 2016") print
|
|
167
|
+
# the date; a space-separated date always stays ("…/DCDV July 2015").
|
|
168
|
+
# IEEE-published drafts normalize the comma date to the long form
|
|
169
|
+
# ("D08, September, 2018").
|
|
155
170
|
if id.draft_obj
|
|
156
|
-
|
|
171
|
+
printed = id.draft_obj.to_s
|
|
172
|
+
if id.publisher == "IEC" && id.copublisher == ["IEEE"]
|
|
173
|
+
printed = printed.split(", ").first
|
|
174
|
+
elsif id.publisher == "IEEE" && id.draft_status.to_s.empty?
|
|
175
|
+
# The long comma form is for dated project drafts; an
|
|
176
|
+
# unapproved-draft render keeps its pinned single-comma form
|
|
177
|
+
# (pubid#318 idempotence).
|
|
178
|
+
printed = printed.sub(/, ([A-Z][a-z]+) (\d{4})\z/, ', \1, \2')
|
|
179
|
+
end
|
|
180
|
+
# A space-separated draft year with no print date trailing is
|
|
181
|
+
# IEEE's dash form ("…/D1-2006"); with a trailing print date the
|
|
182
|
+
# space stays ("…/D1 2004, Nov 2004").
|
|
183
|
+
printed = printed.sub(/\A(D\d+) (\d{4})\z/, '\1-\2')
|
|
184
|
+
result += id.space_before_draft ? " #{printed}" : printed
|
|
157
185
|
end
|
|
158
186
|
|
|
159
187
|
# Append interpretation notation (/INT)
|
|
@@ -191,8 +219,12 @@ module Pubid
|
|
|
191
219
|
# Build the main identifier (without month yet)
|
|
192
220
|
result = parts.join(" ")
|
|
193
221
|
|
|
194
|
-
|
|
195
|
-
|
|
222
|
+
|
|
223
|
+
# Month/Day - append directly to avoid extra space before comma.
|
|
224
|
+
# An exactly-IEC/IEEE co-published reference drops the comma date
|
|
225
|
+
# entirely (same catalogue-metadata rule as the draft date above):
|
|
226
|
+
# "IEC/IEEE P60076-16, May 2016" prints as "IEC/IEEE 60076-16".
|
|
227
|
+
if id.month && !(id.publisher == "IEC" && id.copublisher == ["IEEE"])
|
|
196
228
|
result += ", #{id.month}"
|
|
197
229
|
result += " #{id.day}" if id.day
|
|
198
230
|
if id.year && !id.edition
|
|
@@ -127,6 +127,10 @@ module Pubid
|
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
def publisher_component
|
|
130
|
+
# The IEC/IEEE co-published pair is definitional to the class and
|
|
131
|
+
# was previously lost ("urn:ieee:ieee" — no number, no draft).
|
|
132
|
+
return "iec-ieee" if identifier.is_a?(Identifiers::IecIeeeCopublished)
|
|
133
|
+
|
|
130
134
|
pub = normalized_publisher
|
|
131
135
|
|
|
132
136
|
if identifier.copublisher&.any?
|
|
@@ -150,6 +154,14 @@ module Pubid
|
|
|
150
154
|
end
|
|
151
155
|
|
|
152
156
|
def type_component
|
|
157
|
+
# A joint stage draft carries the stage in its draft clause and the
|
|
158
|
+
# project P inside the code — a separate type segment would
|
|
159
|
+
# duplicate both.
|
|
160
|
+
if identifier.is_a?(Identifiers::JointDevelopment) &&
|
|
161
|
+
identifier.ieee_draft.to_s.start_with?("D=")
|
|
162
|
+
return nil
|
|
163
|
+
end
|
|
164
|
+
|
|
153
165
|
return nil unless identifier.type
|
|
154
166
|
|
|
155
167
|
type = identifier.type
|
|
@@ -159,6 +171,16 @@ module Pubid
|
|
|
159
171
|
end
|
|
160
172
|
|
|
161
173
|
def code_component
|
|
174
|
+
# The co-published code is number+parts+separators (no year — its
|
|
175
|
+
# own segment), e.g. "61886-1".
|
|
176
|
+
if identifier.is_a?(Identifiers::IecIeeeCopublished)
|
|
177
|
+
return nil if identifier.number.to_s.empty?
|
|
178
|
+
|
|
179
|
+
# Year-less: the publication year is its own URN segment (the
|
|
180
|
+
# rebuilt copublished_number would double-emit it).
|
|
181
|
+
return "#{identifier.number}#{identifier.parts_suffix}"
|
|
182
|
+
end
|
|
183
|
+
|
|
162
184
|
return nil unless identifier.code_obj
|
|
163
185
|
|
|
164
186
|
identifier.code_obj.to_s
|
|
@@ -182,6 +204,15 @@ module Pubid
|
|
|
182
204
|
end
|
|
183
205
|
|
|
184
206
|
def draft_component
|
|
207
|
+
if identifier.is_a?(Identifiers::JointDevelopment) &&
|
|
208
|
+
identifier.ieee_draft.to_s.start_with?("D=")
|
|
209
|
+
return "draft.#{identifier.ieee_draft}"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
if identifier.is_a?(Identifiers::IecIeeeCopublished)
|
|
213
|
+
return identifier.draft_info ? "draft.#{identifier.draft_info}" : nil
|
|
214
|
+
end
|
|
215
|
+
|
|
185
216
|
return nil unless identifier.draft_obj
|
|
186
217
|
|
|
187
218
|
"draft.#{identifier.draft_obj}"
|
data/lib/pubid/ieee.rb
CHANGED
|
@@ -20,6 +20,7 @@ module Pubid
|
|
|
20
20
|
autoload :Parser, "#{__dir__}/ieee/parser"
|
|
21
21
|
autoload :PreParser, "#{__dir__}/ieee/pre_parser"
|
|
22
22
|
autoload :Compaction, "#{__dir__}/ieee/compaction"
|
|
23
|
+
autoload :ProjectRenderer, "#{__dir__}/ieee/project_renderer"
|
|
23
24
|
autoload :Renderer, "#{__dir__}/ieee/renderer"
|
|
24
25
|
autoload :TypedStages, "#{__dir__}/ieee/typed_stages"
|
|
25
26
|
autoload :UrnGenerator, "#{__dir__}/ieee/urn_generator"
|
|
@@ -162,3 +163,4 @@ Pubid::Registry.register(:ieee, Pubid::Ieee)
|
|
|
162
163
|
# Per-flavor format registry: inherits global formats, overrides :human
|
|
163
164
|
Pubid::Ieee::Identifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
|
|
164
165
|
Pubid::Ieee::Identifier.format_registry.register(:human, renderer: Pubid::Ieee::Renderer)
|
|
166
|
+
Pubid::Ieee::Identifier.format_registry.register(:project, renderer: Pubid::Ieee::ProjectRenderer)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# IETF flavor notes
|
|
2
|
+
|
|
3
|
+
IETF readiness for the unified relaton index.
|
|
4
|
+
|
|
5
|
+
These notes were part of the root `CLAUDE.md`. Read them before you change `lib/pubid/ietf/` or `spec/pubid/ietf/`. The root file keeps the cross-flavor contract that every flavor obeys.
|
|
6
|
+
|
|
7
|
+
- **IETF readiness for the unified relaton index (`relaton-data-ietf`)**: relaton is collapsing RFCs, the RFC sub-series (BCP/STD/FYI) and Internet-Drafts into **one** index keyed on the structured pubid hash (`pubid_class: ::Pubid::Ietf::Identifier`). That index is **all-or-nothing** — `Relaton::Index::FileIO#deserialize_id` raises on the *first* unparseable row and `#load_index` then rejects the whole index — so one bad id out of 176,862 means no consumer resolves *any* IETF reference. Four changes, all verified against the published corpora (`relaton-data-{rfcs,rfcsubseries,ids}`, branch `v2`). **(1) `draft_rest` accepts `.` and `A-Z`** (`match['a-zA-Z0-9+_.\-']`): exactly 50 of the 166,740 published draft ids failed without them (21 dotted `draft-ietf-pilc-2.5g3g-12`, 29 uppercase `draft-chapin-clnp-ISO8473-00`, 0 both), and a character census confirms the class now covers the corpus **exactly** — the only chars outside `[a-z0-9-]` anywhere in it are `. _ +` and `A-Z`. Widening is safe because the top-level alternation is keyed on the leading token (`RFC`/`BCP|STD|FYI`/`draft-`), so a wider draft tail can never make another branch match; `Builder#split_draft_version` needed no change (it inspects only the last three characters). The set stays **closed** — a space, `/` or `&` in a slug is crawler junk and still fails (pinned by negative examples). **(2) Zero-padded ids parse, grammar-level**: `rfc-index.xml` writes sub-series membership as `<is-also><doc-id>STD0066</doc-id></is-also>` (369 padded doc-ids) and RFCs as `RFC0001`, and relaton#109 forbids relaton normalizing them itself. The space is `.maybe` on both the `rfc` and `subseries` rules and `Builder#unpad` strips the pad (`/\A0+(?=\d)/`, a look-ahead so an all-zero number keeps its last digit), so `STD0066`/`STD 0066`/`STD66` all render the canonical `STD 66`. `unpad` is applied unconditionally, so the **spaced** padded form is normalized too — `RFC 0001` previously parsed and rendered back verbatim, and now renders `RFC 1` with a correspondingly changed hash and URN. That is deliberate (one canonical spelling per document) and has **zero** effect on the published corpora, which contain no padded row. **This is a normalizing parse, so the padded spellings must NEVER go into the byte-exact `spec/fixtures/ietf/identifiers/pass/`** — they live in `spec/pubid/ietf/zero_padded_spec.rb`, the BIPM `CIPM/2005-06(REV)` precedent. **(3) The Internet-Draft slug moved from `name` into `number`, and `series` became derived**: relaton bsearches on `id.root.number.to_s`, so with the slug in `name` all 166,740 drafts keyed to `""` and the narrowing bought nothing (with the slug: 43,564 buckets, median 2, worst 101). `name` is **dropped entirely** (no alias); the slug — leading `draft-` included — is the key, deliberately shared by a draft's unversioned aggregator row and every one of its versions so a document and its variants cluster. `series` is likewise **not stored**: `_type: pubid:ietf:std` already encodes it, so `Bcp`/`Std`/`Fyi` expose a `SERIES` constant + a plain `#series` reader (safe — `::Pubid::Identifier` declares no `series` attribute and nothing generic reads `.series`) and `build_subseries` stops passing it. The whole serialized vocabulary is now **three keys**: `_type` + `number` always, `version` only on a versioned draft — a sub-series row (`{_type, number}`) has the same shape as an RFC's. **The attributes live on the five LEAVES, not the shared `Pubid::Ietf::Identifier`**, via the `Identifiers::Serialization` mixin (`number` + the `key_value` block; `InternetDraft` merges its own `version` mapping on top — lutaml combines a mixin-installed block with a second in-class one, the ITU precedent). This is the IEEE `number` determinism landmine: a `:string` redefinition of the parent's `Components::Code number` on a class the leaves *inherit* from resolves nondeterministically under multi-flavor load. It was invisible while drafts left `number` nil; it is load-bearing now. The base deliberately carries **no** `key_value` block — one there would be inherited-and-merged by every leaf. `spec/pubid/ietf/root_number_spec.rb` is the tripwire (asserts `number` is a `String`, the exact keys, the exact `to_hash` key sets) and **must run under the full `rake` suite** to mean anything. **(4) Round-trip is validated here because relaton structurally cannot**: `FileIO#id_supported?` **skips** its `to_hash`/`from_hash` check whenever the object is a concrete subclass (`return true unless obj.instance_of?(@pubid_class)`), and *every* IETF id is a subclass — so a lossy round-trip would pass validation silently and produce wrong lookups. Three layers: `fixtures_spec.rb` is now **zero-failure** (was a 90% threshold — wrong for an all-or-nothing index) and checks `to_s` byte-exactness, `from_hash(to_hash)` fidelity in both `to_s` and `to_hash`, **and** a non-empty `root.number` for every fixture line; the fixtures grew to ~2,500 lines (the complete 365-row sub-series corpus, a 139-id structural edge set, a deterministic 1-in-84 draft sample — each file's header records the regeneration command); and `spec/pubid/ietf/corpus_round_trip_spec.rb` runs the same four checks over all 176,862 published ids, **opt-in** via `PUBID_IETF_CORPUS=<dir with the three relaton-data checkouts> bundle exec rake test:corpus_ietf` (self-skips otherwise; ~100s; verified 0 failures). **relaton note — the indexes must be regenerated, there is no alias**: `name` and `series` are gone as serialized keys, so a pre-`number` row (`{_type, name, version}`) deserializes with **`number` nil** and no error at all — lutaml ignores unknown keys, and relaton's subclass skip means `id_supported?` won't catch it either, leaving every draft keyed under `""`. Rendering is therefore the loud failure: `Renderer#require_number!` raises `ArgumentError` on a nil/empty `number` rather than returning `nil` or `"-02"`, and the renderer's sub-series arm is an explicit `when Bcp, Std, Fyi` with an `else raise` instead of a catch-all (a bare `Pubid::Ietf::Identifier` has no `series` reader). Pinned by the "legacy `name`-shaped hash" block in `root_number_spec.rb`. **Pre-existing bug fixed in passing**: `UrnParser`'s bare `Errors::ParseError` does not resolve — `Errors` lives under `Pubid::UrnParser` (the module), which is neither in the lexical scope of `Pubid::Ietf::UrnParser` nor an ancestor of `Base` — so an invalid URN raised `NameError` instead, and the spec's `raise_error(StandardError)` accepted it. Now fully qualified as `Pubid::UrnParser::Errors::ParseError` (the adobe/easc/gost/iala convention) with the spec asserting that exact class. **`Pubid::Iec::UrnParser` has the identical bug and is untouched here.** Also: `Identifier.parse` gained the inline `MAX_INPUT_LENGTH` guard — relaton reaches that class-level funnel directly through `pubid_class:`, bypassing `Pubid::Ietf.parse` — and IETF was added to the three cross-flavor tables it was missing from (`identifier_roundtrip_spec`, `uniform_identifier_handle_spec`, `redos_guard_spec`), which is what exercises the leaf `number` under real multi-flavor load. (hand-off: ietf-index-readiness.)
|
data/lib/pubid/ietf/builder.rb
CHANGED
data/lib/pubid/iho/builder.rb
CHANGED
data/lib/pubid/isbn/builder.rb
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ISO flavor notes
|
|
2
|
+
|
|
3
|
+
- **No identifier attribute holds a `Components::Code` any more**: `number`,
|
|
4
|
+
`part` and `subpart` on `Pubid::Iso::Identifier`, the committee structure on
|
|
5
|
+
`Identifiers::TcDocument` (`tc_type`/`tc_number`/`sc_type`/`sc_number`/
|
|
6
|
+
`wg_type`/`wg_number`), `Identifiers::Directives#subgroup` and the
|
|
7
|
+
`edition.number` the builder writes are all plain strings, and
|
|
8
|
+
`Pubid::Iso::Components::Code` is deleted.
|
|
9
|
+
**The component was degenerate everywhere it was used.** Measured over the
|
|
10
|
+
whole 7,613-id pass corpus: no ISO Code carries `prefix`, `part`, `subpart`
|
|
11
|
+
or `parts`, `parts` is never written anywhere in `lib/pubid/iso`, and no Code
|
|
12
|
+
renders differently from its own `value`. ISO's part and subpart are sibling
|
|
13
|
+
attributes of the identifier, not fields of the number — the `-` join in
|
|
14
|
+
`Code#to_s` was unreachable.
|
|
15
|
+
**`edition.number` was worse than degenerate: it leaked a live object.**
|
|
16
|
+
`Components::Edition#number` is typed `Lutaml::Model::Type::Value`, so lutaml
|
|
17
|
+
never serialized it — `to_hash` returned the `Components::Code` instance
|
|
18
|
+
itself, and `to_yaml` emitted `!ruby/object:Pubid::Components::Code` with its
|
|
19
|
+
internal ivars, which `YAML.safe_load` refuses. An edition now serializes
|
|
20
|
+
`{"number" => "13", "original_text" => "Ed 13"}`.
|
|
21
|
+
**The TC converters are gone with it**: twelve `*_to_kv`/`*_from_kv` helpers
|
|
22
|
+
were replaced by plain `map "tc_type", to: :tc_type` declarations (the
|
|
23
|
+
ETSI/OIML shape), because a String needs no converter to flatten.
|
|
24
|
+
**Two shared surfaces needed a change, and both are the documented shims**:
|
|
25
|
+
`Renderers::DirectivesRenderer` called `subgroup.render(context:)` directly
|
|
26
|
+
and now reads through `render_component`; `Pubid::Iso.build_code` returned a
|
|
27
|
+
Code and now returns the string (ASTM's `to_iso_identifier` goes through it,
|
|
28
|
+
which is how one ASTM example caught the `NameError` after the class was
|
|
29
|
+
deleted).
|
|
30
|
+
**Verification — replay a baseline, do not trust the suite alone.** Against
|
|
31
|
+
all 7,621 pass-fixture ids captured on the parent commit, `to_s`, `to_urn`,
|
|
32
|
+
`to_mr_string`, `root.number` and the identifier class are **byte-identical**,
|
|
33
|
+
and `to_hash` differs for exactly **12** ids: the 9 `subgroup` rows and the 3
|
|
34
|
+
editions below. The first replay also caught a real regression the specs did
|
|
35
|
+
not — `directives.rb` still called `part.value.downcase`, so 4 Directives
|
|
36
|
+
URNs raised.
|
|
37
|
+
**relaton note — `relaton-data-iso` needs a re-crawl, and only for one key.**
|
|
38
|
+
`subgroup` flattens from `{"value" => "JTC 1"}` to `"JTC 1"`, and the
|
|
39
|
+
published `index-v2.yaml` (branch `v2`) carries **5 such rows**, all ISO/IEC
|
|
40
|
+
JTC 1 directives. **No compatibility shim is kept** — a stored nested
|
|
41
|
+
`subgroup` will not deserialize. The edition change reaches nothing stored:
|
|
42
|
+
`grep -c edition` over that index returns **0**.
|
|
43
|
+
**Spec fallout is the shape to expect for the remaining flavors**: 592
|
|
44
|
+
assertions across 25 files read `.number.value` / `.part.value`. The rewrite
|
|
45
|
+
needs a lookbehind, because `tc_number.value` and `edition.number.value` are
|
|
46
|
+
different attributes — the first pass stripped `edition.number.value` too,
|
|
47
|
+
and two corrigendum examples caught it.
|
data/lib/pubid/iso/builder.rb
CHANGED
|
@@ -58,6 +58,12 @@ module Pubid
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def build(parsed_hash)
|
|
61
|
+
# "(all parts)" and the ":ser" URN name every part of the document,
|
|
62
|
+
# so they build an AllPartsIdentifier around the document (the URN
|
|
63
|
+
# parser puts the key on the outermost identifier for the same
|
|
64
|
+
# reason). The document itself holds no all-parts mark.
|
|
65
|
+
all_parts = parsed_hash.delete(:all_parts)
|
|
66
|
+
|
|
61
67
|
# For ISO/R legacy format, split into publisher and type
|
|
62
68
|
if parsed_hash[:iso_r_prefix]
|
|
63
69
|
parsed_hash[:publisher] = "ISO"
|
|
@@ -77,14 +83,20 @@ module Pubid
|
|
|
77
83
|
end
|
|
78
84
|
end
|
|
79
85
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
#
|
|
86
|
+
# For French GUIDE entries: "Guide ISO/CEI 37:1995". The rename
|
|
87
|
+
# must happen BEFORE class selection — locate_identifier_klass
|
|
88
|
+
# reads :type_with_stage, and the tree of a guide-first spelling
|
|
89
|
+
# carries an empty :type_with_stage plus the type under
|
|
90
|
+
# :type_with_stage_fr, so deferring the rename selected the
|
|
91
|
+
# default International Standard class for every guide-first
|
|
92
|
+
# (and Cyrillic "Руководства ИСО …") reference.
|
|
84
93
|
if type_with_stage_fr = parsed_hash.delete(:type_with_stage_fr)
|
|
85
94
|
parsed_hash[:type_with_stage] = type_with_stage_fr
|
|
86
95
|
end
|
|
87
96
|
|
|
97
|
+
# Instantiate the identifier based on the typed stage
|
|
98
|
+
identifier = locate_identifier_klass(parsed_hash).new
|
|
99
|
+
|
|
88
100
|
# For DirectivesSupplement, rename :publisher to :supplement_publisher
|
|
89
101
|
if identifier.is_a?(Identifiers::DirectivesSupplement) && parsed_hash[:publisher]
|
|
90
102
|
parsed_hash[:supplement_publisher] = parsed_hash.delete(:publisher)
|
|
@@ -112,7 +124,7 @@ module Pubid
|
|
|
112
124
|
identifier.type = default_typed_stage.to_type
|
|
113
125
|
end
|
|
114
126
|
|
|
115
|
-
identifier
|
|
127
|
+
all_parts ? identifier.to_all_parts : identifier
|
|
116
128
|
end
|
|
117
129
|
|
|
118
130
|
def handle_key(identifier, key, value)
|
|
@@ -143,7 +155,7 @@ module Pubid
|
|
|
143
155
|
return nil unless year_value.between?(1900, 2099)
|
|
144
156
|
|
|
145
157
|
{
|
|
146
|
-
number:
|
|
158
|
+
number: number,
|
|
147
159
|
date: ::Pubid::Components::Date.new(year: part),
|
|
148
160
|
}
|
|
149
161
|
end
|
|
@@ -197,7 +209,7 @@ module Pubid
|
|
|
197
209
|
# or "105/F" ('F' is part)
|
|
198
210
|
# or "5843/6" ('6' is part)
|
|
199
211
|
# LEGACY: "4037-1979" (number-year, year should become date)
|
|
200
|
-
parse_number_with_part(value
|
|
212
|
+
parse_number_with_part(value)
|
|
201
213
|
|
|
202
214
|
when :directives_type
|
|
203
215
|
# nothing to do here, just return nil
|
|
@@ -240,8 +252,10 @@ module Pubid
|
|
|
240
252
|
original_text = value.to_s
|
|
241
253
|
# Extract just the digit(s) for the number field
|
|
242
254
|
number_string = original_text.match(/\d+/)&.to_s
|
|
243
|
-
|
|
244
|
-
|
|
255
|
+
# A plain string: Components::Edition#number is typed Value, so a
|
|
256
|
+
# component here would leak a live Ruby object into to_hash (and a
|
|
257
|
+
# !ruby/object tag into to_yaml).
|
|
258
|
+
Pubid::Components::Edition.new(number: number_string,
|
|
245
259
|
original_text: original_text)
|
|
246
260
|
|
|
247
261
|
when :languages
|
|
@@ -260,8 +274,7 @@ module Pubid
|
|
|
260
274
|
|
|
261
275
|
when :subgroup
|
|
262
276
|
# Handle JTC 1 subgroup in directives (ISO/IEC JTC 1 DIR)
|
|
263
|
-
|
|
264
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
277
|
+
value.to_s
|
|
265
278
|
|
|
266
279
|
when :supplements
|
|
267
280
|
# Handle bundled supplements (+ operator)
|
|
@@ -274,12 +287,10 @@ module Pubid
|
|
|
274
287
|
|
|
275
288
|
# TC Document attributes
|
|
276
289
|
when :tc_type, :sc_type, :wg_type
|
|
277
|
-
|
|
278
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
290
|
+
value.to_s
|
|
279
291
|
|
|
280
292
|
when :tc_number, :sc_number, :wg_number
|
|
281
|
-
|
|
282
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
293
|
+
value.to_s
|
|
283
294
|
|
|
284
295
|
when :year
|
|
285
296
|
# For TC documents with year, convert to Date
|
|
@@ -290,7 +301,7 @@ module Pubid
|
|
|
290
301
|
# For regular identifiers, this is handled in :number_with_part
|
|
291
302
|
if value.is_a?(Parslet::Slice) || value.is_a?(String) ||
|
|
292
303
|
value.is_a?(Integer)
|
|
293
|
-
|
|
304
|
+
value.to_s
|
|
294
305
|
else
|
|
295
306
|
value
|
|
296
307
|
end
|
|
@@ -314,3 +325,5 @@ module Pubid
|
|
|
314
325
|
end
|
|
315
326
|
end
|
|
316
327
|
end
|
|
328
|
+
|
|
329
|
+
Pubid::Iso::Builder.prepend(Pubid::Builder::AllPartsWrap)
|
|
@@ -8,6 +8,8 @@ module Pubid
|
|
|
8
8
|
# ISO Publisher with copublisher support
|
|
9
9
|
# Examples: ISO, ISO/IEC, ISO/IEC/IEEE
|
|
10
10
|
class Publisher < Lutaml::Model::Serializable
|
|
11
|
+
include ::Pubid::SubsetMatch
|
|
12
|
+
|
|
11
13
|
attribute :publisher, :string, default: -> { "ISO" }
|
|
12
14
|
attribute :copublisher, :string, collection: true
|
|
13
15
|
|
data/lib/pubid/iso/components.rb
CHANGED
data/lib/pubid/iso/identifier.rb
CHANGED
|
@@ -11,6 +11,12 @@ module Pubid
|
|
|
11
11
|
attribute :copublishers, ::Pubid::Iso::Components::Publisher,
|
|
12
12
|
collection: true
|
|
13
13
|
|
|
14
|
+
# ISO prints "(all parts)" and has a series URN, so it has its own
|
|
15
|
+
# all-parts class.
|
|
16
|
+
def self.all_parts_class
|
|
17
|
+
Identifiers::AllParts
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
# The publisher implied when none is serialized. ISO for most types;
|
|
15
21
|
# publisher-less types (IWA) override this to nil.
|
|
16
22
|
def self.default_publisher
|
|
@@ -56,9 +62,14 @@ module Pubid
|
|
|
56
62
|
ts ? dup.tap { |id| id.typed_stage = ts } : dup
|
|
57
63
|
end
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
# Plain strings. Iso::Components::Code existed to join `parts` with
|
|
66
|
+
# "-", a composition no ISO identifier ever reached: `parts` is never
|
|
67
|
+
# written in lib/pubid/iso and no Code in the 7,613-id corpus carries
|
|
68
|
+
# anything but `value`. ISO part and subpart are sibling attributes, not
|
|
69
|
+
# fields of the number.
|
|
70
|
+
attribute :number, :string
|
|
71
|
+
attribute :part, :string
|
|
72
|
+
attribute :subpart, :string
|
|
62
73
|
|
|
63
74
|
# Polymorphic type map for lutaml::Model key_value serialization
|
|
64
75
|
# Maps polymorphic_name → class name for deserialization
|
|
@@ -132,20 +143,6 @@ module Pubid
|
|
|
132
143
|
# unique typed-stage `code` under "stage" and recompute the rest on
|
|
133
144
|
# load. _type already pins the document type.
|
|
134
145
|
map "stage", with: { to: :stage_to_kv, from: :stage_from_kv }
|
|
135
|
-
# Omit the `false` default; only the meaningful `true` is serialized.
|
|
136
|
-
map "all_parts", with: { to: :all_parts_to_kv, from: :all_parts_from_kv }
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def all_parts_to_kv(model, doc)
|
|
140
|
-
return unless model.all_parts
|
|
141
|
-
|
|
142
|
-
doc.add_child(
|
|
143
|
-
Lutaml::KeyValue::DataModel::Element.new("all_parts", true),
|
|
144
|
-
)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def all_parts_from_kv(model, value)
|
|
148
|
-
model.all_parts = value
|
|
149
146
|
end
|
|
150
147
|
|
|
151
148
|
# Serialize typed_stage as just its unique code (e.g. "is", "dis",
|
|
@@ -213,8 +210,10 @@ module Pubid
|
|
|
213
210
|
doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
|
|
214
211
|
end
|
|
215
212
|
|
|
213
|
+
# number/part/subpart are plain strings; the converter name is kept
|
|
214
|
+
# so the key_value map below does not have to change.
|
|
216
215
|
def build_code(value)
|
|
217
|
-
|
|
216
|
+
value.to_s
|
|
218
217
|
end
|
|
219
218
|
|
|
220
219
|
# --- date serialized flat as year/month/day ---
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Iso
|
|
5
|
+
module Identifiers
|
|
6
|
+
# Every part of one ISO document: "ISO 9000 (all parts)".
|
|
7
|
+
#
|
|
8
|
+
# The URN is the series URN: the document URN without its stage, plus
|
|
9
|
+
# the "ser" slot.
|
|
10
|
+
class AllParts < ::Pubid::Iso::Identifier
|
|
11
|
+
include ::Pubid::AllParts
|
|
12
|
+
|
|
13
|
+
def to_urn
|
|
14
|
+
"#{identity.exclude(:stage, :typed_stage).to_urn}:ser"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -4,7 +4,10 @@ module Pubid
|
|
|
4
4
|
module Iso
|
|
5
5
|
module Identifiers
|
|
6
6
|
class Directives < SingleIdentifier
|
|
7
|
-
|
|
7
|
+
# A plain string ("JTC 1"). The serialized form flattens from
|
|
8
|
+
# `{"value" => "JTC 1"}` to `"JTC 1"`, so the 5 directives rows of
|
|
9
|
+
# relaton-data-iso need a re-crawl; no compatibility shim is kept.
|
|
10
|
+
attribute :subgroup, :string
|
|
8
11
|
|
|
9
12
|
# Merges with Identifier's block (base attributes); only adds the
|
|
10
13
|
# Directives-specific subgroup so it survives to_hash/from_hash.
|
|
@@ -46,15 +49,15 @@ module Pubid
|
|
|
46
49
|
parts << ([publisher] + copubs).map(&:body).map(&:downcase).join("-")
|
|
47
50
|
|
|
48
51
|
if subgroup
|
|
49
|
-
subgroup_parts = subgroup.
|
|
52
|
+
subgroup_parts = subgroup.split
|
|
50
53
|
parts << subgroup_parts[0].downcase if subgroup_parts[0]
|
|
51
54
|
parts << subgroup_parts[1] if subgroup_parts[1]
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
parts << "dir"
|
|
55
58
|
|
|
56
|
-
parts << number.
|
|
57
|
-
parts << part.
|
|
59
|
+
parts << number.to_s if number
|
|
60
|
+
parts << part.to_s.downcase if part
|
|
58
61
|
parts << date.year if date
|
|
59
62
|
|
|
60
63
|
parts.join(":")
|
|
@@ -89,8 +89,10 @@ format: nil, stage_format_long: nil, with_date: nil, **opts)
|
|
|
89
89
|
def to_supplement_s(lang: :en, lang_single: false, with_edition: false,
|
|
90
90
|
format: nil, stage_format_long: nil, with_date: nil, **_opts)
|
|
91
91
|
date_str = if date
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
# Components::Date#render already carries the month
|
|
93
|
+
# (and day) when present — appending a month_part
|
|
94
|
+
# here doubled it (":2016-05-05-05").
|
|
95
|
+
":#{date.render}"
|
|
94
96
|
else
|
|
95
97
|
""
|
|
96
98
|
end
|