pubid 2.0.20 → 2.0.22
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 +73 -31
- data/data/iec/legacy-notation.md +298 -0
- data/data/iho/s4-reserved-specs.yaml +15 -0
- data/data/iso/historic-schemes.md +368 -0
- data/data/parg/bipm.json +1 -1
- data/data/parg/bipm.parg +46 -11
- data/data/parg/iec.json +1 -1
- data/data/parg/iho.json +1 -1
- data/data/parg/iho.parg +128 -11
- data/data/parg/iso.json +1 -1
- data/data/parg/iso.parg +142 -2
- data/data/parg/plateau.json +1 -1
- data/data/parg/tables/iec_typed_stages.yaml +3 -0
- data/data/parg/tables/typed_stages_ballots.yaml +6 -0
- data/data/parg/tables/typed_stages_supplements.yaml +1 -0
- data/lib/pubid/bipm/CLAUDE.md +6 -1
- data/lib/pubid/bipm/builder.rb +20 -1
- data/lib/pubid/bipm/renderer.rb +14 -2
- data/lib/pubid/bipm/urn_generator.rb +80 -14
- data/lib/pubid/bipm/urn_parser.rb +70 -6
- data/lib/pubid/ecma/CLAUDE.md +12 -0
- data/lib/pubid/ecma/identifier.rb +1 -2
- data/lib/pubid/ecma/parser.rb +49 -0
- data/lib/pubid/iec/CLAUDE.md +9 -1
- data/lib/pubid/iec/builder.rb +47 -0
- data/lib/pubid/iec/identifier.rb +19 -70
- data/lib/pubid/iec/identifiers/amendment.rb +34 -0
- data/lib/pubid/iec/identifiers/corrigendum.rb +6 -1
- data/lib/pubid/iec/identifiers/fragment_identifier.rb +3 -3
- data/lib/pubid/iec/single_identifier.rb +69 -4
- data/lib/pubid/iec/supplement_identifier.rb +89 -83
- data/lib/pubid/iho/CLAUDE.md +54 -1
- data/lib/pubid/iho/builder.rb +105 -2
- data/lib/pubid/iho/identifiers/base.rb +52 -1
- data/lib/pubid/iho/pubid_urn_schema.rb +12 -4
- data/lib/pubid/iho/renderer.rb +39 -2
- data/lib/pubid/iho/reserved_specs.rb +54 -0
- data/lib/pubid/iho/urn_generator.rb +6 -0
- data/lib/pubid/iho/urn_parser.rb +50 -9
- data/lib/pubid/iho.rb +1 -0
- data/lib/pubid/iso/CLAUDE.md +49 -0
- data/lib/pubid/iso/builder.rb +77 -0
- data/lib/pubid/iso/identifiers/amendment.rb +1 -1
- data/lib/pubid/iso/single_identifier.rb +7 -1
- data/lib/pubid/nist/CLAUDE.md +49 -0
- data/lib/pubid/nist/builder.rb +5 -0
- data/lib/pubid/nist/identifiers/base.rb +42 -1
- data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +44 -5
- data/lib/pubid/nist/preprocessor.rb +18 -0
- data/lib/pubid/nist/urn_parser.rb +1 -1
- data/lib/pubid/plateau/CLAUDE.md +35 -0
- data/lib/pubid/plateau/builder.rb +4 -0
- data/lib/pubid/plateau/identifiers/handbook.rb +10 -2
- data/lib/pubid/plateau/pubid_urn_schema.rb +1 -0
- data/lib/pubid/plateau/renderer.rb +6 -1
- data/lib/pubid/sae/CLAUDE.md +11 -2
- data/lib/pubid/version.rb +1 -1
- metadata +7 -2
data/data/parg/iso.parg
CHANGED
|
@@ -11,6 +11,20 @@
|
|
|
11
11
|
# below, whose captures carry the idf_ prefix so they never collide
|
|
12
12
|
# with the ISO ones and can bind as scalars.
|
|
13
13
|
#
|
|
14
|
+
# Historic TYPE-first ballot faces (decode-to-modern, owner ruling
|
|
15
|
+
# 2026-11-12): the DAM-family token in TYPE position — "ISO/IEC FDAM 1
|
|
16
|
+
# 14496-12:2004", "ISO/PDAM 19973-2" — and the space-attached ballot
|
|
17
|
+
# face "ISO 15877-5:2009 FDAM 1". Both branches sit LAST in the
|
|
18
|
+
# identifier alternation, so they are purely additive: every face an
|
|
19
|
+
# earlier branch parses keeps its exact parse. The ballot token
|
|
20
|
+
# captures as ballot_type_with_stage; a number on the TYPE token is
|
|
21
|
+
# space-bounded (ballot_number) so "PDAM 19973-2" keeps 19973 in the
|
|
22
|
+
# base; an on-base stamp's number/date capture as ballot_stamp_* (the
|
|
23
|
+
# stamp token itself matches uncaptured — the ballot's stage comes
|
|
24
|
+
# from the TYPE token and the decode keeps no spelling). The builder
|
|
25
|
+
# folds the captures into ONE amendment layer over the whole base, the
|
|
26
|
+
# number taken from the TYPE token, the stamp, or the implied 1.
|
|
27
|
+
#
|
|
14
28
|
# Edition 2 with typed model bindings: every capture the builder
|
|
15
29
|
# consumes is bound. Supplement layers capture into position-scoped
|
|
16
30
|
# names (supp_* on the first supplement, supp2_* on the second,
|
|
@@ -23,7 +37,7 @@
|
|
|
23
37
|
|
|
24
38
|
use idf
|
|
25
39
|
|
|
26
|
-
grammar PubidIso version "0.
|
|
40
|
+
grammar PubidIso version "0.5.0" edition 2 {
|
|
27
41
|
|
|
28
42
|
# ---- lexical (pubid/parser/common_parse_rules.rb + ISO override) ----
|
|
29
43
|
digit = %x30-39
|
|
@@ -47,6 +61,7 @@ grammar PubidIso version "0.4.0" edition 2 {
|
|
|
47
61
|
# inline the alt so the capture holds one scalar span) ----
|
|
48
62
|
typed_stage_abbrev = alt from_table "typed_stages" column "abbr"
|
|
49
63
|
supp_stage_abbrev = alt from_table "typed_stages_supplements" column "abbr"
|
|
64
|
+
ballot_stage_abbrev = alt from_table "typed_stages_ballots" column "abbr"
|
|
50
65
|
directives_stage_abbrev = alt from_table "directives_typed_stages" column "abbr"
|
|
51
66
|
directives_supp_stage_abbrev = alt from_table "directives_supplements_typed_stages" column "abbr"
|
|
52
67
|
idf_stage_abbrev = alt from_table "idf_typed_stages" column "abbr"
|
|
@@ -395,6 +410,76 @@ grammar PubidIso version "0.4.0" edition 2 {
|
|
|
395
410
|
)
|
|
396
411
|
}
|
|
397
412
|
|
|
413
|
+
# ---- historic TYPE-first ballot faces (decode-to-modern) ----
|
|
414
|
+
## The DAM-family ballot token in TYPE position. Captured under its
|
|
415
|
+
## own name: the supplement tables' captures stay reserved for the
|
|
416
|
+
## on-base layers, and the ballot's stage is the one the decode keeps.
|
|
417
|
+
ballot_type_with_stage = {
|
|
418
|
+
(
|
|
419
|
+
(alt from_table "typed_stages_ballots" column "abbr")
|
|
420
|
+
) as ballot_type_with_stage
|
|
421
|
+
}
|
|
422
|
+
## An on-base stamp riding a ballot face ("/Amd 9:2001", "/Amd.1",
|
|
423
|
+
## "/Am1:2006"): it carries the amendment's number and ballot date
|
|
424
|
+
## while its own token letters are decode-away (matched uncaptured —
|
|
425
|
+
## the ballot's stage comes from the TYPE token). Mirrors the three
|
|
426
|
+
## supplement tails: a (glued or spaced) number with an optional
|
|
427
|
+
## date, or a dot number.
|
|
428
|
+
ballot_stamp = {
|
|
429
|
+
slash supp_stage_abbrev
|
|
430
|
+
(
|
|
431
|
+
(
|
|
432
|
+
[space]
|
|
433
|
+
((1*5digit)) as ballot_stamp_number
|
|
434
|
+
[
|
|
435
|
+
[space]
|
|
436
|
+
(
|
|
437
|
+
(colon / dash) [
|
|
438
|
+
(("19" / "20") 2*digit !digit [(dash 2*digit)] [(dash 2*digit)]) as ballot_stamp_date
|
|
439
|
+
/ (("--" / "—")) as ballot_stamp_undated_marker
|
|
440
|
+
]
|
|
441
|
+
)
|
|
442
|
+
]
|
|
443
|
+
)
|
|
444
|
+
/ ( dot (1*digit) as ballot_stamp_dot_number )
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
## "ISO/IEC FDAM 1 14496-12:2004", "ISO/PDAM 19973-2": the ballot
|
|
448
|
+
## token first, then the base kept whole. The TYPE-token number is
|
|
449
|
+
## space-bounded on both sides — mandatory trailing space — so
|
|
450
|
+
## "PDAM 19973-2" cannot read 19973 as the ballot number: with no
|
|
451
|
+
## second space the group backtracks and 19973 parses in second_part.
|
|
452
|
+
ballot_supplement_identifier = {
|
|
453
|
+
prefix_with_copublishers
|
|
454
|
+
[space]
|
|
455
|
+
[slash]
|
|
456
|
+
ballot_type_with_stage
|
|
457
|
+
[ space ((1*digit)) as ballot_number space ]
|
|
458
|
+
[space]
|
|
459
|
+
[type_with_stage]
|
|
460
|
+
[space]
|
|
461
|
+
second_part
|
|
462
|
+
[ ballot_stamp ]
|
|
463
|
+
}
|
|
464
|
+
## The space-attached ballot face: "ISO 15877-5:2009 FDAM 1" — the
|
|
465
|
+
## base designation first, then the ballot token attached by a space.
|
|
466
|
+
## The base front is inlined (not supplement_base_no_third): that
|
|
467
|
+
## rule ends in base_third_part_edition, whose own optional space
|
|
468
|
+
## would consume the separator the ballot token needs. No base
|
|
469
|
+
## edition is served here — none of the stored or owner-cited ballot
|
|
470
|
+
## faces carries one.
|
|
471
|
+
ballot_space_supplement_identifier = {
|
|
472
|
+
[ (("Guide" / "GUIDE") as type_with_stage_fr) space ]
|
|
473
|
+
[prefix_with_copublishers]
|
|
474
|
+
[space]
|
|
475
|
+
[slash]
|
|
476
|
+
[type_with_stage]
|
|
477
|
+
[space]
|
|
478
|
+
second_part
|
|
479
|
+
space ballot_type_with_stage
|
|
480
|
+
[ space ((1*digit)) as ballot_number ]
|
|
481
|
+
}
|
|
482
|
+
|
|
398
483
|
# ---- directives: "ISO/IEC DIR 1", "ISO/IEC JTC 1 DIR", supplements,
|
|
399
484
|
# bundled "ISO/IEC DIR 1:2022 + IEC SUP:2022" ----
|
|
400
485
|
directives_publisher_subgroup = ("JTC 1") as subgroup
|
|
@@ -609,7 +694,8 @@ grammar PubidIso version "0.4.0" edition 2 {
|
|
|
609
694
|
}
|
|
610
695
|
|
|
611
696
|
## The ISO identifier root: common-text twin form first, then the
|
|
612
|
-
## single spine.
|
|
697
|
+
## single spine. The historic ballot faces go last — purely additive
|
|
698
|
+
## branches (an input an earlier member parses keeps that parse).
|
|
613
699
|
identifier = {
|
|
614
700
|
bare_tc_document
|
|
615
701
|
/ nsb_iso_identifier
|
|
@@ -623,6 +709,8 @@ grammar PubidIso version "0.4.0" edition 2 {
|
|
|
623
709
|
/ supplement_identifier
|
|
624
710
|
/ joint_identifier
|
|
625
711
|
/ identifier_copublishers
|
|
712
|
+
/ ballot_space_supplement_identifier
|
|
713
|
+
/ ballot_supplement_identifier
|
|
626
714
|
}
|
|
627
715
|
|
|
628
716
|
entry identifier: identifier
|
|
@@ -712,6 +800,12 @@ bs3_undated_marker -> bs3_undated_marker (string)
|
|
|
712
800
|
idf_supp_stage_iteration2 -> idf_supp_stage_iteration2 (string)
|
|
713
801
|
idf_supp_date2 -> idf_supp_date2 (string)
|
|
714
802
|
idf_supp_undated_marker -> idf_supp_undated_marker (string)
|
|
803
|
+
ballot_type_with_stage -> ballot_type_with_stage (string)
|
|
804
|
+
ballot_number -> ballot_number (string)
|
|
805
|
+
ballot_stamp_number -> ballot_stamp_number (string)
|
|
806
|
+
ballot_stamp_dot_number -> ballot_stamp_dot_number (string)
|
|
807
|
+
ballot_stamp_date -> ballot_stamp_date (string)
|
|
808
|
+
ballot_stamp_undated_marker -> ballot_stamp_undated_marker (string)
|
|
715
809
|
}
|
|
716
810
|
|
|
717
811
|
## In-file grammar tests: run at compile time, embedded in the artifact,
|
|
@@ -728,9 +822,55 @@ bs3_undated_marker -> bs3_undated_marker (string)
|
|
|
728
822
|
accept "ISO 5537|IDF 26"
|
|
729
823
|
accept "ISO 4055/Amd 1:2021"
|
|
730
824
|
accept "ISO/R 9:1962"
|
|
825
|
+
accept "ISO/IEC FDAM 1 14496-12:2004"
|
|
826
|
+
accept "ISO/PDAM 19973-2"
|
|
827
|
+
accept "ISO/IEC FPDAM 9075/1"
|
|
828
|
+
accept "ISO/IEC FPDAM 10373-6/Amd 9:2001"
|
|
829
|
+
accept "ISO/PDAM 19110:2005/Amd.1"
|
|
830
|
+
accept "ISO/IEC PDAM TR 9573-11/Amd.1"
|
|
831
|
+
accept "ISO/IEC PDAM 9541-1/Amd.4"
|
|
832
|
+
accept "ISO/IEC PDAM 2 10646:2012"
|
|
833
|
+
accept "ISO 15877-5:2009 FDAM 1"
|
|
834
|
+
accept "ISO 19776-2:2005/Am1:2006"
|
|
731
835
|
reject "nonsense"
|
|
836
|
+
reject "ISO/PDAM"
|
|
837
|
+
reject "ISO/FDAM"
|
|
732
838
|
example "ISO/IEC WD TS 25025" { publisher: "ISO" }
|
|
733
839
|
example "JCGM 200:2008(F)" { publisher: "JCGM" }
|
|
840
|
+
example "ISO/IEC FDAM 1 14496-12:2004" {
|
|
841
|
+
ballot_type_with_stage: "FDAM"
|
|
842
|
+
ballot_number: "1"
|
|
843
|
+
number_with_part: "14496-12"
|
|
844
|
+
date: "2004"
|
|
845
|
+
}
|
|
846
|
+
example "ISO/PDAM 19973-2" {
|
|
847
|
+
ballot_type_with_stage: "PDAM"
|
|
848
|
+
number_with_part: "19973-2"
|
|
849
|
+
}
|
|
850
|
+
example "ISO/IEC FPDAM 10373-6/Amd 9:2001" {
|
|
851
|
+
ballot_type_with_stage: "FPDAM"
|
|
852
|
+
ballot_stamp_number: "9"
|
|
853
|
+
ballot_stamp_date: "2001"
|
|
854
|
+
}
|
|
855
|
+
example "ISO/PDAM 19110:2005/Amd.1" {
|
|
856
|
+
ballot_type_with_stage: "PDAM"
|
|
857
|
+
ballot_stamp_number: "1"
|
|
858
|
+
}
|
|
859
|
+
example "ISO/IEC FPDAM 9075/1" {
|
|
860
|
+
ballot_type_with_stage: "FPDAM"
|
|
861
|
+
number_with_part: "9075/1"
|
|
862
|
+
}
|
|
863
|
+
example "ISO 15877-5:2009 FDAM 1" {
|
|
864
|
+
ballot_type_with_stage: "FDAM"
|
|
865
|
+
ballot_number: "1"
|
|
866
|
+
number_with_part: "15877-5"
|
|
867
|
+
date: "2009"
|
|
868
|
+
}
|
|
869
|
+
example "ISO/IEC FDAM 19776-2:2005/Am1:2006" {
|
|
870
|
+
ballot_type_with_stage: "FDAM"
|
|
871
|
+
ballot_stamp_number: "1"
|
|
872
|
+
ballot_stamp_date: "2006"
|
|
873
|
+
}
|
|
734
874
|
}
|
|
735
875
|
}
|
|
736
876
|
|
data/data/parg/plateau.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"bindings":null,"version":"0.1.0","grammar":"PubidPlateau","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Entity":{"atom":
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidPlateau","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Entity":{"atom":87}},{"Entity":{"atom":67}},{"Str":{"pattern":"PLATEAU"}},{"Str":{"pattern":" "}},{"Entity":{"atom":8}},{"Str":{"pattern":"Handbook"}},{"Str":{"pattern":"Technical Report"}},{"Alternative":{"atoms":[5,6]}},{"Named":{"name":"type","atom":7}},{"Str":{"pattern":" "}},{"Entity":{"atom":15}},{"Str":{"pattern":"#"}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":12,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"number","atom":13}},{"Sequence":{"atoms":[11,14]}},{"Entity":{"atom":23}},{"Str":{"pattern":"-"}},{"Str":{"pattern":"_"}},{"Alternative":{"atoms":[17,18]}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":20,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"annex","atom":21}},{"Sequence":{"atoms":[19,22]}},{"Repetition":{"atom":16,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":47}},{"Str":{"pattern":" "}},{"Entity":{"atom":37}},{"Str":{"pattern":"第"}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":29,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"."}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":32,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[30,31,33]}},{"Named":{"name":"edition","atom":34}},{"Str":{"pattern":"版"}},{"Sequence":{"atoms":[28,35,36]}},{"Entity":{"atom":45}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":39,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"."}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":42,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[40,41,43]}},{"Named":{"name":"edition","atom":44}},{"Alternative":{"atoms":[27,38]}},{"Sequence":{"atoms":[26,46]}},{"Entity":{"atom":63}},{"Entity":{"atom":52}},{"Str":{"pattern":" "}},{"Re":{"pattern":"[\\u3000]"}},{"Alternative":{"atoms":[50,51]}},{"Named":{"name":"volume_sep","atom":49}},{"Str":{"pattern":"本編"}},{"Str":{"pattern":"+"}},{"Str":{"pattern":"+"}},{"Alternative":{"atoms":[55,56]}},{"Str":{"pattern":"付録"}},{"Sequence":{"atoms":[57,58]}},{"Repetition":{"atom":59,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[54,60]}},{"Named":{"name":"volume","atom":61}},{"Sequence":{"atoms":[53,62]}},{"Repetition":{"atom":48,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[25,64]}},{"Repetition":{"atom":65,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[2,3,4,9,10,24,66]}},{"Entity":{"atom":76}},{"Str":{"pattern":"PLATEAU"}},{"Str":{"pattern":" "}},{"Entity":{"atom":8}},{"Str":{"pattern":" "}},{"Entity":{"atom":15}},{"Entity":{"atom":23}},{"Repetition":{"atom":74,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[69,70,71,72,73,75]}},{"Alternative":{"atoms":[1,68]}},{"Named":{"name":"base","atom":77}},{"Entity":{"atom":86}},{"Str":{"pattern":" "}},{"Str":{"pattern":"Annex"}},{"Str":{"pattern":" "}},{"Entity":{"atom":85}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Named":{"name":"annex_letter","atom":84}},{"Sequence":{"atoms":[80,81,82,83]}},{"Sequence":{"atoms":[78,79]}},{"Entity":{"atom":67}},{"Entity":{"atom":76}},{"Alternative":{"atoms":[0,88,89]}}],"root":90},"bindings":[{"capture":"base","path":"base","type":"raw","card":null,"preprocess":null},{"capture":"type","path":"type","type":"string","card":null,"preprocess":null},{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"annex","path":"annex","type":"string","card":null,"preprocess":null},{"capture":"edition","path":"edition","type":"string","card":null,"preprocess":null},{"capture":"volume","path":"volume","type":"string","card":null,"preprocess":null},{"capture":"annex_letter","path":"annex_letter","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule identifier: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule identifier: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule identifier: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"PLATEAU Handbook #3","expect":{}},{"entry":"identifier","kind":"accept","input":"PLATEAU Technical Report #1","expect":{}},{"entry":"identifier","kind":"accept","input":"PLATEAU Handbook #00 第5.0版 本編","expect":{}},{"entry":"identifier","kind":"accept","input":"PLATEAU Handbook #00 第5.0版 本編+付録","expect":{}},{"entry":"identifier","kind":"accept","input":"PLATEAU Handbook #00 第5.0版 本編+付録","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}}],"docs":{},"source":"# Port of lib/pubid/plateau/parser.rb: PLATEAU Handbook/Technical Report\n# #NN[-annex][ edition], plus Annex supplements. Japanese canonical\n# edition (第X.Y版) and legacy Latin X.Y both capture the same atom.\n#\n# Edition 2: every reference inside a captured body is inlined to raw\n# terms (a rule reference materializes as a named node in the edition-2\n# tree, so only a raw capture binds a scalar span). The base wrapper\n# keeps the v1 tree shape and the bindings name the scalar leaves.\n\ngrammar PubidPlateau version \"0.1.0\" edition 2 {\n doc_type = (\"Handbook\" / \"Technical Report\") as type\n number = \"#\" (1*%x30-39) as number\n annex = (\"-\" / \"_\") (1*%x30-39) as annex\n edition_part = \"第\" (1*%x30-39 \".\" 1*%x30-39) as edition \"版\"\n edition_latin = (1*%x30-39 \".\" 1*%x30-39) as edition\n edition = \" \" (edition_part / edition_latin)\n # MLIT's volume label after the edition: 本編 (main volume) or 本編+付録\n # (main volume with appendix). ASCII or full-width (U+3000) space; ASCII\n # \"+\" or full-width \"+\" (U+FF0B), which the builder normalizes to \"+\".\n volume_sep = \" \" / %x3000\n volume = volume_sep (\"本編\" [(\"+\" / \"+\") \"付録\"]) as volume\n annex_letter = (%x41-5A) as annex_letter\n annex_supplement = \" \" \"Annex\" \" \" annex_letter\n handbook = \"PLATEAU\" \" \" doc_type \" \" number [annex] [edition [volume]]\n technical_report = \"PLATEAU\" \" \" doc_type \" \" number [annex]\n annex_identifier = (handbook / technical_report) as base annex_supplement\n identifier = annex_identifier / handbook / technical_report\n\n entry identifier: identifier\n\n test {\n accept \"PLATEAU Handbook #3\"\n accept \"PLATEAU Technical Report #1\"\n accept \"PLATEAU Handbook #00 第5.0版 本編\"\n accept \"PLATEAU Handbook #00 第5.0版 本編+付録\"\n accept \"PLATEAU Handbook #00 第5.0版 本編+付録\"\n reject \"nonsense\"\n }\n\n bindings identifier {\n # The builder dispatches on base && annex_letter and RE-parses the base\n # subtree recursively (build_annex calls build(parsed[:base])), so base\n # binds uncast — the nested {type, number, annex, edition} hash.\n base -> base (raw)\n type -> type (string)\n number -> number (string)\n annex -> annex (string)\n edition -> edition (string)\n volume -> volume (string)\n annex_letter -> annex_letter (string)\n }\n}\n","source_hash":"f5a43fb4d638687462490f2b05b635501ac21375c917b10e28f2cad554985476","unicode_tables":"onigmo (Ruby 3.4.10)","compiler_version":"1.3.114","edition":2,"checksum":"sha256:e876e3871cd842ded4df7a9ad906a428fbf11ab466631f489f555dd9508bef8a"}
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
- abbr: "ANW Amd"
|
|
5
5
|
- abbr: "WD Amd"
|
|
6
6
|
- abbr: "CDAM"
|
|
7
|
+
- abbr: "PDAM"
|
|
7
8
|
- abbr: "DAM"
|
|
8
9
|
- abbr: "FDAM"
|
|
10
|
+
- abbr: "FPDAM"
|
|
9
11
|
- abbr: "PRF Amd"
|
|
10
12
|
- abbr: "Amd"
|
|
11
13
|
- abbr: "AMD"
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
- abbr: "ANW Cor"
|
|
15
17
|
- abbr: "WDCor"
|
|
16
18
|
- abbr: "CDCor"
|
|
19
|
+
- abbr: "CDCOR"
|
|
17
20
|
- abbr: "DCOR"
|
|
18
21
|
- abbr: "FDCOR"
|
|
19
22
|
- abbr: "PRF Cor"
|
data/lib/pubid/bipm/CLAUDE.md
CHANGED
|
@@ -12,7 +12,12 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
|
|
|
12
12
|
|
|
13
13
|
- **Routing reaches BIPM (`Pubid.parse`, pubid#644)**: the note above says "`Pubid.parse` auto-routing does not resolve **any** BIPM form today … so `PREFIXES` was left alone" — that is no longer true, in two halves. **(1) `PREFIXES` gained the two SI-family series tokens** `SI Brochure` and `SI MEP`: both lead real printed references on their own (`SI Brochure 9e v3.01 (2019/2024, E)` — the spelling relaton's `Bibliography#search` strips the `BIPM ` off, per the note above — and `SI MEP 10`), and before this both parsed **directly** but the router could not route them (no prefix owner ⇒ no non-exact fallback). "Rapport" stays excluded per the ambiguous-token policy (generic French word). **(2) The quoted-title form** `BIPM "The International System of Units"` — the brochure IS titled that — is mapped onto the parseable `BIPM SI Brochure` section form by **`data/bipm/update_codes.yaml`** (the CIPM-MRA precedent), so it parses as a **partial reference** that wildcards every edition, exactly like `SI Brochure Part 1`; the bare `"The International System of Units"` maps to `SI Brochure`. Both are normalizing parses and live with the loose-forms expectations, never in the byte-exact fixtures. The **French title is deliberately not mapped**: it names the F-language record specifically, and mapping it would silently drop typed language information (the loose-forms rule above). Also note the router's prefix-owner mechanism is what makes the normalizing parses routable: `Pubid::Bipm.parse("BIPM SI Brochure")` happens to round-trip exactly, but `SI Brochure 9e …` renders with the leading `BIPM ` the input lacked — without prefix-owner status the router would reject it. (hand-off: router-printed-forms-644.)
|
|
14
14
|
|
|
15
|
-
- **Corpus-cited forms + guide printings (pubid#657)**: the metanorma-bipm fetch queue cites two spellings the grammar rejected, and the 2026-11 guide update adds printings of its own. All are **parse-in forms over the existing canonical identities** — the canonical render follows the guide, nothing that already parsed changed. **(1) The em-dash meeting variant** `CGPM -- Meeting 1 (1889)`: `meeting_en` gained `<group> -- Meeting <n>` and `<group> -- <n><ord> Meeting` branches (the corpus cites only the first; the second is the same reordering over the other word order). They build through the existing `Meeting` path, so the canonical render is `CGPM 1st Meeting (1889)`. **(2) The publisher-prefixed decision** `BIPM DECN CIPM/101-1 (2012, EN)` (and `, FR`): new `committee_prefixed` rule — a **literal `BIPM`** lead (the constant publisher, deliberately NOT the `group` table, which contains BIPM and would collide with the second `group` capture), `type_abbrev`, then the body-qualified id `{group}/{number}`. Builds through `build_committee` short-form, so it equals `CIPM DECN 101-1 (2012, E)` — verified against real `index-v2` rows in `loose_consumer_forms_spec` (the corpus's citeas comes out as the BIPM-long style, which is the consumer's rendering choice, not pubid's). **(3) The guide's French body-prefixed long form** `Décision CIPM/111-10 (2022)` / `Recommandation JCRB/43-1 (2021)`: an alternative inside `committee_long_fr` (same capture name, so the same builder path — long form, language F). **The canonical French long form stays the connective spelling** (`Décision 101-1 du CIPM (2012)`) even though the guide's language-independent example prefers the body-prefixed one — the corpus freezes the connective render for what already parsed, and flipping the canonical would move frozen cases; that flip is an owner decision if the guide is adopted wholesale. **(4) SI Brochure guide forms**: the language code and the version are now OPTIONAL (`SI Brochure 9e v3.01 (2019/2024)` language-independent, `SI Brochure 9e (2019, E)` version-less — both byte round-trips with the canonical `BIPM SI Brochure ` lead), and the guide's French lead `Brochure sur le SI 9e …` parses as an alias of the `BIPM SI Brochure sur le SI …` canonical (note the lead alternation is `"BIPM SI Brochure" / "SI Brochure" / "Brochure sur le SI"` with the `["sur le SI" space]` phrase still optional after the first two — it just fails cleanly after the third). **(5) The corpus-cited ordinal-edition spelling** `SI Brochure 9th edition (2019)`: its own `si_brochure_ordinal_edition` rule (a separate branch, because the `edition` capture would otherwise bind `"9th"`); the builder strips the ordinal and appends `e`, so it normalizes onto `BIPM SI Brochure 9e (2019)`. **(6) Part numbers** (the guide's resource-specific-id numbering, `partnumbers` proposal, bipm-si-brochure#301): parts/subparts are dash forms inside `number` (`CIPM DECN 111-10-2`) and always parsed; the appendix/annex complement `CIPM DECN 112 A3[.5]` is the new optional ` A<n>[.<m>]` tail on `committee_short`, stored in the shared `appendix`/`annex` attributes (the MEP/guide tail's home), printed back byte-exactly by `appendix_segment`, folded into the URN identifier segment as `-a<n>[.<m>]` (`urn:bipm:cipm:decn:112-a3.5:2022` — unambiguous, because a bare number never carries letters; `UrnParser#split_appendix` splits it back), and joined into the MR number segment (`mr_slug` collapses the annex dot). It requires a number before it (`CIPM DECN A3` still fails). **URN deviations from the guide, deliberate**: the guide's own committee-example URNs (`urn:bipm:v1:cipm:resolution:95-2006:1`) carry a `v1` version segment and venue-qualified shapes the flavor's URNs never adopted (`urn:bipm:cipm:res:101-1:2012`, no `v1`, no venue segments — green for years, kept byte-identical); the new forms emit URNs under the EXISTING shape for the same reason, and the same applies to the brochure (`urn:bipm:si-brochure:<lang>:<edition>:<version>:<years>` vs the guide's `urn:bipm:v1:bipm:si-brochure:9:3.01:2024` — the guide strips the `e`/`v` and drops the language segment; adopting that is an index-affecting owner decision, not taken here). **One Ruby trap the URN fold exposed**: `id.number.to_s` on a String **attribute** returns the attribute itself, so building the folded segment by `<<` mutated `number` in place — every later `to_s`/`to_hash` of the same object then carried `-a3`; the fold is now interpolation, and `urn_spec` pins that a URN emission leaves `number` untouched. **The unmerged `si-brochure-id` proposal** (`SI Brochure 9`, `SI Brochure 9 (E)`, `SI Brochure 9 (2024) (F)` — bare-number edition) is NOT implemented: it conflicts with the merged guide's `9e` spelling. (hand-off: bipm-657-corpus-forms.)
|
|
15
|
+
- **Corpus-cited forms + guide printings (pubid#657)**: the metanorma-bipm fetch queue cites two spellings the grammar rejected, and the 2026-11 guide update adds printings of its own. All are **parse-in forms over the existing canonical identities** — the canonical render follows the guide, nothing that already parsed changed. **(1) The em-dash meeting variant** `CGPM -- Meeting 1 (1889)`: `meeting_en` gained `<group> -- Meeting <n>` and `<group> -- <n><ord> Meeting` branches (the corpus cites only the first; the second is the same reordering over the other word order). They build through the existing `Meeting` path, so the canonical render is `CGPM 1st Meeting (1889)`. **(2) The publisher-prefixed decision** `BIPM DECN CIPM/101-1 (2012, EN)` (and `, FR`): new `committee_prefixed` rule — a **literal `BIPM`** lead (the constant publisher, deliberately NOT the `group` table, which contains BIPM and would collide with the second `group` capture), `type_abbrev`, then the body-qualified id `{group}/{number}`. Builds through `build_committee` short-form, so it equals `CIPM DECN 101-1 (2012, E)` — verified against real `index-v2` rows in `loose_consumer_forms_spec` (the corpus's citeas comes out as the BIPM-long style, which is the consumer's rendering choice, not pubid's). **(3) The guide's French body-prefixed long form** `Décision CIPM/111-10 (2022)` / `Recommandation JCRB/43-1 (2021)`: an alternative inside `committee_long_fr` (same capture name, so the same builder path — long form, language F). **The canonical French long form stays the connective spelling** (`Décision 101-1 du CIPM (2012)`) even though the guide's language-independent example prefers the body-prefixed one — the corpus freezes the connective render for what already parsed, and flipping the canonical would move frozen cases; that flip is an owner decision if the guide is adopted wholesale. **(4) SI Brochure guide forms**: the language code and the version are now OPTIONAL (`SI Brochure 9e v3.01 (2019/2024)` language-independent, `SI Brochure 9e (2019, E)` version-less — both byte round-trips with the canonical `BIPM SI Brochure ` lead), and the guide's French lead `Brochure sur le SI 9e …` parses as an alias of the `BIPM SI Brochure sur le SI …` canonical (note the lead alternation is `"BIPM SI Brochure" / "SI Brochure" / "Brochure sur le SI"` with the `["sur le SI" space]` phrase still optional after the first two — it just fails cleanly after the third). **(5) The corpus-cited ordinal-edition spelling** `SI Brochure 9th edition (2019)`: its own `si_brochure_ordinal_edition` rule (a separate branch, because the `edition` capture would otherwise bind `"9th"`); the builder strips the ordinal and appends `e`, so it normalizes onto `BIPM SI Brochure 9e (2019)`. **(6) Part numbers** (the guide's resource-specific-id numbering, `partnumbers` proposal, bipm-si-brochure#301): parts/subparts are dash forms inside `number` (`CIPM DECN 111-10-2`) and always parsed; the appendix/annex complement `CIPM DECN 112 A3[.5]` is the new optional ` A<n>[.<m>]` tail on `committee_short`, stored in the shared `appendix`/`annex` attributes (the MEP/guide tail's home), printed back byte-exactly by `appendix_segment`, folded into the URN identifier segment as `-a<n>[.<m>]` (`urn:bipm:cipm:decn:112-a3.5:2022` — unambiguous, because a bare number never carries letters; `UrnParser#split_appendix` splits it back), and joined into the MR number segment (`mr_slug` collapses the annex dot). It requires a number before it (`CIPM DECN A3` still fails). **URN deviations from the guide, deliberate**: the guide's own committee-example URNs (`urn:bipm:v1:cipm:resolution:95-2006:1`) carry a `v1` version segment and venue-qualified shapes the flavor's URNs never adopted (`urn:bipm:cipm:res:101-1:2012`, no `v1`, no venue segments — green for years, kept byte-identical); the new forms emit URNs under the EXISTING shape for the same reason, and the same applies to the brochure (`urn:bipm:si-brochure:<lang>:<edition>:<version>:<years>` vs the guide's `urn:bipm:v1:bipm:si-brochure:9:3.01:2024` — the guide strips the `e`/`v` and drops the language segment; adopting that is an index-affecting owner decision, not taken here). *(Both halves superseded by the 2026-11-11 official-URN ruling, below.)* **One Ruby trap the URN fold exposed**: `id.number.to_s` on a String **attribute** returns the attribute itself, so building the folded segment by `<<` mutated `number` in place — every later `to_s`/`to_hash` of the same object then carried `-a3`; the fold is now interpolation, and `urn_spec` pins that a URN emission leaves `number` untouched. **The unmerged `si-brochure-id` proposal** (`SI Brochure 9`, `SI Brochure 9 (E)`, `SI Brochure 9 (2024) (F)` — bare-number edition) is NOT implemented: it conflicts with the merged guide's `9e` spelling. *(Superseded — adopted as parse-in aliases by the 2026-11-11 ruling, below.)* (hand-off: bipm-657-corpus-forms.)
|
|
16
|
+
|
|
17
|
+
- **The three 2026-11-11 owner rulings (official URNs, bare-number brochure editions, French-long flip)**: the owner ratified the guide-of-record wholesale, moving the official `urn:bipm:` face for the first time (a relaton-data-bipm re-crawl follows, accepted) and flipping one canonical render.
|
|
18
|
+
**(R1 — the `si-brochure-id` proposal adopted as parse-in aliases.** `SI Brochure 9`, `SI Brochure 9 (E)` and `SI Brochure 9 (2024) (F)` now parse, via the `si_brochure_bare_edition` grammar rule (the `si_brochure_ordinal_edition` model: a separate branch because the `edition` capture would bind the bare digit without the canonical `e`; the year and the language may each sit in their own parentheses, exactly the proposal's spellings). The builder appends the `e` — `9` → `9e`, the same normalization the ordinal spelling takes — so all three land on `BIPM SI Brochure 9e …`. **Two grammar/render consequences worth recording**: the canonical render of a year-less alias (`BIPM SI Brochure 9e`) must re-parse, so the brochure parenthetical is now OPTIONAL and accepts a **language-only paren** (`(E)` with no year — the main `si_brochure` rule's second alternative); and the renderer's paren segment had to stop printing unconditionally, because a nil `years` beside a language rendered the garbage `(, E)` — a live bug the year-less ordinal spelling already had on main (`SI Brochure 9th edition` → `BIPM SI Brochure 9e ()`). The paren now carries the year, the language or both, and stays off entirely when neither is named. Alias expectations live ONLY in `loose_consumer_forms_spec` (the ruling restates the normalizing-parses-never-in-pass rule); the three canonical faces gained byte-exact fixture lines.
|
|
19
|
+
**(R2 — the guide's official-URN shapes adopted.** Every `to_urn` now emits the `v1` face: committee `urn:bipm:v1:{group}:{type-word}:{identifier}[:{year}]` (the guide's `urn:bipm:v1:cipm:decision:110-17:2021` verbatim; the type segment is the lowercase ENGLISH NAME — recommendation/resolution/decision/action/statement — never the REC/RES/DECN abbreviation), meeting `urn:bipm:v1:{group}:meeting:{n}[:{year}]` (venue-type + venue-id as separate segments per the guide's component list; the proceedings example glues them as `meeting-26` and carries a publication year the flavor does not model), metrologia unchanged-shape-plus-`v1` (the guide's metrologia URN section is empty — as are MEP/Guide, which still raise: no landed URN, nothing to move), brochure `urn:bipm:v1:bipm:si-brochure:{edition-no-e}:{version-no-v}:{latest-year}` (the guide's pattern verbatim: language segment dropped, `9e`→`9`, `v3.01`→`3.01`, `2019/2024`→`2024` — the guide's "latest year of publication at the version"; the version segment stays empty when absent, per the guide's `…si-brochure:9::2019`). **Two guide examples do not fit the guide's own stated pattern** and are documented, not reproduced: `urn:bipm:v1:cipm:resolution:95-2006:1` puts a venue-id and the outcome ordinal where the pattern's identifier/date slots sit (its own git history edited it there from `95-2006:resolution:1`, which fit), and `urn:bipm:v1:cgpm:26:2018:resolution:1` carries the CGPM meeting number in a venue-id slot the flavor has no attribute for — the venue qualification this flavor holds lives inside the document number (`110-17`), so CGPM resolutions emit `urn:bipm:v1:cgpm:resolution:1:2018`. **The legacy faces stay parseable as documented parse-in aliases** (`UrnParser` branches on the leading `v1`): `urn:bipm:cipm:res:101-1:2012`, `urn:bipm:si-brochure:e:9e:v3.01:2019/2024`, `urn:bipm:metrologia:51:1:128`, `urn:bipm:cgpm:meeting:17:1983` and the empty-segment forms all rebuild the same identity whose `to_urn` is now the v1 face — no stored row or consumer-held URN stops resolving while the crawl lags; the emitter never produces them. The brochure alias parser also tightened two segments through `presence` (the legacy face's empty edition/version/years segments now read nil, matching what `to_hash` stores). The **pubid-scheme URN (`urn:pubid:bipm:…`) is untouched** — schema, atoms and emission byte-identical (0-diff verified).
|
|
20
|
+
**(R3 — the French-long canonical flipped to the guide's body-prefixed form.** `render_committee_long`'s F branch now prints `{name} {group}/{number} (year)` — `Décision CIPM/111-10 (2022)` — for every group, wholesale (the owner overrode the guide's own mixed pattern, which keeps the connective for CGPM resolutions). A **number-less** document has no id to qualify, so it keeps the connective spelling (`Statement de la CGPM (1889)`) — the guide's general French pattern. The connective spellings (`Décision 101-1 du CIPM (2012)`) and the group-leading word order (`CIPM Décision 101-1 (2012)`) are now normalizing aliases onto the same identity; `language: "F"` semantics unchanged. **Six byte-exact fixture lines moved** to the new canonical (recorded in the PR): the four CCL/CGPM/JCRB/CIPM connective lines became their body-prefixed spellings, the two that would have duplicated existing lines were replaced (one by the guide's own `Décision CIPM/111-10 (2022)` example, one dropped as now-identical), and the partial `Recommandation 1 du CCL` became `Recommandation CCL/1`. `to_hash` is unchanged by all three rulings — the flips are render/emitter faces only; verified by a full corpus replay (0 `to_hash` diffs, `to_pubid_urn` 0-diff).
|
|
16
21
|
|
|
17
22
|
## pubid-scheme URN (issue #670)
|
|
18
23
|
|
data/lib/pubid/bipm/builder.rb
CHANGED
|
@@ -39,6 +39,8 @@ module Pubid
|
|
|
39
39
|
build_si_brochure_section(data[:si_brochure_section])
|
|
40
40
|
elsif data.key?(:si_brochure_ordinal_edition)
|
|
41
41
|
build_si_brochure_ordinal_edition(data[:si_brochure_ordinal_edition])
|
|
42
|
+
elsif data.key?(:si_brochure_bare_edition)
|
|
43
|
+
build_si_brochure_bare_edition(data[:si_brochure_bare_edition])
|
|
42
44
|
elsif data[:mep]
|
|
43
45
|
build_mep(data[:mep])
|
|
44
46
|
elsif data[:guide]
|
|
@@ -119,7 +121,7 @@ module Pubid
|
|
|
119
121
|
number: node[:edition].to_s,
|
|
120
122
|
edition: node[:edition].to_s,
|
|
121
123
|
version: node[:version]&.to_s,
|
|
122
|
-
years: node[:years]
|
|
124
|
+
years: node[:years]&.to_s,
|
|
123
125
|
language: Identifier.normalize_language(node[:language]),
|
|
124
126
|
)
|
|
125
127
|
end
|
|
@@ -153,6 +155,23 @@ module Pubid
|
|
|
153
155
|
)
|
|
154
156
|
end
|
|
155
157
|
|
|
158
|
+
# The unmerged si-brochure-id proposal spells the edition as a bare
|
|
159
|
+
# number ("SI Brochure 9 (2024) (F)"); the guide's canonical edition
|
|
160
|
+
# carries the trailing "e", so the bare number normalizes onto it the
|
|
161
|
+
# same way the corpus-cited ordinal spelling does. The proposal puts the
|
|
162
|
+
# year and the language in separate parentheses; they map onto the same
|
|
163
|
+
# attributes the canonical form prints, and an absent year stays nil (a
|
|
164
|
+
# partial reference, like "SI Brochure 9th edition" without a year).
|
|
165
|
+
def build_si_brochure_bare_edition(node)
|
|
166
|
+
edition = "#{node[:bare_edition]}e"
|
|
167
|
+
Identifiers::SiBrochure.new(
|
|
168
|
+
number: edition,
|
|
169
|
+
edition: edition,
|
|
170
|
+
years: node[:year]&.to_s,
|
|
171
|
+
language: Identifier.normalize_language(node[:language]),
|
|
172
|
+
)
|
|
173
|
+
end
|
|
174
|
+
|
|
156
175
|
# The Appendix/Annex/Part tail is the full-content spelling of the SAME
|
|
157
176
|
# document, so it stays out of the key.
|
|
158
177
|
def build_mep(node)
|
data/lib/pubid/bipm/renderer.rb
CHANGED
|
@@ -57,6 +57,15 @@ module Pubid
|
|
|
57
57
|
def render_committee_long(id)
|
|
58
58
|
if id.language == "F"
|
|
59
59
|
name = Identifier::TYPE_NAME_FR[id.type_code]
|
|
60
|
+
# The guide's body-prefixed French pattern ("Décision CIPM/111-10
|
|
61
|
+
# (2022)") is the canonical long face: the group qualifies the
|
|
62
|
+
# resource-specific id with a slash. A number-less document has no
|
|
63
|
+
# id to qualify, so it keeps the connective spelling the guide's
|
|
64
|
+
# general French pattern uses ("Statement de la CGPM (1889)").
|
|
65
|
+
if id.number
|
|
66
|
+
return "#{name} #{id.group}/#{id.number}#{year_segment(id)}"
|
|
67
|
+
end
|
|
68
|
+
|
|
60
69
|
conn = Identifier.french_connective(id.group)
|
|
61
70
|
"#{name}#{number_segment(id)} #{conn} #{id.group}#{year_segment(id)}"
|
|
62
71
|
else
|
|
@@ -91,12 +100,15 @@ module Pubid
|
|
|
91
100
|
|
|
92
101
|
# The version is optional (the guide's "SI Brochure 9e (2019, E)" form)
|
|
93
102
|
# and the language code too (the language-independent form), so both
|
|
94
|
-
# segments are conditional.
|
|
103
|
+
# segments are conditional. The parens carry the year, the language or
|
|
104
|
+
# both, and stay off entirely when the reference names neither ("SI
|
|
105
|
+
# Brochure 9e", the bare-number alias without a year).
|
|
95
106
|
phrase = id.language == "F" ? "sur le SI " : ""
|
|
96
107
|
lang = id.language ? ", #{id.language}" : ""
|
|
108
|
+
tail = id.years ? "#{id.years}#{lang}" : id.language.to_s
|
|
97
109
|
result = +"BIPM SI Brochure #{phrase}#{id.edition}"
|
|
98
110
|
result << " #{id.version}" if id.version
|
|
99
|
-
result << " (#{id.years
|
|
111
|
+
result << " (#{tail})" if id.years || id.language
|
|
100
112
|
result
|
|
101
113
|
end
|
|
102
114
|
|
|
@@ -3,12 +3,50 @@
|
|
|
3
3
|
module Pubid
|
|
4
4
|
module Bipm
|
|
5
5
|
# Emits a URN carrying the canonical (language/form-neutral) document
|
|
6
|
-
# identity for each family
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
6
|
+
# identity for each family, in the guide-of-record's official shapes
|
|
7
|
+
# (bipm-editor-guides, sources/bipm-references-en.adoc, "URN" clauses):
|
|
8
|
+
#
|
|
9
|
+
# committee: urn:bipm:v1:<group>:<type-word>:<identifier>[:<year>]
|
|
10
|
+
# meeting: urn:bipm:v1:<group>:meeting:<number>[:<year>]
|
|
11
|
+
# metrologia: urn:bipm:v1:metrologia:<vol>[:<issue>[:<article>]]
|
|
12
|
+
# brochure: urn:bipm:v1:bipm:si-brochure:<edition>:[<version>]:<year>
|
|
13
|
+
#
|
|
14
|
+
# The guide's general pattern is
|
|
15
|
+
# `urn:bipm:{version}:{group}:{venue-type}:{venue-id}
|
|
16
|
+
# :{type}:{identifier}:{date}` with the venue slots optional. The
|
|
17
|
+
# flavor holds no venue attribute — the venue qualification lives
|
|
18
|
+
# inside the document number itself ("110-17" is the 110th meeting's
|
|
19
|
+
# decision 17) — so the venue slots stay unfilled and one shape per
|
|
20
|
+
# family falls out:
|
|
21
|
+
#
|
|
22
|
+
# * committee — the guide's `decision` example verbatim:
|
|
23
|
+
# `urn:bipm:v1:cipm:decision:110-17:2021`. The type segment is the
|
|
24
|
+
# English type name lowercased (resolution/recommendation/decision/
|
|
25
|
+
# action/statement), not the REC/RES/DECN abbreviation the previous
|
|
26
|
+
# face carried; the empty segment stays for the type-less bare MRA
|
|
27
|
+
# form. The guide's second committee example
|
|
28
|
+
# (`urn:bipm:v1:cipm:resolution:95-2006:1`) does not fit the stated
|
|
29
|
+
# pattern — it puts a venue-id (meeting 95, year 2006) and the
|
|
30
|
+
# outcome ordinal where the pattern's identifier/date slots sit
|
|
31
|
+
# (its own git history edited it there from `95-2006:resolution:1`,
|
|
32
|
+
# which DID fit). This flavor emits the pattern-conforming shape;
|
|
33
|
+
# a venue-qualified number flows through the identifier slot
|
|
34
|
+
# verbatim.
|
|
35
|
+
# * meeting — the venue-type `meeting` plus the venue-id, as separate
|
|
36
|
+
# segments per the guide's meeting-outcomes component list (its only
|
|
37
|
+
# accepted venue-type value). The guide's proceedings example glues
|
|
38
|
+
# them (`meeting-26`) and carries a proceedings type + publication
|
|
39
|
+
# year this flavor does not model.
|
|
40
|
+
# * metrologia — the guide defines no metrologia URN (its section is
|
|
41
|
+
# empty), so only the mandatory `v1` convention applies; the series
|
|
42
|
+
# shape is unchanged.
|
|
43
|
+
# * brochure — the guide's pattern verbatim: the `bipm` group lead,
|
|
44
|
+
# the edition without its `e` ("9e" → "9"), the version without its
|
|
45
|
+
# `v` ("v3.01" → "3.01"), the language segment dropped (the guide's
|
|
46
|
+
# URN is language-independent) and the year the latest the `years`
|
|
47
|
+
# range names ("2019/2024" → "2024", the guide's "latest year of
|
|
48
|
+
# publication at the version"). The version segment stays empty when
|
|
49
|
+
# absent, per the guide's `urn:bipm:v1:bipm:si-brochure:9::2019`.
|
|
12
50
|
class UrnGenerator < Pubid::UrnGenerator::Base
|
|
13
51
|
def generate
|
|
14
52
|
case identifier
|
|
@@ -23,18 +61,29 @@ module Pubid
|
|
|
23
61
|
|
|
24
62
|
private
|
|
25
63
|
|
|
64
|
+
# The v1 version segment leads every family; the venue-type/venue-id
|
|
65
|
+
# slots of the guide's general pattern stay unfilled because the
|
|
66
|
+
# flavor carries no venue attribute (see the class comment).
|
|
26
67
|
def committee
|
|
27
68
|
id = identifier
|
|
28
|
-
# type_code is nil for the bare MRA form → empty type segment,
|
|
29
|
-
# the empty-number-segment convention for number-less
|
|
30
|
-
|
|
31
|
-
|
|
69
|
+
# type_code is nil for the bare MRA form → empty type segment,
|
|
70
|
+
# mirroring the empty-number-segment convention for number-less
|
|
71
|
+
# documents. The segment is the lowercase English type name the
|
|
72
|
+
# guide spells out ("decision"), never the REC/RES/DECN code.
|
|
73
|
+
parts = ["urn", "bipm", "v1", id.group.downcase,
|
|
74
|
+
committee_type_segment(id), committee_number_segment(id)]
|
|
32
75
|
# A partial (date-less) reference drops the trailing year segment; a
|
|
33
76
|
# number-less-but-dated doc keeps its empty number segment.
|
|
34
77
|
parts << id.year if id.year
|
|
35
78
|
parts.join(":")
|
|
36
79
|
end
|
|
37
80
|
|
|
81
|
+
def committee_type_segment(id)
|
|
82
|
+
return "" unless id.type_code
|
|
83
|
+
|
|
84
|
+
Identifier::TYPE_NAME_EN[id.type_code].downcase
|
|
85
|
+
end
|
|
86
|
+
|
|
38
87
|
# The appendix/annex complement folds into the identifier segment as
|
|
39
88
|
# "-a{appendix}[.{annex}]". A bare number is digits and dashes only, so
|
|
40
89
|
# the letter-prefixed tail is unambiguous on the way back (UrnParser
|
|
@@ -50,21 +99,38 @@ module Pubid
|
|
|
50
99
|
|
|
51
100
|
def meeting
|
|
52
101
|
id = identifier
|
|
53
|
-
parts = ["urn", "bipm", id.group.downcase, "meeting",
|
|
102
|
+
parts = ["urn", "bipm", "v1", id.group.downcase, "meeting",
|
|
103
|
+
id.number.to_s]
|
|
54
104
|
parts << id.year if id.year
|
|
55
105
|
parts.join(":")
|
|
56
106
|
end
|
|
57
107
|
|
|
58
108
|
def metrologia
|
|
59
|
-
parts = ["urn", "bipm", "metrologia", identifier.volume]
|
|
109
|
+
parts = ["urn", "bipm", "v1", "metrologia", identifier.volume]
|
|
60
110
|
parts << identifier.issue if identifier.issue
|
|
61
111
|
parts << identifier.article if identifier.article
|
|
62
112
|
parts.join(":")
|
|
63
113
|
end
|
|
64
114
|
|
|
65
115
|
def si_brochure
|
|
66
|
-
|
|
67
|
-
|
|
116
|
+
id = identifier
|
|
117
|
+
["urn", "bipm", "v1", "bipm", "si-brochure",
|
|
118
|
+
brochure_edition_segment(id), id.version.to_s.delete_prefix("v"),
|
|
119
|
+
brochure_year_segment(id)].join(":")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# The guide's edition-number carries no "e" ("Notice the absence of the
|
|
123
|
+
# letter e after the number"): "9e" emits "9". A variant (Appendix 3 /
|
|
124
|
+
# Concise / FAQ) or a bare section reference names no edition, so the
|
|
125
|
+
# segment is empty — the documented partial-reference bucket.
|
|
126
|
+
def brochure_edition_segment(id)
|
|
127
|
+
id.edition.to_s.delete_suffix("e")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# The guide's year is "the latest year of publication at the version":
|
|
131
|
+
# the "2019" of "2019", the "2024" of "2019/2024".
|
|
132
|
+
def brochure_year_segment(id)
|
|
133
|
+
id.years.to_s.split("/").last
|
|
68
134
|
end
|
|
69
135
|
end
|
|
70
136
|
end
|