pubid 2.0.0.pre.alpha.27 → 2.0.0.pre.alpha.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/ieee/update_codes.yaml +6 -3
- data/data/parg/iec.json +1 -1
- data/data/parg/ieee.json +1 -1
- data/data/parg/nesc.parg +17 -2
- data/data/parg/nist.json +1 -1
- data/lib/pubid/ieee/aiee/builder.rb +5 -2
- data/lib/pubid/ieee/aiee/identifier.rb +18 -13
- data/lib/pubid/ieee/builder.rb +164 -15
- data/lib/pubid/ieee/components/draft.rb +29 -3
- data/lib/pubid/ieee/identifiers/base.rb +7 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +15 -2
- data/lib/pubid/ieee/identifiers/nesc/base.rb +1 -1
- data/lib/pubid/ieee/identifiers/nesc/preprint.rb +41 -0
- data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
- data/lib/pubid/ieee/long_renderer.rb +18 -0
- data/lib/pubid/ieee/nesc/builder.rb +5 -0
- data/lib/pubid/ieee/parser.rb +9 -4
- data/lib/pubid/ieee/renderer.rb +58 -4
- data/lib/pubid/ieee/urn_generator.rb +7 -0
- data/lib/pubid/ieee.rb +2 -0
- data/lib/pubid/nist/components/edition.rb +22 -1
- data/lib/pubid/nist/components/translation.rb +4 -2
- data/lib/pubid/nist/identifiers/base.rb +55 -22
- data/lib/pubid/nist/parser.rb +24 -8
- data/lib/pubid/nist/preprocessor.rb +15 -0
- data/lib/pubid/version.rb +1 -1
- metadata +8 -6
|
@@ -38,9 +38,12 @@ module Pubid
|
|
|
38
38
|
|
|
39
39
|
# Extract the long-form date separator ("," or ".") for rendering.
|
|
40
40
|
# Named `date_separator` on the identifier to avoid colliding with the
|
|
41
|
-
# CodeNumber code-part `separator`.
|
|
41
|
+
# CodeNumber code-part `separator`. The dash-glued form ("-1928-05")
|
|
42
|
+
# carries no separator capture (its tail binds as the year/month
|
|
43
|
+
# clause itself), so a month without a separator capture IS the
|
|
44
|
+
# dash form.
|
|
42
45
|
separator_str = extract_value(parsed[:separator])
|
|
43
|
-
attributes[:date_separator] = separator_str if separator_str
|
|
46
|
+
attributes[:date_separator] = separator_str || "-" if separator_str || month_str
|
|
44
47
|
|
|
45
48
|
# Set original format based on parsed data
|
|
46
49
|
attributes[:original_format] = if separator_str || month_str
|
|
@@ -59,20 +59,25 @@ module Pubid
|
|
|
59
59
|
format ||= month || date_separator ? "long" : "short"
|
|
60
60
|
|
|
61
61
|
if year
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
base += "-#{year}"
|
|
65
|
-
when "long", :long
|
|
66
|
-
sep = date_separator || "," # Default to comma for long form
|
|
67
|
-
base += "#{sep} #{"#{month} " if month}#{year}"
|
|
62
|
+
if date_separator == "-" && month
|
|
63
|
+
# The dash-glued numeric form renders whole ("No 15-1928-05")
|
|
64
|
+
base += "-#{year}-#{month}"
|
|
68
65
|
else
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
case format
|
|
67
|
+
when "short", :short
|
|
68
|
+
base += "-#{year}"
|
|
69
|
+
when "long", :long
|
|
70
|
+
sep = date_separator || "," # Default to comma for long form
|
|
71
|
+
base += "#{sep} #{"#{month} " if month}#{year}"
|
|
72
|
+
else
|
|
73
|
+
base += if date_separator
|
|
74
|
+
"#{date_separator} #{"#{month} " if month}#{year}"
|
|
75
|
+
elsif month
|
|
76
|
+
", #{month} #{year}"
|
|
77
|
+
else
|
|
78
|
+
"-#{year}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
76
81
|
end
|
|
77
82
|
end
|
|
78
83
|
|
data/lib/pubid/ieee/builder.rb
CHANGED
|
@@ -511,8 +511,15 @@ module Pubid
|
|
|
511
511
|
# @param parsed_hash [Hash] parsed data with base and supplement info
|
|
512
512
|
# @return [Identifiers::Corrigendum] corrigendum identifier
|
|
513
513
|
def build_corrigendum_supplement(parsed_hash)
|
|
514
|
+
# The `corrigendum_identifier` rule's :base subtree binds as a
|
|
515
|
+
# top-level sequence (an Array of capture hashes — the same shape
|
|
516
|
+
# #build's dispatch merges at line 24) whenever the base carries a
|
|
517
|
+
# multi-capture narrative tail; fold it before reconstruction or
|
|
518
|
+
# reconstruct_base_string's Hash indexing crashes with TypeError.
|
|
519
|
+
base_data = parsed_hash[:base]
|
|
520
|
+
base_data = merge_parsed_array(base_data) if base_data.is_a?(Array)
|
|
514
521
|
# Recursively parse the base identifier reconstructed from the subtree.
|
|
515
|
-
base = Identifier.parse(reconstruct_base_string(
|
|
522
|
+
base = Identifier.parse(reconstruct_base_string(base_data))
|
|
516
523
|
|
|
517
524
|
# Extract corrigendum attributes (parse-tree keys are cor_*; the
|
|
518
525
|
# identifier stores them as the uniform `number`/`year`).
|
|
@@ -771,6 +778,11 @@ module Pubid
|
|
|
771
778
|
def build_joint_development(parsed)
|
|
772
779
|
attributes = {}
|
|
773
780
|
|
|
781
|
+
# The status-draft spelling ("IEEE Unapproved P15288/DFDIS") keeps
|
|
782
|
+
# its status word on the designator face (pubid#318: the word marks
|
|
783
|
+
# the draft).
|
|
784
|
+
attributes[:draft_status] = extract_value(parsed[:draft_status]) if parsed[:draft_status]
|
|
785
|
+
|
|
774
786
|
# Extract publishers from joint_publishers
|
|
775
787
|
if parsed[:joint_publishers]
|
|
776
788
|
joint_pub_str = extract_value(parsed[:joint_publishers])
|
|
@@ -788,6 +800,17 @@ module Pubid
|
|
|
788
800
|
# date ("P42010/D-4-2019") rides the code as a year-part
|
|
789
801
|
# ("P42010.2019/D4") — the face the relaton fixtures pin — while
|
|
790
802
|
# stage-first joints keep the top-level year ("FDIS P15289:2017").
|
|
803
|
+
# A part whose whole value is an ISO/IEC stage token is the
|
|
804
|
+
# stage-last spelling ("29119.FDIS"), not a part: promote it to
|
|
805
|
+
# the stage slot (the #311 embedded rule covers "29119.4.FDIS";
|
|
806
|
+
# this covers the part-less form the shared part capture claims
|
|
807
|
+
# first).
|
|
808
|
+
if parsed[:iso_stage].nil? && parsed[:part] &&
|
|
809
|
+
extract_value(parsed[:part]).to_s.match?(/\A[._-]?(FDIS|FCD|CDV|DIS|CD\d?|WD|PWI|NP)\z/)
|
|
810
|
+
# the stage is the bare token; the capture carries its separator
|
|
811
|
+
parsed[:iso_stage] = extract_value(parsed[:part]).to_s.sub(/\A[._-]/, "")
|
|
812
|
+
parsed[:part] = nil
|
|
813
|
+
end
|
|
791
814
|
code_parts = []
|
|
792
815
|
if parsed[:part].nil? && parsed[:iso_stage].nil? && parsed[:draft_version] &&
|
|
793
816
|
parsed[:printed_dash_year] && parsed[:year] &&
|
|
@@ -805,15 +828,23 @@ module Pubid
|
|
|
805
828
|
"#{extract_value(parsed[:draft_version])}-#{extract_value(parsed[:year])}"
|
|
806
829
|
end
|
|
807
830
|
end
|
|
808
|
-
|
|
831
|
+
# The part/subpart captures carry their printed separator
|
|
832
|
+
# (C1: the part binds before the draft status and the year,
|
|
833
|
+
# separator-in-capture), so they concatenate verbatim - a
|
|
834
|
+
# synthetic separator here is what produced "61850..9".
|
|
835
|
+
# The 8802-family IEC label binds its part with a dash the
|
|
836
|
+
# grammar consumes separately (iec_label_dash): "8802-9", not
|
|
837
|
+
# the dot join a bare part would get.
|
|
838
|
+
if parsed[:part] && parsed[:iec_label_dash]
|
|
839
|
+
code_parts << "-#{extract_value(parsed[:part])}"
|
|
840
|
+
elsif parsed[:part]
|
|
841
|
+
code_parts << extract_value(parsed[:part])
|
|
842
|
+
end
|
|
843
|
+
code_parts << extract_value(parsed[:subpart]) if parsed[:subpart]
|
|
809
844
|
|
|
810
845
|
code_str = extract_value(parsed[:number])
|
|
811
846
|
if code_str && !code_parts.empty?
|
|
812
|
-
|
|
813
|
-
# the printed separator (the iso-format route's :part_dash
|
|
814
|
-
# prints as a dot in the joint code).
|
|
815
|
-
sep = parsed[:iec_label_dash] ? "-" : "."
|
|
816
|
-
code_str += "#{sep}#{code_parts.join(sep)}"
|
|
847
|
+
code_str += code_parts.map { |p| p.to_s.start_with?(".", "-", "_") ? p : ".#{p}" }.join
|
|
817
848
|
end
|
|
818
849
|
# P = project (a draft): identity-bearing, preserved as spelled.
|
|
819
850
|
code_str = "P#{code_str}" if parsed[:project_marker] && code_str
|
|
@@ -849,6 +880,10 @@ module Pubid
|
|
|
849
880
|
end
|
|
850
881
|
attributes[:parenthetical_content] ||= extract_value(parsed[:edition_marker]) if parsed[:edition_marker]
|
|
851
882
|
|
|
883
|
+
# A joint ISO-print redline is a distinct document of the same
|
|
884
|
+
# standard — same flag semantics as the generic path (pubid#215).
|
|
885
|
+
attributes[:redline] = true if parsed[:redline]
|
|
886
|
+
|
|
852
887
|
# Extract edition, from relaton's "/E-<n>" suffix. The grammar's /E
|
|
853
888
|
# alternative captures the bare ordinal (nil-residue hand-off item 1).
|
|
854
889
|
if parsed[:edition]
|
|
@@ -867,7 +902,34 @@ module Pubid
|
|
|
867
902
|
draft_ver = extract_value(parsed[:draft_version])
|
|
868
903
|
# Remove leading 'D' if present since draft_version already has it
|
|
869
904
|
draft_ver = draft_ver.sub(/^D/, "") if draft_ver
|
|
870
|
-
|
|
905
|
+
if draft_ver
|
|
906
|
+
# A date trailing the draft ("/D8, June 2010") belongs to the
|
|
907
|
+
# draft component (canonical month, comma form), and the
|
|
908
|
+
# identity year/month the earlier promotion filled from the
|
|
909
|
+
# same captures are vacated. Stage-first ISO rows are
|
|
910
|
+
# exempt: their canonical is the ISO face, which prints the
|
|
911
|
+
# date from the identity slots (", March 2017", pubid#216).
|
|
912
|
+
if parsed[:draft_month] && parsed[:iso_stage].nil?
|
|
913
|
+
draft = Components::Draft.new(
|
|
914
|
+
version: draft_ver,
|
|
915
|
+
month: extract_value(parsed[:draft_month]),
|
|
916
|
+
year: extract_value(parsed[:draft_year]))
|
|
917
|
+
draft.comma_before_month = true
|
|
918
|
+
attributes[:draft] = draft.to_s.sub(%r{\A/}, "")
|
|
919
|
+
attributes.delete(:year) if parsed[:year].nil?
|
|
920
|
+
attributes.delete(:month) if parsed[:month].nil?
|
|
921
|
+
elsif parsed[:draft_year] && parsed[:iso_stage].nil?
|
|
922
|
+
# The artifact's comma-year tail captures its separator
|
|
923
|
+
# with the value (", 2015") — strip it (the #471
|
|
924
|
+
# separator-in-capture rule: every capture a renderer
|
|
925
|
+
# re-joins gets checked).
|
|
926
|
+
draft_year = extract_value(parsed[:draft_year]).to_s.sub(/\A[, ]+/, "")
|
|
927
|
+
attributes[:draft] = "D#{draft_ver}, #{draft_year}"
|
|
928
|
+
attributes.delete(:year) if parsed[:year].nil?
|
|
929
|
+
else
|
|
930
|
+
attributes[:ieee_draft] = "D#{draft_ver}"
|
|
931
|
+
end
|
|
932
|
+
end
|
|
871
933
|
end
|
|
872
934
|
|
|
873
935
|
# The joint stage-draft clause (docs/IEEE-DRAFT-STAGES.md §1.3):
|
|
@@ -909,7 +971,9 @@ module Pubid
|
|
|
909
971
|
# must not become a printed Standard (which keeps the code's P).
|
|
910
972
|
numeric_draft = parsed[:draft_version] &&
|
|
911
973
|
extract_value(parsed[:draft_version]).to_s.match?(/\A\d/)
|
|
912
|
-
|
|
974
|
+
# A promoted stage ("29119.FDIS") is printed identity - the joint
|
|
975
|
+
# model carries it, never the printed Standard face.
|
|
976
|
+
printed_joint = parsed[:iso_published] && parsed[:iso_stage].nil? &&
|
|
913
977
|
(parsed[:printed_dash_year] || parsed[:printed_month_year] ||
|
|
914
978
|
(numeric_draft && parsed[:draft_month]) ||
|
|
915
979
|
# A date-less stage-less joint reference carrying only a
|
|
@@ -919,9 +983,18 @@ module Pubid
|
|
|
919
983
|
(parsed[:year].nil? && parsed[:parameters].is_a?(Hash) &&
|
|
920
984
|
parsed[:parameters][:parenthetical_content]))
|
|
921
985
|
if printed_joint
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
986
|
+
# The part capture carries its own separator (C1
|
|
987
|
+
# separator-in-capture); join verbatim, synthesizing one only
|
|
988
|
+
# for a bare capture.
|
|
989
|
+
part_val = extract_value(parsed[:part])
|
|
990
|
+
printed_code = extract_value(parsed[:number]).to_s
|
|
991
|
+
if part_val
|
|
992
|
+
printed_code += if part_val.start_with?(".", "-", "_")
|
|
993
|
+
part_val
|
|
994
|
+
else
|
|
995
|
+
"#{parsed[:part_dash] ? "-" : "."}#{part_val}"
|
|
996
|
+
end
|
|
997
|
+
end
|
|
925
998
|
# P = project: the marker is identity, preserved as spelled.
|
|
926
999
|
printed_code = "P#{printed_code}" if parsed[:project_marker]
|
|
927
1000
|
printed_attrs = { publisher: attributes[:publisher],
|
|
@@ -1049,6 +1122,24 @@ module Pubid
|
|
|
1049
1122
|
Pubid::Ieee.locate_stage("P")
|
|
1050
1123
|
end
|
|
1051
1124
|
|
|
1125
|
+
# A plain IEEE-designator draft on joint publishers ("/D8,
|
|
1126
|
+
# June 2010") carries no ISO stage machinery: it is the same
|
|
1127
|
+
# document family as its bare-IEEE twin and the D= designator
|
|
1128
|
+
# rows, so it builds as the project draft they pin (pubid#430)
|
|
1129
|
+
# rather than the joint-development model.
|
|
1130
|
+
if attributes[:draft] && parsed[:iso_stage].nil? &&
|
|
1131
|
+
parsed[:iec_stage].nil? && parsed[:amd_number].nil?
|
|
1132
|
+
draft_attrs = { code: attributes[:code],
|
|
1133
|
+
draft: attributes[:draft] }
|
|
1134
|
+
if attributes[:publishers]
|
|
1135
|
+
draft_attrs[:publisher] = attributes[:publishers].first
|
|
1136
|
+
rest = attributes[:publishers][1..]
|
|
1137
|
+
draft_attrs[:copublisher] = rest if rest
|
|
1138
|
+
end
|
|
1139
|
+
draft_attrs[:draft_status] = attributes[:draft_status] if attributes[:draft_status]
|
|
1140
|
+
return Identifiers::ProjectDraftIdentifier.new(**draft_attrs)
|
|
1141
|
+
end
|
|
1142
|
+
|
|
1052
1143
|
joint = Identifiers::JointDevelopment.new(**attributes)
|
|
1053
1144
|
|
|
1054
1145
|
# Amendment tail on the joint ISO-format form (pubid#317:
|
|
@@ -1322,6 +1413,11 @@ module Pubid
|
|
|
1322
1413
|
# standards ("IEEE No148" prints "IEEE Std 148").
|
|
1323
1414
|
type_value = "Std" if type_value&.match?(/\ANo\.?\z/) &&
|
|
1324
1415
|
original_input.to_s.match?(/\AIEEE\s/)
|
|
1416
|
+
# The canonical type word is the short form (C2 ruling):
|
|
1417
|
+
# "IEEE Standard 495-2007" and "IEEE Std 495-2007" are the same
|
|
1418
|
+
# identifier, so the model normalizes to Std and matches? unifies
|
|
1419
|
+
# the spellings; the long word is a render option (:long).
|
|
1420
|
+
type_value = "Std" if type_value == "Standard"
|
|
1325
1421
|
draft_status_value = extract_value(parsed[:draft_status])
|
|
1326
1422
|
|
|
1327
1423
|
# Handle case where parser captured number without "P" prefix
|
|
@@ -1335,6 +1431,10 @@ module Pubid
|
|
|
1335
1431
|
if !type_value && original_input&.match?(/ANSI\s+P/)
|
|
1336
1432
|
# Extract P as type since it was in the original but parser stripped it
|
|
1337
1433
|
type_value = "P"
|
|
1434
|
+
# The P is identity on a non-IEEE-led publisher too (the C1
|
|
1435
|
+
# ruling): record the marker so the render prepends it —
|
|
1436
|
+
# "ANSI PN42.34/D9a, 2015" round-trips.
|
|
1437
|
+
attributes[:project_marker] = true
|
|
1338
1438
|
end
|
|
1339
1439
|
|
|
1340
1440
|
# NOTE: "P" is a project/draft stage indicator, NOT a code prefix
|
|
@@ -1388,6 +1488,15 @@ module Pubid
|
|
|
1388
1488
|
if parsed[:year]
|
|
1389
1489
|
year_str = extract_value(parsed[:year])
|
|
1390
1490
|
attributes[:year] = year_str
|
|
1491
|
+
# AIEE dash-glued date ("No 15-1928-05"): the tail binds as the
|
|
1492
|
+
# year/month clause with no separator capture, and the AIEE
|
|
1493
|
+
# long-form render is the dash form (a plain numeric month alone
|
|
1494
|
+
# would render ", 05 1928").
|
|
1495
|
+
if attributes[:publisher] == "AIEE" &&
|
|
1496
|
+
original_input.to_s.match?(/-\d{4}(?:-\d{2})?\z/) &&
|
|
1497
|
+
parsed[:month] && year_str.match?(/\A(19|20)\d\d\z/)
|
|
1498
|
+
attributes[:date_separator] = "-"
|
|
1499
|
+
end
|
|
1391
1500
|
elsif parsed[:edition_year]
|
|
1392
1501
|
# The `edition` rule captures its own year under :edition_year (not
|
|
1393
1502
|
# :year) so it never collides with the base -YYYY (see parser.rb).
|
|
@@ -1418,7 +1527,13 @@ module Pubid
|
|
|
1418
1527
|
# Set type attribute for backward compatibility (after P extraction)
|
|
1419
1528
|
# NOTE: "P" IS a type code that maps to ProjectDraftIdentifier via flavor module
|
|
1420
1529
|
# Type can be: "Std", "No", "P" (project draft), etc.
|
|
1421
|
-
|
|
1530
|
+
# A DRAFT type word never reaches the hash: the draft-ness is
|
|
1531
|
+
# carried by draft_status and the draft component (the C2 ruling
|
|
1532
|
+
# - a draft is a Draft, "Draft Std" is banned from canonical
|
|
1533
|
+
# output), so an alias spelling and its canonical hash equal.
|
|
1534
|
+
# The value still feeds determine_stage_abbr below (the
|
|
1535
|
+
# version-less D1 fabrication, pubid#318).
|
|
1536
|
+
attributes[:type] = type_value if type_value && type_value !~ /\ADraft/
|
|
1422
1537
|
|
|
1423
1538
|
# Lookup typed_stage from registry
|
|
1424
1539
|
typed_stage_abbr = determine_stage_abbr(type_value, draft_status_value,
|
|
@@ -1485,9 +1600,29 @@ module Pubid
|
|
|
1485
1600
|
# Redline
|
|
1486
1601
|
attributes[:redline] = true if parsed[:redline]
|
|
1487
1602
|
|
|
1603
|
+
mark_glued_month(attributes)
|
|
1488
1604
|
attributes
|
|
1489
1605
|
end
|
|
1490
1606
|
|
|
1607
|
+
# Glued identity year-month provenance (pubid#517): when the input's
|
|
1608
|
+
# tail is the glued "-YYYY-MM" and the identity carries no draft or
|
|
1609
|
+
# revision suffix, the month belongs to the code's date clause
|
|
1610
|
+
# ("ANSI/IEEE 21-1976-11", "IEEE Std PC2-2016-01") and the renderer
|
|
1611
|
+
# reproduces the glued face. The same month/year attribute shape is
|
|
1612
|
+
# produced by trailing print dates (", 05 2014" — whose numeric form
|
|
1613
|
+
# is its own documented law) and by dash-promoted draft tails
|
|
1614
|
+
# ("/R-x-2011-04"), both of which keep the comma face: the input
|
|
1615
|
+
# shape, checked here at the single choke point every assignment
|
|
1616
|
+
# path converges to, is what distinguishes them (the AIEE
|
|
1617
|
+
# date_separator precedent).
|
|
1618
|
+
def mark_glued_month(attributes)
|
|
1619
|
+
return unless attributes[:month] && attributes[:year] &&
|
|
1620
|
+
attributes[:draft].nil? && attributes[:revision].nil? &&
|
|
1621
|
+
original_input.to_s.match?(/-\d{4}-\d{2}\z/)
|
|
1622
|
+
|
|
1623
|
+
attributes[:month_glued] = true
|
|
1624
|
+
end
|
|
1625
|
+
|
|
1491
1626
|
# Determine stage abbreviation for TYPED_STAGE lookup
|
|
1492
1627
|
# @param type_value [String] the type value (e.g., "Std", "P")
|
|
1493
1628
|
# @param draft_status_value [String] the draft status (e.g., "Unapproved")
|
|
@@ -1638,6 +1773,17 @@ module Pubid
|
|
|
1638
1773
|
# Normalize a leading hyphen ("/D-3.0" -> "3.0"); the draft
|
|
1639
1774
|
# designator is otherwise held verbatim so no digit is lost.
|
|
1640
1775
|
version = version.sub(/\A-/, "") if version
|
|
1776
|
+
|
|
1777
|
+
# FDIS/CDV/… are ISO/IEC stage tokens, not draft ordinals (C1
|
|
1778
|
+
# ruling, testsuite#2). "/DDIS" and "/DFDIS" are hallucinated
|
|
1779
|
+
# concatenations — the designator D does not merge onto a
|
|
1780
|
+
# stage word, and IEEE speak has no such token. The draft of
|
|
1781
|
+
# a stage rides the iso_stage slot, which Draft#to_s renders
|
|
1782
|
+
# as the D= designator face ("…/D=DIS-2020").
|
|
1783
|
+
if version.match?(/\A(FDIS|FCD|CDV|DIS|CD|WD|PWI|NP)\z/)
|
|
1784
|
+
iso_stage = version
|
|
1785
|
+
version = nil
|
|
1786
|
+
end
|
|
1641
1787
|
end
|
|
1642
1788
|
|
|
1643
1789
|
# The PARG capture carries its separator (".12", the #471
|
|
@@ -1649,7 +1795,7 @@ module Pubid
|
|
|
1649
1795
|
|
|
1650
1796
|
# The compound both-systems form (docs/IEEE-DRAFT-STAGES.md
|
|
1651
1797
|
# §1.3): the stage half of "=DDIS.3".
|
|
1652
|
-
iso_stage
|
|
1798
|
+
iso_stage ||= extract_value(draft_data[:draft_iso_stage]) if draft_data[:draft_iso_stage]
|
|
1653
1799
|
iso_iteration = extract_value(draft_data[:draft_iso_iteration]) if draft_data[:draft_iso_iteration]
|
|
1654
1800
|
|
|
1655
1801
|
# Extract date information from draft data
|
|
@@ -1674,9 +1820,12 @@ module Pubid
|
|
|
1674
1820
|
version = extract_value(draft_data)
|
|
1675
1821
|
end
|
|
1676
1822
|
|
|
1823
|
+
# A stage-token draft's month rides the D= designator zero-padded
|
|
1824
|
+
# ("-202007", the pubid#203 convention) — it must not drop.
|
|
1825
|
+
|
|
1677
1826
|
# Create Draft component object if we have version info (or a
|
|
1678
1827
|
# compound stage half without an ordinal, "D=CDV:2020")
|
|
1679
|
-
if version || draft_data.is_a?(Hash) && draft_data[:draft_iso_stage]
|
|
1828
|
+
if version || iso_stage || draft_data.is_a?(Hash) && draft_data[:draft_iso_stage]
|
|
1680
1829
|
draft_obj = Components::Draft.new(
|
|
1681
1830
|
version: version,
|
|
1682
1831
|
revision: revision,
|
|
@@ -44,7 +44,11 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
44
44
|
self.version = version
|
|
45
45
|
self.revision = revision
|
|
46
46
|
self.year = year
|
|
47
|
-
|
|
47
|
+
# The canonical month form is the IEEE crawl abbreviation
|
|
48
|
+
# (C2 ruling: "Aug 2007" and "August 2007" are the same
|
|
49
|
+
# document, so the model normalizes and matches? unifies the
|
|
50
|
+
# spellings; the long face spells the name back out).
|
|
51
|
+
self.original_month = month && CANONICAL_ABBREVIATIONS[month.sub(/\.\z/, "")] || month
|
|
48
52
|
self.month = convert_month(month)
|
|
49
53
|
self.day = day
|
|
50
54
|
# The grammar's ordered alternation captures the stage WITH its
|
|
@@ -58,6 +62,16 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
58
62
|
self.iso_iteration = iso_iteration
|
|
59
63
|
end
|
|
60
64
|
|
|
65
|
+
# Canonical month spelling: the crawl abbreviation. Full names
|
|
66
|
+
# normalize onto these ("August" → "Aug"); "September" keeps its
|
|
67
|
+
# IEEE "Sept" form, so the 3-letter "Sep" folds onto it too.
|
|
68
|
+
CANONICAL_ABBREVIATIONS = {
|
|
69
|
+
"January" => "Jan", "February" => "Feb", "March" => "Mar",
|
|
70
|
+
"April" => "Apr", "June" => "Jun", "July" => "Jul",
|
|
71
|
+
"August" => "Aug", "September" => "Sept", "October" => "Oct",
|
|
72
|
+
"November" => "Nov", "December" => "Dec", "Sep" => "Sept",
|
|
73
|
+
}.freeze
|
|
74
|
+
|
|
61
75
|
# Month names as an alternation, longest-first so "September" wins over
|
|
62
76
|
# "Sep"; each may carry a trailing period ("Sept."). Used to split a
|
|
63
77
|
# rendered draft's trailing date back out.
|
|
@@ -67,7 +81,7 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
67
81
|
private_constant :MONTH_ALTERNATION
|
|
68
82
|
|
|
69
83
|
DATE_SUFFIX =
|
|
70
|
-
/(?:(, | )(#{MONTH_ALTERNATION})(?: (\d{1,2}))?(?:, | )| )((?:19|20)\d{2}[a-z]{0,2})\z/
|
|
84
|
+
/(?:(, | )(#{MONTH_ALTERNATION})(?: (\d{1,2}))?(?:, | )|, | )((?:19|20)\d{2}[a-z]{0,2})\z/
|
|
71
85
|
private_constant :DATE_SUFFIX
|
|
72
86
|
|
|
73
87
|
# Parse a rendered draft such as "/D3", "/D3.4", "/D7 Jul 2019", or a
|
|
@@ -151,6 +165,15 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
151
165
|
end if revision
|
|
152
166
|
|
|
153
167
|
if year
|
|
168
|
+
if iso_stage
|
|
169
|
+
# The D= designator face dash-joins its date in IEEE's
|
|
170
|
+
# convention: the year, and a draft month rides the
|
|
171
|
+
# designator zero-padded ("D=FDIS-201008", pubid#203).
|
|
172
|
+
result += "-#{year}"
|
|
173
|
+
result += format("%02d", month.to_i) if month
|
|
174
|
+
return result
|
|
175
|
+
end
|
|
176
|
+
|
|
154
177
|
# Use original month format to preserve abbreviated vs full names
|
|
155
178
|
display_month = original_month
|
|
156
179
|
|
|
@@ -173,7 +196,10 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
173
196
|
", #{year}"
|
|
174
197
|
end
|
|
175
198
|
else
|
|
176
|
-
|
|
199
|
+
# The year-only date joins with its comma - the grammar's
|
|
200
|
+
# comma-year draft tail (pubid-grammar 17244fc) - so the
|
|
201
|
+
# render re-parses through the same clause.
|
|
202
|
+
result += ", #{year}"
|
|
177
203
|
end
|
|
178
204
|
end
|
|
179
205
|
|
|
@@ -38,6 +38,12 @@ module Pubid
|
|
|
38
38
|
attribute :revision, :string
|
|
39
39
|
attribute :edition, :string # Edition 1.0
|
|
40
40
|
attribute :month, :string
|
|
41
|
+
# Provenance flag (pubid#517): the month arrived glued to the identity
|
|
42
|
+
# year on the code ("ANSI/IEEE 21-1976-11", grammar
|
|
43
|
+
# date_with_month_numeric) rather than as a trailing ", 11 1976"
|
|
44
|
+
# print date. Serialization round-trips it so to_s reproduces the
|
|
45
|
+
# glued face.
|
|
46
|
+
attribute :month_glued, :boolean, default: -> { false }
|
|
41
47
|
attribute :day, :string
|
|
42
48
|
attribute :redline, :boolean, default: -> { false }
|
|
43
49
|
attribute :amendments, Identifier, collection: true # Amendment identifiers
|
|
@@ -235,6 +241,7 @@ module Pubid
|
|
|
235
241
|
Identifiers::Nesc::Draft,
|
|
236
242
|
Identifiers::Nesc::Edition,
|
|
237
243
|
Identifiers::Nesc::Handbook,
|
|
244
|
+
Identifiers::Nesc::Preprint,
|
|
238
245
|
Identifiers::Nesc::Redline,
|
|
239
246
|
Identifiers::Nesc::Standard,
|
|
240
247
|
]
|
|
@@ -159,8 +159,13 @@ module Pubid
|
|
|
159
159
|
|
|
160
160
|
# The P project marker is identity-bearing and prints on both
|
|
161
161
|
# faces (the standing trademark_leaf_to_s_spec contract:
|
|
162
|
-
# "ISO/IEC/IEEE P26511:2018").
|
|
162
|
+
# "ISO/IEC/IEEE P26511:2018"). A P-prefixed joint project
|
|
163
|
+
# prints its parts dot-joined on the ISO face ("ISO/IEEE DIS
|
|
164
|
+
# P11073.10418", #216); a plain ISO/IEC number keeps the
|
|
165
|
+
# printed separator ("IEC/IEEE FDIS 60079-30-2", "ISO/IEC
|
|
166
|
+
# 8802-3").
|
|
163
167
|
code_str = code.to_s
|
|
168
|
+
code_str = code_str.tr("-", ".") if code_str.start_with?("P")
|
|
164
169
|
code_str += mark unless code_str.empty?
|
|
165
170
|
parts << code_str if code_str && !code_str.empty?
|
|
166
171
|
|
|
@@ -172,6 +177,9 @@ module Pubid
|
|
|
172
177
|
if parenthetical_content&.match?(%r{\A[A-Z](?:\s*[/&]\s*[A-Z])*\z})
|
|
173
178
|
result += " (#{parenthetical_content})"
|
|
174
179
|
end
|
|
180
|
+
# The redline marker is identity — the joint ISO print spells it
|
|
181
|
+
# with the space-dash form ("15289:2015(E) - Redline", pubid#215).
|
|
182
|
+
result += " - Redline" if redline
|
|
175
183
|
|
|
176
184
|
result
|
|
177
185
|
end
|
|
@@ -200,6 +208,9 @@ module Pubid
|
|
|
200
208
|
# Publishers (slash-separated)
|
|
201
209
|
parts << publishers.join("/") if publishers && !publishers.empty?
|
|
202
210
|
|
|
211
|
+
# A status word ("Unapproved") marks the draft (pubid#318)
|
|
212
|
+
parts << draft_status if draft_status
|
|
213
|
+
|
|
203
214
|
# Build code part — the P-state prints as spelled (P = project
|
|
204
215
|
# draft; no P = standard). Never added or stripped.
|
|
205
216
|
code_str = code.to_s
|
|
@@ -230,7 +241,8 @@ module Pubid
|
|
|
230
241
|
# ("D=CD.2" — docs/IEEE-DRAFT-STAGES.md §1.3).
|
|
231
242
|
stage = iso_stage.match(/\A([A-Z]+?)(\d+)\z/)
|
|
232
243
|
code_str += stage ? "/D=#{stage[1]}.#{stage[2]}" : "/D=#{iso_stage}"
|
|
233
|
-
elsif typed_stage&.ieee_draft_equivalent
|
|
244
|
+
elsif typed_stage&.ieee_draft_equivalent &&
|
|
245
|
+
!code_str.start_with?(typed_stage.ieee_draft_equivalent)
|
|
234
246
|
code_str += "/#{typed_stage.ieee_draft_equivalent}"
|
|
235
247
|
end
|
|
236
248
|
|
|
@@ -241,6 +253,7 @@ module Pubid
|
|
|
241
253
|
result = parts.join(" ")
|
|
242
254
|
result += "-#{year}" if year && !@designator_carries_year &&
|
|
243
255
|
!ieee_draft.to_s.end_with?("-#{year}")
|
|
256
|
+
result += " - Redline" if redline
|
|
244
257
|
|
|
245
258
|
result
|
|
246
259
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ieee
|
|
5
|
+
module Identifiers
|
|
6
|
+
module Nesc
|
|
7
|
+
# Preprint NESC identifier — the draft stage preceding a C2 edition.
|
|
8
|
+
# "Preprint" is a draft stage (the NESC's own terminology for its
|
|
9
|
+
# pre-edition drafts), not a variant marker: the document IS a draft
|
|
10
|
+
# of the C2 code, distinct from the published edition.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# nesc = Pubid::Ieee.parse("IEEE Std C2.2012.Preprint")
|
|
14
|
+
# nesc.to_s # => "IEEE Std C2.2012.Preprint"
|
|
15
|
+
class Preprint < Base
|
|
16
|
+
include Pubid::Ieee::Identifiers::CodeNumber
|
|
17
|
+
|
|
18
|
+
def self.polymorphic_name
|
|
19
|
+
"pubid:ieee:nesc-preprint"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def draft?
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Render preprint identifier. The canonical spelling is dotted
|
|
27
|
+
# (C2.2012.Preprint); the dash spelling is a non-normalized alias.
|
|
28
|
+
#
|
|
29
|
+
# @param trademark [Boolean] append the IEEE trademark symbol (™/®)
|
|
30
|
+
# @return [String] IEEE Std C2.YYYY.Preprint
|
|
31
|
+
def to_s(trademark: false, **opts)
|
|
32
|
+
body = ["C2", year, "Preprint"].compact.join(".")
|
|
33
|
+
result = ["IEEE Std", body].join(" ")
|
|
34
|
+
result += trademark_symbol if trademark
|
|
35
|
+
annotate_plain_render(result, **opts)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -8,6 +8,7 @@ module Pubid
|
|
|
8
8
|
autoload :Draft, "#{__dir__}/nesc/draft"
|
|
9
9
|
autoload :Edition, "#{__dir__}/nesc/edition"
|
|
10
10
|
autoload :Handbook, "#{__dir__}/nesc/handbook"
|
|
11
|
+
autoload :Preprint, "#{__dir__}/nesc/preprint"
|
|
11
12
|
autoload :Redline, "#{__dir__}/nesc/redline"
|
|
12
13
|
autoload :Standard, "#{__dir__}/nesc/standard"
|
|
13
14
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Ieee
|
|
5
|
+
# The long face (C2 ruling): one uniform format dimension for every
|
|
6
|
+
# IEEE identifier. Expands the type words an identifier actually
|
|
7
|
+
# carries — Std → Standard on a published standard — and spells
|
|
8
|
+
# draft months out ("August 2007"). A draft carries no Std/Standard
|
|
9
|
+
# word, so both faces render `Draft`; there are no draft-specific
|
|
10
|
+
# render rules.
|
|
11
|
+
class LongRenderer < Renderer
|
|
12
|
+
def render(context: nil, **opts)
|
|
13
|
+
@long = true
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -88,6 +88,11 @@ module Pubid
|
|
|
88
88
|
# @param parsed_hash [Hash] Parsed attributes
|
|
89
89
|
# @return [Class] Identifier class to instantiate
|
|
90
90
|
def determine_identifier_class(parsed_hash)
|
|
91
|
+
# Preprint — a draft STAGE of the C2 code (checked before the
|
|
92
|
+
# Standard route below: the c2-preprint tree carries :code "C2"
|
|
93
|
+
# too, and the verbose proposal forms carry none).
|
|
94
|
+
return Identifiers::Nesc::Preprint if parsed_hash[:preprint]
|
|
95
|
+
|
|
91
96
|
# Draft identifiers
|
|
92
97
|
return Identifiers::Nesc::Draft if parsed_hash[:draft]
|
|
93
98
|
|
data/lib/pubid/ieee/parser.rb
CHANGED
|
@@ -735,10 +735,19 @@ module Pubid
|
|
|
735
735
|
(slash >> str("Amd") >> (dot | space).maybe >>
|
|
736
736
|
digits.as(:amd_number) >>
|
|
737
737
|
((str(":") | dash) >> year_digits.as(:amd_year)).maybe).maybe >>
|
|
738
|
+
# Optional corrigendum tail, the ISO print's dotted spelling
|
|
739
|
+
# (pubid#215): "8802-1AC:2018/Cor.1:2020(E)". The shared
|
|
740
|
+
# corrigendum rule accepts the slash/dot/colon separators; the
|
|
741
|
+
# flat tree routes through build_flat_corrigendum.
|
|
742
|
+
corrigendum.maybe >>
|
|
738
743
|
# Optional edition, from relaton's "/E-<n>" suffix normalized to
|
|
739
744
|
# "Edition <n>.0[ YYYY]" (nil-residue hand-off item 1).
|
|
740
745
|
edition.maybe >>
|
|
741
746
|
revision_suffix.maybe >>
|
|
747
|
+
# A redline is a distinct document of the joint ISO print
|
|
748
|
+
# (pubid#215): "15289:2015(E) - Redline". Same flag semantics as
|
|
749
|
+
# the generic rules - the builder sets redline: true.
|
|
750
|
+
redline.maybe >>
|
|
742
751
|
# Published joint docs print a language marker, after either the
|
|
743
752
|
# year or the amendment tail: "9945:2009(E)", "...Amd.1:2014(E)".
|
|
744
753
|
# The crawl sometimes spaces it ("…(E), January 2017" family,
|
|
@@ -1465,10 +1474,6 @@ module Pubid
|
|
|
1465
1474
|
cleaned = "IEEE P#{cleaned}"
|
|
1466
1475
|
end
|
|
1467
1476
|
|
|
1468
|
-
# Part D: Suffix Normalization
|
|
1469
|
-
# 5. "/Preprint" -> remove (data quality - not standard suffix)
|
|
1470
|
-
cleaned = cleaned.gsub(/\/Preprint\b/, "")
|
|
1471
|
-
|
|
1472
1477
|
# Part E: Relationship Text Normalization
|
|
1473
1478
|
# 6. "Proposed Revision of" -> "Revision of"
|
|
1474
1479
|
cleaned = cleaned.gsub("Proposed Revision of", "Revision of")
|