pubid 2.0.0.pre.alpha.12 → 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/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/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/national_annex.rb +18 -20
- 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/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 +8 -0
- 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 +2 -0
- data/lib/pubid/csa/identifier.rb +13 -1
- data/lib/pubid/csa/renderer.rb +12 -12
- data/lib/pubid/csa/single_identifier.rb +17 -0
- 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 +2 -0
- data/lib/pubid/gb/CLAUDE.md +140 -0
- data/lib/pubid/gb/builder.rb +7 -2
- data/lib/pubid/gb/identifier.rb +5 -3
- data/lib/pubid/gb/identifiers/all_parts.rb +17 -0
- data/lib/pubid/gb/identifiers.rb +1 -0
- data/lib/pubid/gb/renderer.rb +0 -1
- 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 +161 -17
- data/lib/pubid/idf/builder.rb +6 -1
- data/lib/pubid/idf/identifier.rb +5 -0
- data/lib/pubid/idf/identifiers/all_parts.rb +17 -0
- data/lib/pubid/idf/identifiers.rb +1 -0
- 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 +134 -5
- 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/parser.rb +134 -21
- data/lib/pubid/ieee/renderer.rb +40 -7
- data/lib/pubid/ieee/urn_generator.rb +31 -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 +19 -5
- data/lib/pubid/iso/components/publisher.rb +2 -0
- data/lib/pubid/iso/identifier.rb +6 -14
- data/lib/pubid/iso/identifiers/all_parts.rb +19 -0
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -2
- data/lib/pubid/iso/identifiers.rb +1 -0
- data/lib/pubid/iso/rendering_style.rb +0 -1
- data/lib/pubid/itu/CLAUDE.md +69 -0
- data/lib/pubid/itu/builder.rb +2 -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/supplement.rb +15 -0
- 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 +2 -0
- 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 +24 -3
- data/lib/pubid/nist/parser.rb +15 -2
- data/lib/pubid/nist/preprocessor.rb +53 -2
- 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 +20 -0
- 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/certification_system.rb +34 -0
- data/lib/pubid/oiml/identifiers/code_number.rb +8 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +174 -0
- data/lib/pubid/oiml/identifiers.rb +2 -0
- data/lib/pubid/oiml/parser.rb +35 -4
- data/lib/pubid/oiml/renderer.rb +23 -1
- data/lib/pubid/oiml/single_identifier.rb +4 -0
- data/lib/pubid/oiml/supplement_identifier.rb +7 -0
- data/lib/pubid/oiml/urn_generator.rb +28 -0
- 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/human_readable.rb +0 -1
- data/lib/pubid/sae/builder.rb +2 -0
- data/lib/pubid/sae/components/date.rb +2 -0
- data/lib/pubid/sae/components/type.rb +2 -0
- 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
- metadata +44 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 177a3443a2daa5ff1848fb31a5136ea7eb05986005590c5938b0ae88874b3ef2
|
|
4
|
+
data.tar.gz: 4eeb9f9a26023aa610e821951febd68b5ef5a30db366eeeef07d595e67097557
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d1a4ad6d0ec70be65ed8e8773c92feda1f63ec623ff59ee4e15a92683e762fa7ed9fc687391d8456731cfe6120c1ef144971422002ecdc9dfe40dfb5482959a
|
|
7
|
+
data.tar.gz: fa1d3d71d2dd96d24ac9e4804a8be54ecfbe02b8fd460a329f0ae6aa2366838670ed5242a3bb3f3d94b5e325dc6494902a94223a94a9ef377374f8ac8baf8fc3
|
data/README.adoc
CHANGED
|
@@ -229,6 +229,48 @@ id.exclude(:year, :part).to_s
|
|
|
229
229
|
# => "ISO 9001"
|
|
230
230
|
----
|
|
231
231
|
|
|
232
|
+
=== Matching a Partial Reference
|
|
233
|
+
|
|
234
|
+
The `===` operator is a subset match. It returns true when the candidate holds
|
|
235
|
+
every part that the reference states. A part that the reference omits matches
|
|
236
|
+
any value. The receiver is the reference, so the operator is not symmetric:
|
|
237
|
+
|
|
238
|
+
[source,ruby]
|
|
239
|
+
----
|
|
240
|
+
require 'pubid/iso'
|
|
241
|
+
|
|
242
|
+
reference = Pubid::Iso.parse("ISO 9001")
|
|
243
|
+
reference === Pubid::Iso.parse("ISO 9001:2015")
|
|
244
|
+
# => true
|
|
245
|
+
reference === Pubid::Iso.parse("ISO/DIS 9001")
|
|
246
|
+
# => false (a default value, here the published stage, is stated)
|
|
247
|
+
|
|
248
|
+
catalogue.grep(reference)
|
|
249
|
+
# => every edition of ISO 9001 in the catalogue
|
|
250
|
+
----
|
|
251
|
+
|
|
252
|
+
Some flavors state a part even when it is nil, because the document really
|
|
253
|
+
has none. Those classes declare it strict, so the reference does not widen:
|
|
254
|
+
|
|
255
|
+
[source,ruby]
|
|
256
|
+
----
|
|
257
|
+
Pubid::Ecma.parse("ECMA-418") === Pubid::Ecma.parse("ECMA-418-1")
|
|
258
|
+
# => false (ECMA-418 has no part)
|
|
259
|
+
Pubid::Ecma.parse("ECMA-418-1") === Pubid::Ecma.parse("ECMA-418-1 ed1")
|
|
260
|
+
# => true
|
|
261
|
+
----
|
|
262
|
+
|
|
263
|
+
A reference asks for every part of a document with `all_parts`:
|
|
264
|
+
|
|
265
|
+
[source,ruby]
|
|
266
|
+
----
|
|
267
|
+
Pubid::Iso.parse("ISO 9001 (all parts)") === Pubid::Iso.parse("ISO 9001-1:2015")
|
|
268
|
+
# => true
|
|
269
|
+
----
|
|
270
|
+
|
|
271
|
+
See `docs/SUBSET_MATCH.md` for the full rules and the list of strict
|
|
272
|
+
attributes.
|
|
273
|
+
|
|
232
274
|
=== Comparing Editions
|
|
233
275
|
|
|
234
276
|
The `new_edition_of?` method checks if an identifier is a newer edition of the same document:
|
|
@@ -1148,7 +1190,7 @@ ASME BPVC.CC.BPV-2021 # Case Code BPV
|
|
|
1148
1190
|
|
|
1149
1191
|
Special Variants:
|
|
1150
1192
|
ASME BPVC COMPLETE CODE BIND-2019 # Complete code set
|
|
1151
|
-
ASME BPVC-CC-BPV-2019 # Dash notation
|
|
1193
|
+
ASME BPVC-CC-BPV-2019 # Dash notation; ASME lists it apart from BPVC.CC.BPV
|
|
1152
1194
|
----
|
|
1153
1195
|
|
|
1154
1196
|
.BPVC Components
|
data/data/ieee/update_codes.yaml
CHANGED
|
@@ -157,15 +157,15 @@ ISO/IEC/IEEE CD P26513/D1, August 2015: ISO/IEC/IEEE P26513/D1, August 2015
|
|
|
157
157
|
"ISO/IEC/IEEE/P16085_DIS, March 2020": "ISO/IEC/IEEE DIS P16085-2020-03"
|
|
158
158
|
"ANSI/IEEE Std: Outdoor Apparatus Bushings": "ANSI/IEEE Std 21-1976-11"
|
|
159
159
|
"Draft National Electrical Safety Code, January 2016": "IEEE PC2-2016-01"
|
|
160
|
-
"International Standard ISO/IEC 8802-9: 1996(E) ANSI/IEEE Std 802.9, 1996 Edition": "ISO/IEC/IEEE Std 802.9
|
|
161
|
-
"ISO/IEC13210: 1994 (E) ANSI/IEEE Std 1003.3-1991": "ISO/IEC/IEEE
|
|
160
|
+
"International Standard ISO/IEC 8802-9: 1996(E) ANSI/IEEE Std 802.9, 1996 Edition": "ISO/IEC 8802-9:1996(E); ANSI/IEEE Std 802.9, 1996 Edition"
|
|
161
|
+
"ISO/IEC13210: 1994 (E) ANSI/IEEE Std 1003.3-1991": "ISO/IEC 13210:1994 (E); ANSI/IEEE Std 1003.3-1991"
|
|
162
162
|
"J-STD-016-1995": "IEEE 016-1995"
|
|
163
163
|
"Nuclear EQ Sourcebook and Supplement": "IEEE 7438946"
|
|
164
164
|
"PC37.30.2/D043 Rev 18, May 2015": "IEEE PC37.30-2/D-043/R-18-2015"
|
|
165
165
|
"IEEE/IEC P62582 CD2 proposal, May 2017": "IEEE/IEC CD2 P62582-2017-05"
|
|
166
|
-
"ISO/IEC/IEEE P16326:201x WD.4a, July 2017": "ISO/IEC/IEEE P16326/D
|
|
166
|
+
"ISO/IEC/IEEE P16326:201x WD.4a, July 2017": "ISO/IEC/IEEE P16326:2017/D=WD.4a"
|
|
167
167
|
"ISO/IEC/IEEE CD.1 P21839, October 2017": "ISO/IEC/IEEE CD1 P21839-2017-10"
|
|
168
|
-
"ISO/IEC/IEEE P16326:201x WD5, December 2017": "ISO/IEC/IEEE P16326/D
|
|
168
|
+
"ISO/IEC/IEEE P16326:201x WD5, December 2017": "ISO/IEC/IEEE P16326:2017/D=WD.5"
|
|
169
169
|
"IEEE/ISO/IEC P42010.CD1-V1.0, April 2020": "IEEE/ISO/IEC CD1 P42010-2020-04"
|
|
170
170
|
"Unapproved Draft Std ISO/IEC FDIS 15288:2007(E) IEEE P15288/D3,": "ISO/IEC/IEEE FDIS Std P15288/D-3-2007"
|
|
171
171
|
"IS0/IEC/IEEE 8802-11:2012/Amd.5:2015(E) (Adoption of IEEE Std 802.11af-2014)": "ISO/IEC/IEEE 802.11/Amd5-2012"
|
|
@@ -208,3 +208,16 @@ ISO/IEC/IEEE CD P26513/D1, August 2015: ISO/IEC/IEEE P26513/D1, August 2015
|
|
|
208
208
|
"ISO/IEC/IEEE/ P12207.2/D-3_FDIS-2020": "ISO/IEC/IEEE FDIS P12207.2-2020/D3"
|
|
209
209
|
"ISO/IEC/IEEE/ P24748.3/D-IS-2019": "ISO/IEC/IEEE DIS P24748.3-2019"
|
|
210
210
|
"P1635/D10/ASHARE 21/D-10-2016": "IEEE P1635/D10-2016"
|
|
211
|
+
# The joint-publisher underscore drafts ("ISO /IEC/IEEE P24774_D1, February
|
|
212
|
+
# 2020") are the slash spellings ("/D1") of rows the ledger already pins
|
|
213
|
+
# as project drafts; the underscore form parsed through the printed-joint
|
|
214
|
+
# family and flipped the classification (pubid#430). Applied after the
|
|
215
|
+
# exact one-off rules above so their targets stay reachable.
|
|
216
|
+
# Dated: the trailing text date rides in the draft clause with the long
|
|
217
|
+
# comma the project-draft route pins ("...D1, February, 2020").
|
|
218
|
+
# Undated.
|
|
219
|
+
# Dated: the trailing text date rides in the draft clause with the long
|
|
220
|
+
# comma the project-draft route pins ("...D1, February, 2020").
|
|
221
|
+
/\b(ISO ?\/ ?IEC ?\/ ?IEEE|IEC ?\/ ?IEEE) (P\d+)_D(\d+), ([A-Z][a-z]+.?) (\d{4})\b/: "\\1 \\2/D\\3, \\4, \\5"
|
|
222
|
+
# Undated.
|
|
223
|
+
/\b(ISO ?\/ ?IEC ?\/ ?IEEE|IEC ?\/ ?IEEE) (P\d+)_D(\d+)\b/: "\\1 \\2/D\\3"
|
data/data/nist/update_codes.yaml
CHANGED
|
@@ -38,6 +38,8 @@ NIST AI NIST AI 100-2e2023 ipd: NIST AI 100-2e2023 ipd
|
|
|
38
38
|
NBS CIRC 154suprev: NBS CIRC 154r1sup
|
|
39
39
|
NBS CIRC supJun1925-Jun1926: NBS CIRC 24e7sup2
|
|
40
40
|
NBS CIRC supJun1925-Jun1927: NBS CIRC 24e7sup3
|
|
41
|
+
NBS.CIRC.supJun1925-Jun1926: NBS CIRC 24e7sup2
|
|
42
|
+
NBS.CIRC.supJun1925-Jun1927: NBS CIRC 24e7sup3
|
|
41
43
|
/^NBS CIRC sup$/: NBS CIRC 24e7sup
|
|
42
44
|
NBS CIRC 25sup-1924: NBS CIRC 25sup
|
|
43
45
|
NIST SP 260-126 rev 2013: NIST SP 260-126r2013
|
|
@@ -63,6 +65,7 @@ NIST AMS 300-8r1/upd: NIST AMS 300-8r1/Upd1-202102
|
|
|
63
65
|
NIST IR 8115r1-upd: NIST IR 8115r1/Upd1-202103
|
|
64
66
|
NIST IR 8170-upd: NIST IR 8170/Upd1-202003
|
|
65
67
|
NIST TN 2150-upd: NIST TN 2150/Upd1-202102
|
|
68
|
+
NIST.TN.2150-upd: NIST.TN.2150-upd1-202102
|
|
66
69
|
NBS IR 73-197r: NBS IR 73-197r1
|
|
67
70
|
NBS.HB.105-1r1990: NIST.HB.105-1r1990
|
|
68
71
|
NBS.HB.28p11969: NBS.HB.28-1969pt1
|
|
@@ -97,6 +100,7 @@ NIST SP 500-281-v1 0: NIST SP 500-281v1.0
|
|
|
97
100
|
NIST SP 800-63v1 0 1: NIST SP 800-63v1.0.1
|
|
98
101
|
NIST SP 800-63v1 0 2: NIST SP 800-63v1.0.2
|
|
99
102
|
NIST SP 955 Suppl: NIST SP 955sup
|
|
103
|
+
NIST.SP.955.Suppl: NIST.SP.955-S.uppl
|
|
100
104
|
NIST SP 984 4: NIST SP 984-4
|
|
101
105
|
NISTPUB 0413171251: NIST TN 1648-2009
|
|
102
106
|
/\-draft$/: " (Draft)"
|
|
@@ -109,9 +113,9 @@ NIST IR 8413-upd1: NIST IR 8413/Upd1-202207
|
|
|
109
113
|
NIST IR 85-3273-37-upd1: NIST IR 85-3273-37/Upd1-202205
|
|
110
114
|
/NBS CRPL-F-B(?=\d+)/: "NBS CRPL-F-B "
|
|
111
115
|
"NIST.AMS.300-8r1/upd": NIST.AMS.300-8r1-upd1
|
|
112
|
-
NIST.hb.150-1-2017: NIST
|
|
113
|
-
nbs.tn.671: NBS
|
|
114
|
-
NIST.TN.1648_2009: NIST
|
|
116
|
+
NIST.hb.150-1-2017: NIST.HB.105-1r2017
|
|
117
|
+
nbs.tn.671: NBS.TN.671
|
|
118
|
+
NIST.TN.1648_2009: NIST.TN.1648e2009
|
|
115
119
|
NBS NSRDS: NSRDS-NBS
|
|
116
120
|
nist ir: NIST IR
|
|
117
121
|
/(?<=\d)es/: (spa)
|
data/lib/pubid/adobe/builder.rb
CHANGED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pubid"
|
|
4
|
+
module Pubid
|
|
5
|
+
# Every part of one document, e.g. "ISO 9000 (all parts)".
|
|
6
|
+
#
|
|
7
|
+
# The class that includes this module holds part identifiers of one
|
|
8
|
+
# document in `identifiers`, in natural order and without duplicates. A
|
|
9
|
+
# member with no part stands for the whole document; it is permitted only
|
|
10
|
+
# as the sole member.
|
|
11
|
+
#
|
|
12
|
+
# A flavor includes it in a subclass of its own `Identifier`, so the
|
|
13
|
+
# all-parts identifier of a flavor is an identifier of that flavor
|
|
14
|
+
# (`Pubid::Iso::Identifiers::AllParts < Pubid::Iso::Identifier`). The
|
|
15
|
+
# subclass names its own suffix or URN; everything else comes from here.
|
|
16
|
+
# A flavor with no such class uses {Pubid::AllPartsIdentifier}.
|
|
17
|
+
#
|
|
18
|
+
# `==` compares the members. `===` compares the document only: the first
|
|
19
|
+
# member without its part and its edition (see #identity).
|
|
20
|
+
module AllParts
|
|
21
|
+
SUFFIX = " (all parts)"
|
|
22
|
+
|
|
23
|
+
# The members hold the whole identity, so the hash carries nothing else.
|
|
24
|
+
# Without the key_value block the serializer reads every inherited
|
|
25
|
+
# attribute, and the derived #number below would be written too.
|
|
26
|
+
def self.included(base)
|
|
27
|
+
base.attribute :identifiers, ::Pubid::Identifier, polymorphic: true,
|
|
28
|
+
collection: true,
|
|
29
|
+
initialize_empty: true
|
|
30
|
+
declare_key_value(base)
|
|
31
|
+
base.extend(ClassMethods)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# lutaml MERGES a subclass block onto the flavor's own block, so the
|
|
35
|
+
# derived #number below would be written as a top-level key. A no-op
|
|
36
|
+
# converter keeps it out.
|
|
37
|
+
def self.declare_key_value(base)
|
|
38
|
+
base.key_value do
|
|
39
|
+
map "_type", to: :_type
|
|
40
|
+
map "identifiers", to: :identifiers
|
|
41
|
+
map "number", with: { to: :number_to_kv, from: :number_from_kv }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module ClassMethods
|
|
46
|
+
# lutaml's from_hash builds the object with no attributes and assigns
|
|
47
|
+
# `identifiers` after #initialize, so it normalizes here too.
|
|
48
|
+
def from_hash(data, options = {})
|
|
49
|
+
super.tap do |id|
|
|
50
|
+
id.send(:normalize_identifiers!) if id.is_a?(::Pubid::AllParts)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def initialize(attrs = {}, options = {})
|
|
56
|
+
super
|
|
57
|
+
normalize_identifiers!
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The members hold the number, so it is neither written nor read.
|
|
61
|
+
def number_to_kv(_model, _doc); end
|
|
62
|
+
|
|
63
|
+
def number_from_kv(_model, _value); end
|
|
64
|
+
|
|
65
|
+
# @param other [Object] a candidate identifier
|
|
66
|
+
# @return [Boolean] true when +other+ is any part of the same document,
|
|
67
|
+
# in any edition
|
|
68
|
+
def ===(other)
|
|
69
|
+
return false unless other.is_a?(::Pubid::Identifier) && identity
|
|
70
|
+
|
|
71
|
+
identity === document_of(other)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Another all-parts identifier with +other+ added. The receiver does not
|
|
75
|
+
# change.
|
|
76
|
+
# @param other [Pubid::Identifier] a part of the same document, or
|
|
77
|
+
# another all-parts identifier of it
|
|
78
|
+
# @return [Pubid::Identifier] an all-parts identifier of the same class
|
|
79
|
+
# @raise [ArgumentError] for a different document, an identifier with no
|
|
80
|
+
# part, or a part that is already a member
|
|
81
|
+
def +(other)
|
|
82
|
+
members = other.is_a?(::Pubid::AllParts) ? other.identifiers : [other]
|
|
83
|
+
members.each { |member| validate_member!(member) }
|
|
84
|
+
self.class.new(identifiers: identifiers + members)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def to_s(**opts)
|
|
88
|
+
return "" unless identity
|
|
89
|
+
|
|
90
|
+
annotate_plain_render(
|
|
91
|
+
"#{identity.to_s(**opts.except(:annotated))}#{self.class::SUFFIX}",
|
|
92
|
+
**opts,
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# The all-parts attributes are empty, so the flavor renderers cannot
|
|
97
|
+
# print it. Only the human form exists yet; `to_mr_string` and `to_slug`
|
|
98
|
+
# come through here and raise too.
|
|
99
|
+
def render(format: :human, **opts)
|
|
100
|
+
return to_s(**opts) if format == :human
|
|
101
|
+
|
|
102
|
+
raise NotImplementedError,
|
|
103
|
+
"an all-parts identifier has no #{format} form yet"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def to_urn
|
|
107
|
+
raise NotImplementedError, "an all-parts identifier has no URN yet"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def to_all_parts
|
|
111
|
+
self
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def root
|
|
115
|
+
identifiers.first&.root
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# The document number, e.g. "9000". The index keys on it.
|
|
119
|
+
def number
|
|
120
|
+
identity&.number
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# True here and false for every other identifier, so a caller that reads
|
|
124
|
+
# the old flag still works.
|
|
125
|
+
# rubocop:disable Naming/PredicateMethod
|
|
126
|
+
def all_parts
|
|
127
|
+
true
|
|
128
|
+
end
|
|
129
|
+
# rubocop:enable Naming/PredicateMethod
|
|
130
|
+
|
|
131
|
+
def all_parts?
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def base_document
|
|
136
|
+
identifiers.first&.base_document
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
protected
|
|
140
|
+
|
|
141
|
+
# The document: the first member without its part, its subpart and its
|
|
142
|
+
# edition. #document_of reads it from another all-parts identifier, so it
|
|
143
|
+
# is protected and not private.
|
|
144
|
+
# @return [Pubid::Identifier, nil]
|
|
145
|
+
def identity
|
|
146
|
+
first = identifiers.first
|
|
147
|
+
first && document_of(first)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
# The document of +id+: +id+ without its part and its edition.
|
|
153
|
+
def document_of(id)
|
|
154
|
+
return id.identity if id.is_a?(::Pubid::AllParts)
|
|
155
|
+
|
|
156
|
+
id.without_parts(*id.class.all_parts_edition_keys)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def validate_member!(id)
|
|
160
|
+
unless id.is_a?(::Pubid::Identifier)
|
|
161
|
+
raise ArgumentError, "not an identifier: #{id.inspect}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
raise ArgumentError, "#{id} is not a part of #{self}" unless self === id
|
|
165
|
+
raise ArgumentError, "#{id} has no part" unless id.part?
|
|
166
|
+
return unless identifiers.any? { |member| same_member?(member, id) }
|
|
167
|
+
|
|
168
|
+
raise ArgumentError, "#{id} is already a member of #{self}"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def same_member?(one, other)
|
|
172
|
+
one.normalized_copy == other.normalized_copy
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Sort, remove duplicates, and drop the whole-document member when a
|
|
176
|
+
# part is present. `==` and `to_hash` depend on this order.
|
|
177
|
+
def normalize_identifiers!
|
|
178
|
+
members = unique_members
|
|
179
|
+
parts = members.select(&:part?)
|
|
180
|
+
self.identifiers = sorted(parts.empty? ? members : parts)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def unique_members
|
|
184
|
+
identifiers.each_with_object([]) do |member, acc|
|
|
185
|
+
acc << member unless acc.any? { |kept| same_member?(kept, member) }
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# One member needs no sort, and #to_s raises on an abstract class.
|
|
190
|
+
def sorted(members)
|
|
191
|
+
return members if members.size < 2
|
|
192
|
+
|
|
193
|
+
members.sort_by { |member| natural_key(member.to_s) }
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# "ISO 9000-10" sorts after "ISO 9000-2".
|
|
197
|
+
def natural_key(str)
|
|
198
|
+
str.split(/(\d+)/).map { |s| s.match?(/\A\d+\z/) ? [0, s.to_i] : [1, s] }
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pubid"
|
|
4
|
+
module Pubid
|
|
5
|
+
# The all-parts identifier of a flavor that has no class of its own.
|
|
6
|
+
# A flavor that prints "(all parts)" or has a series URN gives its own
|
|
7
|
+
# class instead: see {Pubid::AllParts} and `Identifier.all_parts_class`.
|
|
8
|
+
class AllPartsIdentifier < Identifier
|
|
9
|
+
include AllParts
|
|
10
|
+
|
|
11
|
+
# This class belongs to no flavor, so its name carries no flavor segment
|
|
12
|
+
# and {TypeResolver} resolves it directly.
|
|
13
|
+
def self.polymorphic_name
|
|
14
|
+
return super unless self == ::Pubid::AllPartsIdentifier
|
|
15
|
+
|
|
16
|
+
"pubid:all-parts"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# AMCA flavor notes
|
|
2
|
+
|
|
3
|
+
AMCA index key and MR slug.
|
|
4
|
+
|
|
5
|
+
These notes were part of the root `CLAUDE.md`. Read them before you change `lib/pubid/amca/` or `spec/pubid/amca/`. The root file keeps the cross-flavor contract that every flavor obeys.
|
|
6
|
+
|
|
7
|
+
## From the root note "AMCA / ASME / ASTM index key (`root.number`): three flavors, three different shapes"
|
|
8
|
+
|
|
9
|
+
**(1) AMCA — flat `:string` columns on the leaves, and a latent `==` bug fixed with them.** `code` is deleted and each of the three leaves declares `attribute :number, :string`. An earlier draft kept the inherited `Components::Code` instead (AMCA's own `Components::Code` resolved to `Pubid::Components::Code` — there is no `lib/pubid/amca/components/code.rb` — so nothing needed retyping, the CSA case); that works too, and the serialized bytes are identical either way, but the flat string matches the other flavors here and lets the custom `key_value` converters go entirely. **The converters were what hid a real bug.** `year` was declared `Components::Date`, yet the builder assigns a String and lutaml does not cast it — so the **parse** path held a String while **from_hash** produced a `Components::Date`. `to_hash` and `to_s` agreed, because `year_to_kv` normalised both shapes to a scalar, so the relaton index gate (`from_hash(to_hash) == to_hash`) passed — while **`parse(x) == from_hash(parse(x).to_hash)` was false for every AMCA id**, breaking `#matches?`, which is built on `==`. `year` is now `:string` too, both `with:` converters are gone (every mapped attribute is a plain scalar, and the canonical `to_hash` already drops empty and default values), and a spec asserts round-trip **equality**, not just hash equality — the stronger check that would have caught it. **Lesson: a `with:` converter that normalises two possible runtime shapes is a signal that the attribute type is wrong, not a fix.** The serialized key moved `code` → `number` (no consumer). **AMCA's `Publication` and `Interpretation` also lost hand-written keyword `initialize` methods** that assigned ivars directly and bypassed lutaml — costing them their `_type` (so `from_hash` could not route back), their `publisher` default, and the serialization of `revision`/`interpretation_code`, which were `attr_reader`s `to_hash` dropped. Both are now ordinary lutaml attributes; the builder already called `new(**attributes)` exactly as it does for `Standard`, which never had the problem. This is the AIEE/IRE/NESC migration applied again.
|
|
10
|
+
|
|
11
|
+
## Revision, rendering and URN (hand-off `asme-bpvc-and-amca-residue`)
|
|
12
|
+
|
|
13
|
+
**The publication revision never reached the object.** The grammar captured only `01` of `Rev. 01-23`, and `Builder#build_publication` read it under `parsed[:revision]`, where the grammar did not put it. The grammar now captures the whole `01-23` as `:revision`, so `revision`, `to_hash`, `to_s` and the URN (`rev.01-23`) carry it.
|
|
14
|
+
|
|
15
|
+
**The renderer lost text.** It printed `AMCA Publication 211 -22` (a space before the year), `AMCA 99 – JW` (no `Interp`), and `(2010)` for `(R2010)`. Every parseable AMCA fixture id now renders as it was written, except the real normalizations (`ANSI/AMCA 220-21` → `ANSI/AMCA Standard 220-21`).
|
|
16
|
+
|
|
17
|
+
**Every AMCA URN held a Ruby Hash.** `urn_type` interpolated the `type` metadata Hash (`copub.amca:{key: :publication, ...}`); it now reads `type[:key]`, the source `mr_type` reads. The URN also carries the interpretation code (`interp.jw`), so the interpretations of one standard no longer share a URN. `UrnParser` reads every token back (type, copublisher, interpretation code, revision, reaffirmation), so all 50 parseable fixture ids come back `==` from their URN; before, it rebuilt a bare `AMCA <number>-<year>` Standard.
|
|
18
|
+
|
|
19
|
+
**Not fixed, pre-existing:** `AMCA 204 – 1` and `ANSI/AMCA Standard 210-25 / ASHRAE 51-25` do not parse. `ANSI/AMCA 210-16 /ASHRAE 51-16` parses but silently drops `/ASHRAE 51-16`, because `additional_copublisher` has no capture. The `suffix` rule of `standard_identifier` has no capture either, so `suffix` is never set on a `Standard`.
|
|
20
|
+
|
|
21
|
+
## `all_parts_edition_keys`: Publication's `revision`, then the shared `reaffirmed`
|
|
22
|
+
|
|
23
|
+
`Identifier.all_parts_edition_keys` defaults to `%i[date year edition
|
|
24
|
+
version]`. A first pass fixed `Identifiers::Publication#revision` (the
|
|
25
|
+
`Rev. 01-23` token), a separate discriminator that list never covered, so
|
|
26
|
+
`"AMCA Publication 211-22 (Rev. 01-23)".to_all_parts` did not collapse
|
|
27
|
+
onto another revision of the same publication under `#to_all_parts`/`#===`.
|
|
28
|
+
Fixed with `Identifiers::Publication.all_parts_edition_keys` (`super +
|
|
29
|
+
%i[revision]`), declared on `Publication` itself rather than the shared
|
|
30
|
+
`Pubid::Amca::Identifier` base — `Standard`/`Interpretation` don't carry
|
|
31
|
+
`revision`.
|
|
32
|
+
|
|
33
|
+
Code review of that same change found a second, wider gap it had missed:
|
|
34
|
+
`reaffirmed` (the `"(R2010)"` year) is declared on the shared
|
|
35
|
+
`Pubid::Amca::Identifier` base (`identifiers/base.rb`), not on
|
|
36
|
+
`Publication`, and `Renderer#render_base` reads it for **every** leaf —
|
|
37
|
+
`Standard` as well as `Publication` — so `"AMCA 210-16 (R2010)"` failed to
|
|
38
|
+
collapse onto `"AMCA 210-16 (R2015)"` even though neither is a
|
|
39
|
+
`Publication`. Fixed on the shared base itself:
|
|
40
|
+
`Pubid::Amca::Identifier.all_parts_edition_keys` is `super +
|
|
41
|
+
%i[reaffirmed]`; `Publication`'s own override chains through `super` and
|
|
42
|
+
picks it up automatically. **Lesson**: a discriminator declared on a
|
|
43
|
+
shared base needs the override on that base, not repeated per leaf — and,
|
|
44
|
+
per the IEEE entry above, finding one missed attribute is not proof the
|
|
45
|
+
audit is complete. Not part of the original hand-off's audit list (which
|
|
46
|
+
didn't cover AMCA); found during code review of the OGC/3GPP/NIST fix.
|
|
47
|
+
Locked by `spec/pubid/all_parts_edition_keys_audit_spec.rb`.
|
data/lib/pubid/amca/builder.rb
CHANGED
|
@@ -154,11 +154,7 @@ module Pubid
|
|
|
154
154
|
|
|
155
155
|
# Extract revision (Rev. 01-23)
|
|
156
156
|
if parsed[:revision]
|
|
157
|
-
|
|
158
|
-
if revision_data && revision_data[:revision_year]
|
|
159
|
-
attributes[:revision] =
|
|
160
|
-
extract_value(revision_data[:revision_year])
|
|
161
|
-
end
|
|
157
|
+
attributes[:revision] = extract_value(parsed[:revision])
|
|
162
158
|
end
|
|
163
159
|
|
|
164
160
|
Identifiers::Publication.new(**attributes)
|
|
@@ -174,3 +170,5 @@ module Pubid
|
|
|
174
170
|
end
|
|
175
171
|
end
|
|
176
172
|
end
|
|
173
|
+
|
|
174
|
+
Pubid::Amca::Builder.prepend(Pubid::Builder::AllPartsWrap)
|
|
@@ -87,6 +87,16 @@ module Pubid
|
|
|
87
87
|
def mr_year
|
|
88
88
|
year&.to_s
|
|
89
89
|
end
|
|
90
|
+
|
|
91
|
+
# `reaffirmed` (the "(R2010)" year, read by Renderer#render_base — used
|
|
92
|
+
# for Standard as well as Publication) is a discriminator the default
|
|
93
|
+
# %i[date year edition version] list misses, shared by every leaf that
|
|
94
|
+
# inherits this class. Declared here, not per-leaf, so Standard's own
|
|
95
|
+
# reaffirmations collapse too; Publication's revision (see
|
|
96
|
+
# publication.rb) is layered on top via `super`.
|
|
97
|
+
def self.all_parts_edition_keys
|
|
98
|
+
super + %i[reaffirmed]
|
|
99
|
+
end
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
102
|
end
|
|
@@ -28,6 +28,19 @@ module Pubid
|
|
|
28
28
|
def self.type
|
|
29
29
|
{ key: :publication, title: "Publication", short: nil }
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
# `revision` is Publication's edition/version discriminator and is
|
|
33
|
+
# not in the default %i[date year edition version] list, so
|
|
34
|
+
# #to_all_parts/#=== failed to collapse two revisions of the same
|
|
35
|
+
# publication (e.g. "AMCA Publication 211-22 (Rev. 01-23)" vs
|
|
36
|
+
# "... (Rev. 02-23)"). Declared here, not on the shared
|
|
37
|
+
# Pubid::Amca::Identifier base, because `revision` is
|
|
38
|
+
# Publication-only — Standard and Interpretation don't carry it.
|
|
39
|
+
# `super` also picks up `reaffirmed`, added on the shared base
|
|
40
|
+
# (identifiers/base.rb) since Standard carries that one too.
|
|
41
|
+
def self.all_parts_edition_keys
|
|
42
|
+
super + %i[revision]
|
|
43
|
+
end
|
|
31
44
|
end
|
|
32
45
|
end
|
|
33
46
|
end
|
data/lib/pubid/amca/parser.rb
CHANGED
|
@@ -62,7 +62,8 @@ module Pubid
|
|
|
62
62
|
|
|
63
63
|
# Publication revision (Rev. 01-23)
|
|
64
64
|
rule(:revision) do
|
|
65
|
-
lparen >> str("Rev") >> dot.maybe >> space >>
|
|
65
|
+
lparen >> str("Rev") >> dot.maybe >> space >>
|
|
66
|
+
(digits >> dash >> digits).as(:revision) >> rparen
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
# Interpretation code (JW, KB, RG, AW, AH, or just a number)
|
data/lib/pubid/amca/renderer.rb
CHANGED
|
@@ -29,53 +29,42 @@ module Pubid
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
31
|
def render_base(id)
|
|
32
|
-
parts = []
|
|
33
|
-
parts << id.copublisher if id.copublisher
|
|
34
32
|
t = id.class.respond_to?(:type) ? id.class.type : nil
|
|
35
|
-
if t.is_a?(Hash) && t[:title]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
parts << id.number.to_s
|
|
39
|
-
parts << "-#{id.year}" if id.year
|
|
40
|
-
|
|
41
|
-
result = parts.compact.join(" ")
|
|
42
|
-
|
|
43
|
-
if id.copublisher&.include?("/") && id.year
|
|
44
|
-
type_title = t.is_a?(Hash) ? t[:title].to_s : ""
|
|
45
|
-
result = "#{id.copublisher} #{type_title} #{id.number}-#{id.year}"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
result += " (#{id.reaffirmed})" if id.reaffirmed
|
|
49
|
-
|
|
33
|
+
title = t[:title].to_s if t.is_a?(Hash) && t[:title]
|
|
34
|
+
result = document(id, title)
|
|
35
|
+
result += " (R#{id.reaffirmed})" if id.reaffirmed
|
|
50
36
|
result
|
|
51
37
|
end
|
|
52
38
|
|
|
39
|
+
# The revision and the reaffirmation are separate optional groups in
|
|
40
|
+
# the grammar, so either or both can appear.
|
|
53
41
|
def render_publication(id)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
parts << "-#{id.year}" if id.year
|
|
59
|
-
parts << " (Rev. #{id.revision})" if id.revision
|
|
60
|
-
parts << " (#{id.reaffirmed})" if id.reaffirmed && !id.revision
|
|
61
|
-
|
|
62
|
-
parts.join(" ").squeeze(" ")
|
|
42
|
+
result = document(id, "Publication")
|
|
43
|
+
result += " (Rev. #{id.revision})" if id.revision
|
|
44
|
+
result += " (R#{id.reaffirmed})" if id.reaffirmed
|
|
45
|
+
result
|
|
63
46
|
end
|
|
64
47
|
|
|
65
48
|
def render_interpretation(id)
|
|
66
|
-
|
|
67
|
-
parts << id.copublisher if id.copublisher
|
|
68
|
-
parts << id.number.to_s
|
|
49
|
+
result = [id.copublisher, id.number.to_s].compact.join(" ")
|
|
69
50
|
|
|
70
51
|
if id.interpretation_code
|
|
71
|
-
|
|
52
|
+
result += " #{id.interpretation_code} Interp"
|
|
72
53
|
elsif id.year
|
|
73
|
-
|
|
54
|
+
result += " – #{id.year}"
|
|
55
|
+
else
|
|
56
|
+
result += " Interp"
|
|
74
57
|
end
|
|
75
58
|
|
|
76
|
-
|
|
59
|
+
result += " #{id.suffix}" if id.suffix
|
|
60
|
+
result
|
|
61
|
+
end
|
|
77
62
|
|
|
78
|
-
|
|
63
|
+
# "AMCA Standard 803-02": the year joins the number with a bare dash.
|
|
64
|
+
def document(id, title)
|
|
65
|
+
result = [id.copublisher, title, id.number.to_s].compact.join(" ")
|
|
66
|
+
result += "-#{id.year}" if id.year
|
|
67
|
+
result
|
|
79
68
|
end
|
|
80
69
|
end
|
|
81
70
|
end
|
|
@@ -27,9 +27,26 @@ module Pubid
|
|
|
27
27
|
"copub.#{identifier.copublisher.to_s.downcase}" if identifier.copublisher
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# Identity-bearing: "AMCA 99 JW Interp" and "AMCA 99 KB Interp" are
|
|
31
|
+
# different documents.
|
|
32
|
+
def urn_interpretation
|
|
33
|
+
return nil unless identifier.respond_to?(:interpretation_code)
|
|
34
|
+
|
|
35
|
+
code = identifier.interpretation_code
|
|
36
|
+
"interp.#{code.downcase}" if code
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def urn_revision
|
|
40
|
+
revision = identifier.revision if identifier.respond_to?(:revision)
|
|
41
|
+
"rev.#{revision}" if revision
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# `type` is a metadata Hash; interpolating it put a Ruby Hash literal
|
|
45
|
+
# into every AMCA URN. The key is the source Identifier#mr_type reads.
|
|
30
46
|
def urn_type
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
return nil unless identifier.class.respond_to?(:type)
|
|
48
|
+
|
|
49
|
+
identifier.class.type[:key]&.to_s
|
|
33
50
|
end
|
|
34
51
|
|
|
35
52
|
def generate
|
|
@@ -37,6 +54,8 @@ module Pubid
|
|
|
37
54
|
parts << urn_number if urn_number
|
|
38
55
|
parts << urn_year if urn_year
|
|
39
56
|
parts << urn_suffix if urn_suffix
|
|
57
|
+
parts << urn_interpretation if urn_interpretation
|
|
58
|
+
parts << urn_revision if urn_revision
|
|
40
59
|
parts << urn_reaffirmed if urn_reaffirmed
|
|
41
60
|
parts << urn_copublisher if urn_copublisher
|
|
42
61
|
|