pubid 2.0.0.pre.alpha.11 → 2.0.0.pre.alpha.12
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/lib/pubid/bsi/components/date.rb +10 -4
- data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -1
- data/lib/pubid/bsi/identifiers/handbook.rb +1 -1
- data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -1
- data/lib/pubid/bsi/single_identifier.rb +11 -2
- data/lib/pubid/ccsds/identifier.rb +4 -0
- data/lib/pubid/ccsds/single_identifier.rb +14 -10
- data/lib/pubid/csa/builder.rb +3 -3
- data/lib/pubid/csa/identifiers/bundled.rb +2 -2
- data/lib/pubid/csa/identifiers/cec.rb +1 -1
- data/lib/pubid/csa/single_identifier.rb +1 -1
- data/lib/pubid/csa/urn_generator.rb +1 -1
- data/lib/pubid/evs/builder.rb +1 -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/builder.rb +14 -9
- data/lib/pubid/gb/identifier.rb +23 -4
- data/lib/pubid/gb/parser.rb +4 -0
- data/lib/pubid/gb/renderer.rb +4 -3
- data/lib/pubid/gb.rb +1 -0
- data/lib/pubid/identifier.rb +11 -3
- data/lib/pubid/idf/identifier.rb +7 -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/single_identifier.rb +1 -1
- data/lib/pubid/ieee/builder.rb +42 -2
- 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 +207 -32
- data/lib/pubid/ieee/project_renderer.rb +46 -0
- data/lib/pubid/ieee/renderer.rb +6 -7
- data/lib/pubid/ieee.rb +2 -0
- data/lib/pubid/iso/builder.rb +10 -11
- data/lib/pubid/iso/components.rb +0 -1
- data/lib/pubid/iso/identifier.rb +11 -4
- data/lib/pubid/iso/identifiers/directives.rb +7 -4
- data/lib/pubid/iso/identifiers/tc_document.rb +31 -46
- data/lib/pubid/iso/normalizer.rb +1 -1
- data/lib/pubid/iso/urn_generator.rb +10 -10
- data/lib/pubid/iso.rb +5 -4
- data/lib/pubid/itu/builder.rb +10 -0
- data/lib/pubid/itu/identifiers/base.rb +10 -0
- data/lib/pubid/itu/identifiers/contribution.rb +31 -0
- data/lib/pubid/itu/identifiers.rb +1 -0
- data/lib/pubid/itu/parser.rb +19 -2
- data/lib/pubid/nist/builder.rb +12 -12
- data/lib/pubid/nist/identifiers/base.rb +10 -3
- 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/series/ir.rb +3 -7
- data/lib/pubid/oiml/builder.rb +2 -2
- data/lib/pubid/oiml/identifiers/bulletin.rb +30 -36
- data/lib/pubid/oiml/identifiers/code_number.rb +2 -2
- data/lib/pubid/oiml/parser.rb +7 -2
- data/lib/pubid/oiml/renderer.rb +3 -3
- data/lib/pubid/oiml/single_identifier.rb +1 -1
- data/lib/pubid/oiml/urn_generator.rb +4 -4
- data/lib/pubid/renderers/directives_renderer.rb +3 -1
- data/lib/pubid/sae/builder.rb +1 -1
- data/lib/pubid/sae/identifiers/base.rb +4 -1
- data/lib/pubid/sae/urn_generator.rb +1 -1
- data/lib/pubid/version.rb +1 -1
- data/lib/tasks/docs.rake +13 -11
- metadata +4 -4
- data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +0 -70
- data/lib/pubid/iso/components/code.rb +0 -24
|
@@ -73,7 +73,7 @@ module Pubid
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
# Complete IRE identifier - YEAR FIRST format
|
|
76
|
-
rule(:
|
|
76
|
+
rule(:ire_identifier_year_first) do
|
|
77
77
|
# Format: "52 IRE 7.S2" or "1952 IRE 7.S2"
|
|
78
78
|
year.as(:year) >>
|
|
79
79
|
space >>
|
|
@@ -84,6 +84,24 @@ module Pubid
|
|
|
84
84
|
(space? >> (dash | str(",")).maybe >> space? >> year_full.as(:full_year)).maybe
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
# Prefix-first format: "IRE 7.S2-1952" (pubid#316 family 2) — the
|
|
88
|
+
# year trails the designation instead of leading the identifier.
|
|
89
|
+
# The renderer always emits the year-first short-year form, so this
|
|
90
|
+
# spelling canonicalizes onto it ("IRE 7.S2-1952" → "52 IRE 7.S2").
|
|
91
|
+
rule(:ire_identifier_prefix_first) do
|
|
92
|
+
ire_prefix >>
|
|
93
|
+
space >>
|
|
94
|
+
(ire_type >> space).maybe >>
|
|
95
|
+
number >>
|
|
96
|
+
date
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Year-first is tried first so the original spellings keep their
|
|
100
|
+
# match; prefix-first claims only what year-first cannot.
|
|
101
|
+
rule(:ire_identifier) do
|
|
102
|
+
ire_identifier_year_first | ire_identifier_prefix_first
|
|
103
|
+
end
|
|
104
|
+
|
|
87
105
|
root(:ire_identifier)
|
|
88
106
|
end
|
|
89
107
|
end
|
data/lib/pubid/ieee/parser.rb
CHANGED
|
@@ -611,19 +611,31 @@ module Pubid
|
|
|
611
611
|
# "-YYYY[-MM]" date (instead of ":YYYY"), multi-digit committee-draft
|
|
612
612
|
# stage codes (CD1..CD4) plus CDV, and a wider set of joint publishers.
|
|
613
613
|
# (roadmap items 2/3, phase 1). longest publisher token first.
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
614
|
+
# The stage is OPTIONAL ONLY for ISO-led joint prefixes - the
|
|
615
|
+
# stage-less PUBLISHED form (pubid#317): "ISO/IEC/IEEE 26511:2018",
|
|
616
|
+
# "ISO/IEEE 11073-20101:2004(E)". Every other prefix keeps the
|
|
617
|
+
# stage REQUIREMENT so this rule cannot steal what belongs to
|
|
618
|
+
# iec_ieee_copublished ("IEC/IEEE 60076-2016"), the bare-IEEE
|
|
619
|
+
# project rules ("IEEE P802.16/D-3") or the ISO flavor
|
|
620
|
+
# ("ISO/IEC <n>:<year>").
|
|
621
|
+
iso_led = (str("ISO/IEC/IEEE") | str("IEEE/ISO/IEC") |
|
|
622
|
+
str("IEEE/IEC/ISO") | str("ISO/IEEE"))
|
|
623
|
+
staged_only = (str("IEC/IEEE") | str("IEEE/IEC") |
|
|
624
|
+
str("ISO/IEC") | str("IEEE"))
|
|
625
|
+
# ISO stage codes: FDIS, FCD, CDV; DIS/CD with an optional round
|
|
626
|
+
# digit (DIS2, CD1..CD4); WD/PWI/NP.
|
|
627
|
+
iso_stage = (str("FDIS") | str("FCD") | str("CDV") |
|
|
628
|
+
(str("DIS") >> digit.maybe) |
|
|
629
|
+
(str("CD") >> digit.maybe) |
|
|
630
|
+
str("WD") | str("PWI") | str("NP")).as(:iso_stage)
|
|
631
|
+
std_noise = (space >> str("Std")).maybe
|
|
632
|
+
# The empty-string marker distinguishes the stage-less PUBLISHED
|
|
633
|
+
# tree in the builder (absence of :iso_stage alone means IEEE format).
|
|
634
|
+
((iso_led.as(:joint_publishers) >> space >>
|
|
635
|
+
(iso_stage >> std_noise >> space |
|
|
636
|
+
str("").as(:iso_published) >> space.maybe)) |
|
|
637
|
+
(staged_only.as(:joint_publishers) >> space >>
|
|
638
|
+
iso_stage >> std_noise >> space)) >>
|
|
627
639
|
str("P").maybe >> # optional project marker on the number
|
|
628
640
|
digits.as(:number) >>
|
|
629
641
|
# part must not swallow the trailing year (year_digits.absent?)
|
|
@@ -641,12 +653,33 @@ module Pubid
|
|
|
641
653
|
# historical "…/D-3-2017" onto the number as "…-2017/D3", so by the
|
|
642
654
|
# time this rule runs the draft usually trails the date (bucket 5);
|
|
643
655
|
# a date-less "/D-4" keeps its hyphen (bucket 7), hence dash.maybe.
|
|
656
|
+
# A text date may trail the DRAFT itself (pubid#216:
|
|
657
|
+
# "CD P26515/D1, March 2017", "FDIS P15289/D3, 2017") — distinct
|
|
658
|
+
# keys (:draft_month/:draft_year), because a plain :month/:year
|
|
659
|
+
# here collides with the date clause above and parslet drops the
|
|
660
|
+
# subtree with a "Duplicate subtrees" warning.
|
|
644
661
|
(slash >> str("D") >> dash.maybe >>
|
|
645
|
-
match('[0-9.]').repeat(1).as(:draft_version)
|
|
662
|
+
match('[0-9.]').repeat(1).as(:draft_version) >>
|
|
663
|
+
(((comma | space) >> month_name.as(:draft_month) >> space >>
|
|
664
|
+
year_digits.as(:draft_year)) |
|
|
665
|
+
(comma >> year_digits.as(:draft_year))).maybe).maybe >>
|
|
666
|
+
# Optional amendment tail (pubid#317:
|
|
667
|
+
# "8802-11:2012/Amd.1:2014(E)") - the flat tree keys reuse
|
|
668
|
+
# build_flat_amendment.
|
|
669
|
+
(slash >> str("Amd") >> (dot | space).maybe >>
|
|
670
|
+
digits.as(:amd_number) >>
|
|
671
|
+
((str(":") | dash) >> year_digits.as(:amd_year)).maybe).maybe >>
|
|
646
672
|
# Optional edition, from relaton's "/E-<n>" suffix normalized to
|
|
647
673
|
# "Edition <n>.0[ YYYY]" (nil-residue hand-off item 1).
|
|
648
674
|
edition.maybe >>
|
|
649
|
-
revision_suffix.maybe
|
|
675
|
+
revision_suffix.maybe >>
|
|
676
|
+
# Published joint docs print a language marker, after either the
|
|
677
|
+
# year or the amendment tail: "9945:2009(E)", "...Amd.1:2014(E)".
|
|
678
|
+
# The crawl sometimes spaces it ("…(E), January 2017" family,
|
|
679
|
+
# pubid#216), and a relationship parenthetical may follow
|
|
680
|
+
# ("…CD2 P15288-2013-09 (Revision of …)").
|
|
681
|
+
space.maybe >> (str("(E)") | str("(F)")).maybe >>
|
|
682
|
+
parenthetical.maybe
|
|
650
683
|
end
|
|
651
684
|
|
|
652
685
|
# Embedded (stage-LAST) ISO-led designations: the corpus writes the ISO
|
|
@@ -701,9 +734,13 @@ module Pubid
|
|
|
701
734
|
end
|
|
702
735
|
|
|
703
736
|
# IEEE P pattern (without Std): "IEEE P1003.1..." OR just "P1003.1..." (prefix optional)
|
|
737
|
+
# `P` is not consumed here: the `number` rule carries its own optional
|
|
738
|
+
# leading P and captures it into :number ("P1003.1"), so Code.parse
|
|
739
|
+
# peels it as code.prefix and the project marker survives the parse —
|
|
740
|
+
# a bare `str("P")` swallowed it and "P1201/D0.3" came back without
|
|
741
|
+
# its P at all (pubid#18's data-loss complaint).
|
|
704
742
|
rule(:ieee_p_identifier) do
|
|
705
743
|
(str("IEEE").as(:publisher) >> space).maybe >> # Make IEEE prefix optional
|
|
706
|
-
str("P") >> space.maybe >> # Make space after P optional
|
|
707
744
|
number >>
|
|
708
745
|
(part_subpart_year | edition).maybe >>
|
|
709
746
|
# Pattern for /08 style drafts (digits without D prefix) - MUST come before corrigendum
|
|
@@ -759,15 +796,17 @@ module Pubid
|
|
|
759
796
|
# status is captured (draft_status ends in a space, so "Approved Draft"
|
|
760
797
|
# splits cleanly) and round-trips as the draft_status attribute; the literal
|
|
761
798
|
# "Draft" stays a bare marker (dropped on render, like the plain form).
|
|
799
|
+
# `P` is not consumed here: the `number` rule carries its own optional
|
|
800
|
+
# leading P and captures it into :number ("P802.11"), so Code.parse peels
|
|
801
|
+
# it as code.prefix and the project marker round-trips (pubid#318) — a
|
|
802
|
+
# bare `str("P").maybe` here swallowed it and the render lost the P.
|
|
762
803
|
rule(:ieee_draft_p_identifier) do
|
|
763
804
|
(str("IEEE").as(:publisher) >> space).maybe >> # Make IEEE prefix optional
|
|
764
805
|
draft_status.as(:draft_status).maybe >>
|
|
765
806
|
str("Draft") >> space >>
|
|
766
|
-
#
|
|
767
|
-
# ("IEEE Unapproved Draft 802.1ah/D4.2")
|
|
768
|
-
# ieee_approved_draft_identifier's str("P").maybe. The `number` rule
|
|
807
|
+
# A status-word draft may carry a bare number
|
|
808
|
+
# ("IEEE Unapproved Draft 802.1ah/D4.2"). The `number` rule
|
|
769
809
|
# already accepts the bare forms (802.1ah, C57.15, 11073-10471).
|
|
770
|
-
str("P").maybe >>
|
|
771
810
|
number >>
|
|
772
811
|
(part_subpart_year | edition).maybe >>
|
|
773
812
|
# Trailing "Month YYYY" date under distinct keys so it never collides
|
|
@@ -836,6 +875,11 @@ module Pubid
|
|
|
836
875
|
# Year-first pattern: "52 IRE 7.S2" or "60 IRE 28 PS7"
|
|
837
876
|
((match("[1-6]") >> digit >> space >> str("IRE")) | # 2-digit year format
|
|
838
877
|
(str("19") >> digit.repeat(2, 2) >> space >> str("IRE"))) |
|
|
878
|
+
# Prefix-first pattern: "IRE 7.S2-1952" (pubid#316 family 2) —
|
|
879
|
+
# IRE then a designation (digits or a type word). Loose on
|
|
880
|
+
# purpose: the sub-parser is strict, and a failed delegation just
|
|
881
|
+
# falls through to the remaining alternatives.
|
|
882
|
+
(str("IRE") >> space >> (digits | str("Standard") | str("Std") | str("Trans"))) |
|
|
839
883
|
# IEEE-IRE transitional pattern
|
|
840
884
|
(str("IEEE-IRE") >> space)
|
|
841
885
|
).present? >>
|
|
@@ -861,23 +905,47 @@ module Pubid
|
|
|
861
905
|
Nesc::Parser.new.nesc_identifier.as(:nesc)
|
|
862
906
|
end
|
|
863
907
|
|
|
908
|
+
# Draft notation for PSI (e.g., /D2, /D3, rawbib's /D-2)
|
|
909
|
+
rule(:psi_draft) do
|
|
910
|
+
slash >> str("D") >> dash.maybe >> digits.as(:draft_version)
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
# Date on an SI/PSI identifier: ", Month Year" or "-YEAR[-MM]". The
|
|
914
|
+
# comma branch also accepts a NUMERIC month and a DASH before the
|
|
915
|
+
# year — the renderer emits ", 05 2010" for a numeric-month draft,
|
|
916
|
+
# and the preprocessing gsub rewrites a trailing " <digits> <year>"
|
|
917
|
+
# to "<digits>-<year>" (the same load-bearing coupling draft_date
|
|
918
|
+
# documents), so the re-parse must read its own rendering back.
|
|
919
|
+
rule(:psi_date) do
|
|
920
|
+
(comma >> (month_name | month_numeric).as(:month) >> (space | dash) >>
|
|
921
|
+
year_digits.as(:year)) |
|
|
922
|
+
(dash >> year_digits.as(:year) >>
|
|
923
|
+
(dash >> digit.repeat(2, 2).as(:month)).maybe)
|
|
924
|
+
end
|
|
925
|
+
|
|
864
926
|
# IEEE/ASTM SI/PSI (Système International) patterns
|
|
865
927
|
# SI = Published metric system standard
|
|
866
928
|
# PSI = Proposed SI (draft)
|
|
929
|
+
# Rawbib spellings (pubid#316 family 3): a bare "IEEE" publisher, a dot
|
|
930
|
+
# separator after the type ("PSI.10", "SI 10.1997"), relaton's
|
|
931
|
+
# hyphenated "/D-<n>" draft, and a dash year-month ("-2010-05").
|
|
867
932
|
rule(:ieee_astm_si_psi) do
|
|
868
|
-
str("IEEE/ASTM").as(:publishers) >>
|
|
933
|
+
(str("IEEE/ASTM") | str("IEEE")).as(:publishers) >>
|
|
869
934
|
space >>
|
|
870
935
|
(str("PSI") | str("SI")).as(:si_type) >>
|
|
871
|
-
space >>
|
|
936
|
+
(space | str(".")) >>
|
|
872
937
|
digits.as(:number) >>
|
|
873
|
-
#
|
|
874
|
-
(
|
|
875
|
-
#
|
|
938
|
+
# Glued ".YEAR" edition date ("IEEE/ASTM SI 10.1997")
|
|
939
|
+
(str(".") >> year_digits.as(:year)).maybe >>
|
|
940
|
+
# The date and the draft appear in EITHER order: the legacy
|
|
941
|
+
# spelling puts the draft first ("PSI 10/D2, October 2015"),
|
|
942
|
+
# while normalize_relaton_suffixes repositions the rawbib
|
|
943
|
+
# hyphenated form onto the number ("PSI 10/D-3-2010" →
|
|
944
|
+
# "PSI 10-2010/D3"). Draft-first is tried first so the legacy
|
|
945
|
+
# comma-date keeps its original match; each side is optional so
|
|
946
|
+
# a date-only or draft-less form still parses.
|
|
876
947
|
(
|
|
877
|
-
|
|
878
|
-
(comma >> month_name.as(:month) >> space >> year_digits.as(:year)) |
|
|
879
|
-
# Format: "-YEAR"
|
|
880
|
-
(dash >> year_digits.as(:year))
|
|
948
|
+
(psi_draft >> psi_date.maybe) | (psi_date >> psi_draft.maybe)
|
|
881
949
|
).maybe >>
|
|
882
950
|
# Optional parenthetical (revision relationships)
|
|
883
951
|
parenthetical.maybe
|
|
@@ -1159,12 +1227,15 @@ module Pubid
|
|
|
1159
1227
|
# A "\d+" right after "Rev" both selects the numbered subset and keeps
|
|
1160
1228
|
# these off the English word "Revision". Three source positions:
|
|
1161
1229
|
# after a draft : "PC37.30.2/D043 Rev 18" -> ".../D043/R-18"
|
|
1230
|
+
# The draft captures accept relaton's hyphenated "/D-<n>" spelling
|
|
1231
|
+
# (pubid#316): without the "-?" the before-draft regex matched only
|
|
1232
|
+
# "/D" of "/D-3" and emitted the garbage "/D/R-2-3-2008-02".
|
|
1162
1233
|
cleaned = cleaned.sub(
|
|
1163
|
-
%r{(/D[0-9A-Za-z.]
|
|
1234
|
+
%r{(/D-?[0-9A-Za-z.]+)\s+[Rr][Ee][Vv]\s*(\d+)}, '\1/R-\2'
|
|
1164
1235
|
)
|
|
1165
1236
|
# before a draft: "P802.16Rev2/D3" -> "P802.16/D3/R-2"
|
|
1166
1237
|
cleaned = cleaned.sub(
|
|
1167
|
-
%r{[-/_.]?\s?[Rr][Ee][Vv][-\s]?(\d+)(/D[0-9A-Za-z.]
|
|
1238
|
+
%r{[-/_.]?\s?[Rr][Ee][Vv][-\s]?(\d+)(/D-?[0-9A-Za-z.]+)}, '\2/R-\1'
|
|
1168
1239
|
)
|
|
1169
1240
|
# no draft, trailing: "P1722-rev1" -> "P1722/R-1"
|
|
1170
1241
|
cleaned = cleaned.sub(
|
|
@@ -1176,7 +1247,7 @@ module Pubid
|
|
|
1176
1247
|
# became "/R-<n>", so these regexes only see the lettered residue.
|
|
1177
1248
|
# Revision token that PRECEDES a draft: drop it (keep the /D…).
|
|
1178
1249
|
cleaned = cleaned.sub(
|
|
1179
|
-
%r{[-/_.]?\s?[Rr][Ee][Vv][-\s]?[A-Za-z0-9]+(?=/D[0-
|
|
1250
|
+
%r{[-/_.]?\s?[Rr][Ee][Vv][-\s]?[A-Za-z0-9]+(?=/D-?[0-9A-Za-z])},
|
|
1180
1251
|
"",
|
|
1181
1252
|
)
|
|
1182
1253
|
# Trailing revision glued to the number with no draft ("P802.11REVmb");
|
|
@@ -1185,6 +1256,105 @@ module Pubid
|
|
|
1185
1256
|
cleaned.sub(%r{(\d)[Rr][Ee][Vv][A-Za-z0-9]+\s*\z}, '\1')
|
|
1186
1257
|
end
|
|
1187
1258
|
|
|
1259
|
+
# Rewrite the mechanical spellings of the joint ISO-stage forms that no
|
|
1260
|
+
# grammar branch reaches (pubid#216 residuals). Two safety rules keep
|
|
1261
|
+
# this from stealing inputs other rules already parse:
|
|
1262
|
+
# 1. only BROKEN separators fire — underscore/space glue between
|
|
1263
|
+
# number, draft and stage, a slash-SPACE before the stage, a
|
|
1264
|
+
# dash/underscore month after it. A plain "/FDIS" tail is
|
|
1265
|
+
# natively accepted by ieee_p_identifier (fdraft) and the
|
|
1266
|
+
# stage-LAST embedded rule, so it is never rewritten.
|
|
1267
|
+
# 2. the number carries at most ONE part — joint_development_iso_format
|
|
1268
|
+
# reads a single optional part, while ieee_p_identifier takes
|
|
1269
|
+
# multi-part numbers ("P62271-37-013"); a rewrite that moved a
|
|
1270
|
+
# multi-part number onto the joint rule would break it.
|
|
1271
|
+
def self.normalize_joint_stage_spellings(cleaned)
|
|
1272
|
+
# The separator (slash-optional-space or a space) is INSIDE the
|
|
1273
|
+
# capture so a rewrite re-emits it — an uncaptured separator was
|
|
1274
|
+
# silently eaten, gluing the publisher to the stage.
|
|
1275
|
+
pubs = %r{((?:ISO/IEC/IEEE|IEEE/ISO/IEC|IEEE/IEC/ISO|ISO/IEEE|IEC/IEEE|IEEE/IEC|ISO/IEC|IEEE)(?:/ ?| ))}
|
|
1276
|
+
stage = /(FDIS|FCD|CDV|DIS\d?|CD\d?|WD|PWI|NP)/
|
|
1277
|
+
num = /(P?\d+(?:[.-]\d+)?)/
|
|
1278
|
+
# What the joint grammar can finish reading AFTER the stage: the end
|
|
1279
|
+
# of the string, a (comma-)month-year date, or a dash-year[-month].
|
|
1280
|
+
# Captured and re-emitted so a rewrite never drops the date.
|
|
1281
|
+
tail = /(,? (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)[a-z]* \d{4}|\z|-\d{4}(?:-\d\d)?)/
|
|
1282
|
+
|
|
1283
|
+
# Draft glued to the number with an underscore: "P15289_D3" →
|
|
1284
|
+
# "P15289/D3" (a digit must precede the underscore; "_FDIS" is the
|
|
1285
|
+
# stage, not a draft, and is already slash-rewritten earlier).
|
|
1286
|
+
cleaned = cleaned.gsub(%r{(\d)_D(\d)}, '\1/D\2')
|
|
1287
|
+
|
|
1288
|
+
# Crawl typo: a comma with no space before a month (",March 2021").
|
|
1289
|
+
# In these identifiers a comma is always a date separator, so
|
|
1290
|
+
# spacing it is safe.
|
|
1291
|
+
cleaned = cleaned.sub(/,(?=[A-Za-z])/, ", ")
|
|
1292
|
+
|
|
1293
|
+
# Stage AFTER the draft, both glued with underscores (the early
|
|
1294
|
+
# stage gsub already turned "_CD" into "/CD"):
|
|
1295
|
+
# "…P24748-3/D3/FDIS, April 2020 (E)" → "…FDIS P24748-3/D3, …"
|
|
1296
|
+
cleaned = cleaned.sub(
|
|
1297
|
+
%r{\A#{pubs}#{num}/(D[\d.]+)/ ?#{stage}\b},
|
|
1298
|
+
'\1\4 \2/\3',
|
|
1299
|
+
)
|
|
1300
|
+
|
|
1301
|
+
# Slash-SPACE before the stage ("…P16085/ FDIS, August 2020" —
|
|
1302
|
+
# ieee_p's fdraft has no inner space, so this spelling has no other
|
|
1303
|
+
# home): → "…FDIS P16085, August 2020"
|
|
1304
|
+
cleaned = cleaned.sub(
|
|
1305
|
+
%r{\A#{pubs}#{num}/ #{stage}#{tail}},
|
|
1306
|
+
'\1\3 \2\4',
|
|
1307
|
+
)
|
|
1308
|
+
|
|
1309
|
+
# A space-year after a slash-stage ("…P26511.2/FDIS 2018" — no rule
|
|
1310
|
+
# reads "/FDIS 2018"): → "…FDIS P26511.2-2018" (dash-year clause).
|
|
1311
|
+
cleaned = cleaned.sub(
|
|
1312
|
+
%r{\A#{pubs}#{num}/#{stage} (\d{4})\b},
|
|
1313
|
+
'\1\3 \2-\4',
|
|
1314
|
+
)
|
|
1315
|
+
|
|
1316
|
+
# Stage separated from the number by a SPACE ("IEC/IEEE P63113 CD4,
|
|
1317
|
+
# April 2019"): → "IEC/IEEE CD4 P63113, April 2019". The tail guard
|
|
1318
|
+
# keeps "…FDIS March 2019" (space-month-year, readable after the
|
|
1319
|
+
# swap) while leaving prose suffixes alone.
|
|
1320
|
+
cleaned = cleaned.sub(
|
|
1321
|
+
%r{\A#{pubs}#{num} #{stage}#{tail}},
|
|
1322
|
+
'\1\3 \2\4',
|
|
1323
|
+
)
|
|
1324
|
+
|
|
1325
|
+
# The same space-stage with a space-DRAFT chained after it
|
|
1326
|
+
# ("IEC/IEEE P60980-344 CDV D1, June 2019"): → stage-first with a
|
|
1327
|
+
# slash draft ("…CDV P60980-344/D1, June 2019").
|
|
1328
|
+
cleaned = cleaned.sub(
|
|
1329
|
+
%r{\A#{pubs}#{num} #{stage} (D\d+)\b},
|
|
1330
|
+
'\1\3 \2/\4',
|
|
1331
|
+
)
|
|
1332
|
+
|
|
1333
|
+
# Slash-stage carrying a dash-date ("…P15288/CD2-2013-09 …" — the
|
|
1334
|
+
# dash-year tail is what the joint grammar reads after the number, so
|
|
1335
|
+
# this cannot steal the plain "/FDIS, June 2021" spellings
|
|
1336
|
+
# ieee_p_identifier finishes): → "…CD2 P15288-2013-09 …"
|
|
1337
|
+
cleaned = cleaned.sub(
|
|
1338
|
+
%r{\A#{pubs}#{num}/ ?#{stage}(-\d{4}(?:-\d\d)?)},
|
|
1339
|
+
'\1\3 \2\4',
|
|
1340
|
+
)
|
|
1341
|
+
|
|
1342
|
+
# Draft separated from a stage-first number by a SPACE:
|
|
1343
|
+
# "…DIS P11073-10418 D13, January 2011" → "…DIS P11073-10418/D13, …"
|
|
1344
|
+
cleaned = cleaned.sub(
|
|
1345
|
+
%r{\A#{pubs}#{stage} #{num}/? ?(D\d+)\b},
|
|
1346
|
+
'\1\2 \3/\4',
|
|
1347
|
+
)
|
|
1348
|
+
|
|
1349
|
+
# NOT rewritten: a month glued to the stage with a dash/underscore
|
|
1350
|
+
# ("…/FDIS_Dec 2012", "…/FDIS-Dec 2015"). Even routed onto the joint
|
|
1351
|
+
# grammar, the joint render of a month+draft is itself not yet
|
|
1352
|
+
# idempotent, and the bare-IEEE fdraft path drops the stage and the
|
|
1353
|
+
# date from to_hash — rewriting would trade a visible parse failure
|
|
1354
|
+
# for silent garbage. Deferred with the pubid#216 semantic residue.
|
|
1355
|
+
cleaned
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1188
1358
|
def self.parse(string)
|
|
1189
1359
|
# Strip .pdf extension if present (Pattern 3: File Extensions)
|
|
1190
1360
|
cleaned = string.sub(/\.pdf$/i, "")
|
|
@@ -1265,6 +1435,11 @@ module Pubid
|
|
|
1265
1435
|
/\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)(\d{4})\b/, '\1 \2'
|
|
1266
1436
|
)
|
|
1267
1437
|
|
|
1438
|
+
# Rewrite the joint ISO-stage glued spellings (pubid#216) AFTER the
|
|
1439
|
+
# month unglue above, so "Dec2015" is already spaced when the
|
|
1440
|
+
# dash-month rewrite looks for it.
|
|
1441
|
+
cleaned = normalize_joint_stage_spellings(cleaned)
|
|
1442
|
+
|
|
1268
1443
|
# NEW: Convert IEC/IEEE space-separated to semicolon format
|
|
1269
1444
|
# Pattern: "IEC 61523-3 First edition 2004-09; IEEE 1497" → already semicolon
|
|
1270
1445
|
# Pattern: "IEC 62539 First Edition 2007-07 IEEE 930" → needs semicolon
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ieee
|
|
5
|
+
# Renders the IEEE PROJECT DESIGNATOR — the short form IEEE itself uses
|
|
6
|
+
# for draft documents ("P1201/D0.3", "P10000/D1.2"): the project marker,
|
|
7
|
+
# the number with its parts, and the draft. No publisher, no type word,
|
|
8
|
+
# no date (pubid#18: metanorma-ieee builds these for drafts and had to
|
|
9
|
+
# post-process the full rendering).
|
|
10
|
+
class ProjectRenderer
|
|
11
|
+
def initialize(id)
|
|
12
|
+
@id = id
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render(context: nil, **_opts)
|
|
16
|
+
id = @id
|
|
17
|
+
body = if id.respond_to?(:code_obj) && id.code_obj
|
|
18
|
+
id.code_obj.to_s
|
|
19
|
+
else
|
|
20
|
+
id.number.to_s
|
|
21
|
+
end
|
|
22
|
+
body = "P#{body}" if project?(id) && !body.start_with?("P")
|
|
23
|
+
|
|
24
|
+
draft = id.draft_obj if id.respond_to?(:draft_obj)
|
|
25
|
+
body += "/D#{draft.version}" if draft&.version
|
|
26
|
+
|
|
27
|
+
body
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# A project identifier carries its marker in one of three places
|
|
33
|
+
# depending on which grammar path built it: the code prefix (the bare
|
|
34
|
+
# "P1201/D0.3" spelling), the "P" type code ("IEEE P802.16/D-3"), or a
|
|
35
|
+
# typed stage with project_status (the D1-D6 draft stages).
|
|
36
|
+
def project?(id)
|
|
37
|
+
return true if id.code_obj&.prefix.to_s == "P"
|
|
38
|
+
return true if id.type.to_s == "P"
|
|
39
|
+
|
|
40
|
+
id.respond_to?(:typed_stage) &&
|
|
41
|
+
id.typed_stage&.respond_to?(:project_status) &&
|
|
42
|
+
id.typed_stage.project_status
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/pubid/ieee/renderer.rb
CHANGED
|
@@ -115,17 +115,16 @@ 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
|
|
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)
|
data/lib/pubid/iso/builder.rb
CHANGED
|
@@ -143,7 +143,7 @@ module Pubid
|
|
|
143
143
|
return nil unless year_value.between?(1900, 2099)
|
|
144
144
|
|
|
145
145
|
{
|
|
146
|
-
number:
|
|
146
|
+
number: number,
|
|
147
147
|
date: ::Pubid::Components::Date.new(year: part),
|
|
148
148
|
}
|
|
149
149
|
end
|
|
@@ -197,7 +197,7 @@ module Pubid
|
|
|
197
197
|
# or "105/F" ('F' is part)
|
|
198
198
|
# or "5843/6" ('6' is part)
|
|
199
199
|
# LEGACY: "4037-1979" (number-year, year should become date)
|
|
200
|
-
parse_number_with_part(value
|
|
200
|
+
parse_number_with_part(value)
|
|
201
201
|
|
|
202
202
|
when :directives_type
|
|
203
203
|
# nothing to do here, just return nil
|
|
@@ -240,8 +240,10 @@ module Pubid
|
|
|
240
240
|
original_text = value.to_s
|
|
241
241
|
# Extract just the digit(s) for the number field
|
|
242
242
|
number_string = original_text.match(/\d+/)&.to_s
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
# A plain string: Components::Edition#number is typed Value, so a
|
|
244
|
+
# component here would leak a live Ruby object into to_hash (and a
|
|
245
|
+
# !ruby/object tag into to_yaml).
|
|
246
|
+
Pubid::Components::Edition.new(number: number_string,
|
|
245
247
|
original_text: original_text)
|
|
246
248
|
|
|
247
249
|
when :languages
|
|
@@ -260,8 +262,7 @@ module Pubid
|
|
|
260
262
|
|
|
261
263
|
when :subgroup
|
|
262
264
|
# Handle JTC 1 subgroup in directives (ISO/IEC JTC 1 DIR)
|
|
263
|
-
|
|
264
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
265
|
+
value.to_s
|
|
265
266
|
|
|
266
267
|
when :supplements
|
|
267
268
|
# Handle bundled supplements (+ operator)
|
|
@@ -274,12 +275,10 @@ module Pubid
|
|
|
274
275
|
|
|
275
276
|
# TC Document attributes
|
|
276
277
|
when :tc_type, :sc_type, :wg_type
|
|
277
|
-
|
|
278
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
278
|
+
value.to_s
|
|
279
279
|
|
|
280
280
|
when :tc_number, :sc_number, :wg_number
|
|
281
|
-
|
|
282
|
-
Pubid::Iso::Components::Code.new(value: value.to_s)
|
|
281
|
+
value.to_s
|
|
283
282
|
|
|
284
283
|
when :year
|
|
285
284
|
# For TC documents with year, convert to Date
|
|
@@ -290,7 +289,7 @@ module Pubid
|
|
|
290
289
|
# For regular identifiers, this is handled in :number_with_part
|
|
291
290
|
if value.is_a?(Parslet::Slice) || value.is_a?(String) ||
|
|
292
291
|
value.is_a?(Integer)
|
|
293
|
-
|
|
292
|
+
value.to_s
|
|
294
293
|
else
|
|
295
294
|
value
|
|
296
295
|
end
|
data/lib/pubid/iso/components.rb
CHANGED
data/lib/pubid/iso/identifier.rb
CHANGED
|
@@ -56,9 +56,14 @@ module Pubid
|
|
|
56
56
|
ts ? dup.tap { |id| id.typed_stage = ts } : dup
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
# Plain strings. Iso::Components::Code existed to join `parts` with
|
|
60
|
+
# "-", a composition no ISO identifier ever reached: `parts` is never
|
|
61
|
+
# written in lib/pubid/iso and no Code in the 7,613-id corpus carries
|
|
62
|
+
# anything but `value`. ISO part and subpart are sibling attributes, not
|
|
63
|
+
# fields of the number.
|
|
64
|
+
attribute :number, :string
|
|
65
|
+
attribute :part, :string
|
|
66
|
+
attribute :subpart, :string
|
|
62
67
|
|
|
63
68
|
# Polymorphic type map for lutaml::Model key_value serialization
|
|
64
69
|
# Maps polymorphic_name → class name for deserialization
|
|
@@ -213,8 +218,10 @@ module Pubid
|
|
|
213
218
|
doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
|
|
214
219
|
end
|
|
215
220
|
|
|
221
|
+
# number/part/subpart are plain strings; the converter name is kept
|
|
222
|
+
# so the key_value map below does not have to change.
|
|
216
223
|
def build_code(value)
|
|
217
|
-
|
|
224
|
+
value.to_s
|
|
218
225
|
end
|
|
219
226
|
|
|
220
227
|
# --- date serialized flat as year/month/day ---
|
|
@@ -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(":")
|