pubid 2.0.0.pre.alpha.28 → 2.0.0.pre.alpha.30
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/parg/cen_cenelec.json +1 -1
- data/data/parg/cen_cenelec.parg +12 -4
- data/data/parg/evs.json +1 -1
- data/data/parg/ieee.json +1 -1
- data/data/parg/nesc.parg +16 -1
- data/data/parg/nist.json +1 -1
- data/lib/pubid/cen_cenelec/builder.rb +10 -0
- data/lib/pubid/cen_cenelec/identifier.rb +2 -0
- data/lib/pubid/cen_cenelec/renderer.rb +4 -1
- data/lib/pubid/evs/builder.rb +77 -9
- data/lib/pubid/evs/identifier.rb +29 -7
- data/lib/pubid/evs/identifiers/estonian_standard.rb +15 -0
- data/lib/pubid/evs/identifiers/international_adoption.rb +16 -0
- data/lib/pubid/evs/identifiers.rb +2 -0
- data/lib/pubid/evs/renderer.rb +43 -10
- data/lib/pubid/evs/urn_generator.rb +46 -6
- data/lib/pubid/evs/urn_parser.rb +94 -37
- data/lib/pubid/evs.rb +13 -2
- data/lib/pubid/ieee/builder.rb +95 -4
- data/lib/pubid/ieee/identifiers/base.rb +14 -1
- data/lib/pubid/ieee/identifiers/joint_development.rb +4 -0
- 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/nesc/builder.rb +5 -0
- data/lib/pubid/ieee/parser.rb +9 -4
- data/lib/pubid/ieee/renderer.rb +17 -4
- data/lib/pubid/ieee/urn_generator.rb +7 -0
- data/lib/pubid/nist/parser.rb +23 -8
- data/lib/pubid/nist/preprocessor.rb +15 -0
- data/lib/pubid/version.rb +1 -1
- metadata +9 -6
data/lib/pubid/ieee/builder.rb
CHANGED
|
@@ -5,6 +5,17 @@ module Pubid
|
|
|
5
5
|
# Builder class for constructing IEEE identifier scheme from parsed data
|
|
6
6
|
# Single Responsibility: Transform parsed data into identifier objects
|
|
7
7
|
class Builder
|
|
8
|
+
# The month_name vocabulary the REV date embed canonicalizes numeric
|
|
9
|
+
# (the parg rule's exact spellings, dots already stripped).
|
|
10
|
+
REV_MONTH_NUMBERS = {
|
|
11
|
+
"January" => "01", "February" => "02", "March" => "03",
|
|
12
|
+
"April" => "04", "May" => "05", "June" => "06", "July" => "07",
|
|
13
|
+
"August" => "08", "September" => "09", "Sept" => "09",
|
|
14
|
+
"October" => "10", "November" => "11", "December" => "12",
|
|
15
|
+
"Jan" => "01", "Feb" => "02", "Mar" => "03", "Apr" => "04",
|
|
16
|
+
"Jun" => "06", "Jul" => "07", "Aug" => "08", "Sep" => "09",
|
|
17
|
+
"Oct" => "10", "Nov" => "11", "Dec" => "12",
|
|
18
|
+
}.freeze
|
|
8
19
|
attr_accessor :original_input
|
|
9
20
|
attr_reader :identifier_class
|
|
10
21
|
|
|
@@ -287,6 +298,24 @@ module Pubid
|
|
|
287
298
|
end
|
|
288
299
|
dash = parsed_hash[:dash_year] ? parsed_hash : nil
|
|
289
300
|
dash ||= drafts.find { |d| d.is_a?(Hash) && d[:dash_year] }
|
|
301
|
+
if dash.nil? && parsed_hash[:draft]
|
|
302
|
+
# A numeric month trailing a draft is the draft's own date: it
|
|
303
|
+
# embeds in the designator ("D09, 04 2011" -> "D09-2011-04")
|
|
304
|
+
# rather than printing the long-format comma face (a month name
|
|
305
|
+
# keeps the comma, "D7.2, Nov 2006") — pubid ruling 2026-10-13.
|
|
306
|
+
m = parsed_hash[:month] || parsed_hash[:trailing_month]
|
|
307
|
+
y = parsed_hash[:year] || parsed_hash[:trailing_year]
|
|
308
|
+
if m.to_s.match?(/\A\d{1,2}\z/) && y
|
|
309
|
+
host = drafts.find { |d| d.is_a?(Hash) && d[:draft_version] }
|
|
310
|
+
if host
|
|
311
|
+
host[:draft_version] = [host[:draft_version], y, m].compact.join("-")
|
|
312
|
+
parsed_hash.delete(:month)
|
|
313
|
+
parsed_hash.delete(:year)
|
|
314
|
+
parsed_hash.delete(:trailing_month)
|
|
315
|
+
parsed_hash.delete(:trailing_year)
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
290
319
|
if dash && parsed_hash[:year].nil?
|
|
291
320
|
joined = drafts.filter_map { |d| d.is_a?(Hash) ? d[:draft_version] : nil }
|
|
292
321
|
.map { |v| v.is_a?(Hash) ? v[:value] : v.to_s }.join
|
|
@@ -297,6 +326,15 @@ module Pubid
|
|
|
297
326
|
dash_led = joined.start_with?("-")
|
|
298
327
|
if bare_joint_draft && dash_led
|
|
299
328
|
parsed_hash[:part] = { value: dash[:dash_year] }
|
|
329
|
+
elsif dash[:dash_month] &&
|
|
330
|
+
(host = drafts.find { |d| d.is_a?(Hash) && d[:draft_version] })
|
|
331
|
+
# The draft's own numeric date embeds in the designator
|
|
332
|
+
# ("D2-2015-04") — the "D2, 04 2015" comma spelling
|
|
333
|
+
# normalizes onto it (pubid ruling 2026-10-13).
|
|
334
|
+
host[:draft_version] =
|
|
335
|
+
[joined, dash[:dash_year], dash[:dash_month]].compact.join("-")
|
|
336
|
+
dash.delete(:dash_year)
|
|
337
|
+
dash.delete(:dash_month)
|
|
300
338
|
elsif dash[:dash_month] || dash_led
|
|
301
339
|
parsed_hash[:year] = dash[:dash_year]
|
|
302
340
|
parsed_hash[:month] = dash[:dash_month]
|
|
@@ -307,9 +345,16 @@ module Pubid
|
|
|
307
345
|
# draft version misses the D-registry), no separate year.
|
|
308
346
|
host = drafts.find { |d| d.is_a?(Hash) && d[:draft_version] }
|
|
309
347
|
if host
|
|
310
|
-
|
|
348
|
+
# The draft's own numeric date embeds in the designator
|
|
349
|
+
# ("D9-2006", and with its month "D2-2015-04") — the
|
|
350
|
+
# "D2, 04 2015" comma spelling normalizes onto it.
|
|
351
|
+
host[:draft_version] =
|
|
352
|
+
[joined, dash[:dash_year], dash[:dash_month]].compact.join("-")
|
|
311
353
|
dash.delete(:dash_year)
|
|
312
354
|
dash.delete(:dash_month)
|
|
355
|
+
# the hyphenated "/D-2-2007" spelling's year the spine
|
|
356
|
+
# captured at top level is the draft's own — vacate it
|
|
357
|
+
parsed_hash.delete(:year) if parsed_hash[:year] == dash[:dash_year]
|
|
313
358
|
else
|
|
314
359
|
parsed_hash[:year] = dash[:dash_year]
|
|
315
360
|
parsed_hash[:month] = dash[:dash_month]
|
|
@@ -511,8 +556,15 @@ module Pubid
|
|
|
511
556
|
# @param parsed_hash [Hash] parsed data with base and supplement info
|
|
512
557
|
# @return [Identifiers::Corrigendum] corrigendum identifier
|
|
513
558
|
def build_corrigendum_supplement(parsed_hash)
|
|
559
|
+
# The `corrigendum_identifier` rule's :base subtree binds as a
|
|
560
|
+
# top-level sequence (an Array of capture hashes — the same shape
|
|
561
|
+
# #build's dispatch merges at line 24) whenever the base carries a
|
|
562
|
+
# multi-capture narrative tail; fold it before reconstruction or
|
|
563
|
+
# reconstruct_base_string's Hash indexing crashes with TypeError.
|
|
564
|
+
base_data = parsed_hash[:base]
|
|
565
|
+
base_data = merge_parsed_array(base_data) if base_data.is_a?(Array)
|
|
514
566
|
# Recursively parse the base identifier reconstructed from the subtree.
|
|
515
|
-
base = Identifier.parse(reconstruct_base_string(
|
|
567
|
+
base = Identifier.parse(reconstruct_base_string(base_data))
|
|
516
568
|
|
|
517
569
|
# Extract corrigendum attributes (parse-tree keys are cor_*; the
|
|
518
570
|
# identifier stores them as the uniform `number`/`year`).
|
|
@@ -873,6 +925,10 @@ module Pubid
|
|
|
873
925
|
end
|
|
874
926
|
attributes[:parenthetical_content] ||= extract_value(parsed[:edition_marker]) if parsed[:edition_marker]
|
|
875
927
|
|
|
928
|
+
# A joint ISO-print redline is a distinct document of the same
|
|
929
|
+
# standard — same flag semantics as the generic path (pubid#215).
|
|
930
|
+
attributes[:redline] = true if parsed[:redline]
|
|
931
|
+
|
|
876
932
|
# Extract edition, from relaton's "/E-<n>" suffix. The grammar's /E
|
|
877
933
|
# alternative captures the bare ordinal (nil-residue hand-off item 1).
|
|
878
934
|
if parsed[:edition]
|
|
@@ -1537,6 +1593,8 @@ module Pubid
|
|
|
1537
1593
|
# Optional attributes (excluding part/subpart since they're in code)
|
|
1538
1594
|
extract_optional(parsed, attributes, :edition)
|
|
1539
1595
|
extract_optional(parsed, attributes, :revision)
|
|
1596
|
+
extract_optional(parsed, attributes, :rev_sep)
|
|
1597
|
+
attributes[:rev_bare] = true if parsed[:rev_bare]
|
|
1540
1598
|
|
|
1541
1599
|
# Month/day - always extract if present (but not if already extracted from year)
|
|
1542
1600
|
unless attributes[:edition_month]
|
|
@@ -1589,9 +1647,29 @@ module Pubid
|
|
|
1589
1647
|
# Redline
|
|
1590
1648
|
attributes[:redline] = true if parsed[:redline]
|
|
1591
1649
|
|
|
1650
|
+
mark_glued_month(attributes)
|
|
1592
1651
|
attributes
|
|
1593
1652
|
end
|
|
1594
1653
|
|
|
1654
|
+
# Glued identity year-month provenance (pubid#517): when the input's
|
|
1655
|
+
# tail is the glued "-YYYY-MM" and the identity carries no draft or
|
|
1656
|
+
# revision suffix, the month belongs to the code's date clause
|
|
1657
|
+
# ("ANSI/IEEE 21-1976-11", "IEEE Std PC2-2016-01") and the renderer
|
|
1658
|
+
# reproduces the glued face. The same month/year attribute shape is
|
|
1659
|
+
# produced by trailing print dates (", 05 2014" — whose numeric form
|
|
1660
|
+
# is its own documented law) and by dash-promoted draft tails
|
|
1661
|
+
# ("/R-x-2011-04"), both of which keep the comma face: the input
|
|
1662
|
+
# shape, checked here at the single choke point every assignment
|
|
1663
|
+
# path converges to, is what distinguishes them (the AIEE
|
|
1664
|
+
# date_separator precedent).
|
|
1665
|
+
def mark_glued_month(attributes)
|
|
1666
|
+
return unless attributes[:month] && attributes[:year] &&
|
|
1667
|
+
attributes[:draft].nil? && attributes[:revision].nil? &&
|
|
1668
|
+
original_input.to_s.match?(/-\d{4}-\d{2}\z/)
|
|
1669
|
+
|
|
1670
|
+
attributes[:month_glued] = true
|
|
1671
|
+
end
|
|
1672
|
+
|
|
1595
1673
|
# Determine stage abbreviation for TYPED_STAGE lookup
|
|
1596
1674
|
# @param type_value [String] the type value (e.g., "Std", "P")
|
|
1597
1675
|
# @param draft_status_value [String] the draft status (e.g., "Unapproved")
|
|
@@ -1632,8 +1710,9 @@ module Pubid
|
|
|
1632
1710
|
|
|
1633
1711
|
if version
|
|
1634
1712
|
# relaton's hyphenated "/D-2" spelling captures the dash inside
|
|
1635
|
-
# draft_version; the stage registry keys on "D2".
|
|
1636
|
-
|
|
1713
|
+
# draft_version; the stage registry keys on "D2". A date-embedded
|
|
1714
|
+
# version ("3-2017-07") keys on its leading ordinal.
|
|
1715
|
+
draft_abbr = "D#{version.to_s.sub(/\A-/, "").sub(/-\d{4}(-\d{2})?\z/, "")}"
|
|
1637
1716
|
# Check if this specific draft stage is in registry
|
|
1638
1717
|
stage = Pubid::Ieee.locate_stage(draft_abbr)
|
|
1639
1718
|
return draft_abbr if stage&.abbr&.include?(draft_abbr)
|
|
@@ -1773,6 +1852,18 @@ module Pubid
|
|
|
1773
1852
|
year = extract_value(draft_data[:year]) if draft_data[:year]
|
|
1774
1853
|
day = extract_value(draft_data[:day]) if draft_data[:day]
|
|
1775
1854
|
|
|
1855
|
+
# A REV-carrying draft embeds its print date into the designator
|
|
1856
|
+
# with the month canonicalized numeric (pubid ruling 2026-10-14):
|
|
1857
|
+
# "P802.11-REVmc/D8.0, Aug 2016" renders ".../D8.0-2016-08".
|
|
1858
|
+
# Drafts without a REV keep the comma face.
|
|
1859
|
+
if (attributes[:revision] || attributes[:rev_bare]) && month && year
|
|
1860
|
+
number = REV_MONTH_NUMBERS[month.to_s.delete(".")]
|
|
1861
|
+
if number && version
|
|
1862
|
+
version = "#{version}-#{year}-#{number}"
|
|
1863
|
+
month = year = day = nil
|
|
1864
|
+
end
|
|
1865
|
+
end
|
|
1866
|
+
|
|
1776
1867
|
# Detect comma before month and space before draft by checking the original input
|
|
1777
1868
|
if original_input
|
|
1778
1869
|
if month
|
|
@@ -36,8 +36,20 @@ module Pubid
|
|
|
36
36
|
# "Rev<id>". `::Pubid::Identifier` has no `revision` attribute, so this is
|
|
37
37
|
# free of the number/stage multi-flavor collision landmine.
|
|
38
38
|
attribute :revision, :string
|
|
39
|
+
# The lettered revision's printed separator ("P802.11-REVmc" keeps its
|
|
40
|
+
# dash; a glued "REVi" stays glued) and the bare-word marker (no id
|
|
41
|
+
# after "Rev" — "802.1AR-Rev/D2.2" keeps "Rev"). pubid ruling
|
|
42
|
+
# 2026-10-14.
|
|
43
|
+
attribute :rev_sep, :string
|
|
44
|
+
attribute :rev_bare, :boolean
|
|
39
45
|
attribute :edition, :string # Edition 1.0
|
|
40
46
|
attribute :month, :string
|
|
47
|
+
# Provenance flag (pubid#517): the month arrived glued to the identity
|
|
48
|
+
# year on the code ("ANSI/IEEE 21-1976-11", grammar
|
|
49
|
+
# date_with_month_numeric) rather than as a trailing ", 11 1976"
|
|
50
|
+
# print date. Serialization round-trips it so to_s reproduces the
|
|
51
|
+
# glued face.
|
|
52
|
+
attribute :month_glued, :boolean, default: -> { false }
|
|
41
53
|
attribute :day, :string
|
|
42
54
|
attribute :redline, :boolean, default: -> { false }
|
|
43
55
|
attribute :amendments, Identifier, collection: true # Amendment identifiers
|
|
@@ -210,7 +222,7 @@ module Pubid
|
|
|
210
222
|
# (renderer.rb's `"Edition #{edition} #{year}-#{edition_month}"`),
|
|
211
223
|
# which survived even though its sibling `year` is already stripped.
|
|
212
224
|
def self.all_parts_edition_keys
|
|
213
|
-
super + %i[revision reaffirmed edition_month]
|
|
225
|
+
super + %i[revision rev_sep rev_bare reaffirmed edition_month]
|
|
214
226
|
end
|
|
215
227
|
|
|
216
228
|
# Inverse of the to_hash compaction: expand a scalar `stage` back into the
|
|
@@ -235,6 +247,7 @@ module Pubid
|
|
|
235
247
|
Identifiers::Nesc::Draft,
|
|
236
248
|
Identifiers::Nesc::Edition,
|
|
237
249
|
Identifiers::Nesc::Handbook,
|
|
250
|
+
Identifiers::Nesc::Preprint,
|
|
238
251
|
Identifiers::Nesc::Redline,
|
|
239
252
|
Identifiers::Nesc::Standard,
|
|
240
253
|
]
|
|
@@ -177,6 +177,9 @@ module Pubid
|
|
|
177
177
|
if parenthetical_content&.match?(%r{\A[A-Z](?:\s*[/&]\s*[A-Z])*\z})
|
|
178
178
|
result += " (#{parenthetical_content})"
|
|
179
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
|
|
180
183
|
|
|
181
184
|
result
|
|
182
185
|
end
|
|
@@ -250,6 +253,7 @@ module Pubid
|
|
|
250
253
|
result = parts.join(" ")
|
|
251
254
|
result += "-#{year}" if year && !@designator_carries_year &&
|
|
252
255
|
!ieee_draft.to_s.end_with?("-#{year}")
|
|
256
|
+
result += " - Redline" if redline
|
|
253
257
|
|
|
254
258
|
result
|
|
255
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
|
|
@@ -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")
|
data/lib/pubid/ieee/renderer.rb
CHANGED
|
@@ -187,14 +187,26 @@ module Pubid
|
|
|
187
187
|
# no draft at all, or a draft that carries its OWN date (the
|
|
188
188
|
# draft+corrigendum family: "PC37.09-1999/D7.2, Nov 2006" -
|
|
189
189
|
# the 1999 is the base's year, the Nov 2006 the draft's).
|
|
190
|
-
|
|
190
|
+
# A numeric identity month is the SHORT format: it keeps the
|
|
191
|
+
# year on the code and appends itself dash-joined, whatever the
|
|
192
|
+
# input spelling ("ANSI/IEEE 21-1976-11" and "IEEE P15026.1,
|
|
193
|
+
# 05 2014" both render glued - pubid#517). The comma face is
|
|
194
|
+
# the LONG format, a month name ("..., May 2014").
|
|
195
|
+
glued_month = id.month.to_s.match?(/\A\d{1,2}\z/)
|
|
196
|
+
year_on_code = id.year && !id.edition &&
|
|
197
|
+
(!id.month || glued_month) &&
|
|
191
198
|
(!id.draft_obj || id.draft_obj&.year)
|
|
192
199
|
result += "-#{id.year}" if year_on_code
|
|
200
|
+
result += "-#{id.month}" if glued_month
|
|
193
201
|
|
|
194
202
|
# Append the numbered/lettered revision inline, in IEEE's native
|
|
195
203
|
# position — right after the code number and before the draft
|
|
196
|
-
# ("P802.16Rev2/D3"). Keeps a revision distinct from its base
|
|
197
|
-
|
|
204
|
+
# ("P802.16Rev2/D3"). Keeps a revision distinct from its base
|
|
205
|
+
# standard. The lettered id keeps its printed separator
|
|
206
|
+
# ("P802.11-REVmc" renders "P802.11-Revmc"); the bare word with
|
|
207
|
+
# no id still prints "Rev" (pubid ruling 2026-10-14).
|
|
208
|
+
result += "#{id.rev_sep}Rev#{id.revision}" if id.revision
|
|
209
|
+
result += "#{id.rev_sep}Rev" if id.rev_bare
|
|
198
210
|
|
|
199
211
|
# Append draft to code - with or without space based on original
|
|
200
212
|
# format. An exactly-IEC/IEEE co-published reference prints only the
|
|
@@ -263,7 +275,8 @@ module Pubid
|
|
|
263
275
|
# An exactly-IEC/IEEE co-published reference drops the comma date
|
|
264
276
|
# entirely (same catalogue-metadata rule as the draft date above):
|
|
265
277
|
# "IEC/IEEE P60076-16, May 2016" prints as "IEC/IEEE 60076-16".
|
|
266
|
-
if id.month && !
|
|
278
|
+
if id.month && !glued_month &&
|
|
279
|
+
!(id.publisher == "IEC" && id.copublisher == ["IEEE"])
|
|
267
280
|
result += ", #{id.month}"
|
|
268
281
|
result += " #{id.day}" if id.day
|
|
269
282
|
if id.year && !id.edition
|
|
@@ -40,6 +40,13 @@ module Pubid
|
|
|
40
40
|
parts << "int"
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# A NESC preprint is a draft-stage document distinct from the
|
|
44
|
+
# published edition it precedes — without this component it would
|
|
45
|
+
# share the edition's URN (urn:ieee:ieee:C2:2012).
|
|
46
|
+
if identifier.is_a?(Identifiers::Nesc::Preprint)
|
|
47
|
+
parts << "preprint"
|
|
48
|
+
end
|
|
49
|
+
|
|
43
50
|
# Conformance is always a ConformanceIdentifier wrapper (special_type
|
|
44
51
|
# "conformance"), never inline on a base standard — the base no longer
|
|
45
52
|
# carries a conf_number attribute, so there is no inline conf part.
|
data/lib/pubid/nist/parser.rb
CHANGED
|
@@ -138,7 +138,11 @@ module Pubid
|
|
|
138
138
|
# Two-letter suffixes: Ur (Unclassified Revised), Ua (Unclassified Amended), Ub-Uj (series variants)
|
|
139
139
|
# Single letter: any letter not followed by excluded keywords
|
|
140
140
|
rule(:number_suffix) do
|
|
141
|
-
(str("U") >> lower_letter) |
|
|
141
|
+
(str("U") >> lower_letter) |
|
|
142
|
+
# An "r" directly followed by a digit is the revision marker (pubid#170),
|
|
143
|
+
# not a suffix — leave it for the second_number/edition rules.
|
|
144
|
+
# The guard sits before the letter so it tests the suffix start itself.
|
|
145
|
+
((str("r") >> digit).absent? >> match("[a-zA-Z]") >> (
|
|
142
146
|
# Match suffixes
|
|
143
147
|
str("ec") |
|
|
144
148
|
str("ndex") |
|
|
@@ -265,7 +269,9 @@ module Pubid
|
|
|
265
269
|
(digits >> str("r") >> digits >> match("[a-zA-Z]")) |
|
|
266
270
|
# NEW: Revision pattern with year (e.g., "126r2013")
|
|
267
271
|
# This handles SP revision format where revision is attached to second_number
|
|
268
|
-
(
|
|
272
|
+
# Dotted minor accepted atomically (pubid#170): "53r4.1" binds id "4.1"
|
|
273
|
+
(digits.as(:number_only) >> str("r") >>
|
|
274
|
+
(digits >> (str(".") >> digits).maybe).as(:edition_id)) |
|
|
269
275
|
# CRPL range with underscore (e.g., "2_3-1A")
|
|
270
276
|
(digits >> str("_") >> digits >> dash >> digits >> upper_letter.maybe) |
|
|
271
277
|
# Letter followed by dash and digits (e.g., "m-5")
|
|
@@ -283,7 +289,9 @@ module Pubid
|
|
|
283
289
|
# For patterns like NIST SP 800-27ra where revision 'ra' is attached directly to number
|
|
284
290
|
(str("r") >> match("[a-zA-Z]")).as(:revision_letter_suffix) |
|
|
285
291
|
# NEW: Simple revision pattern r followed by digits (e.g., "r1", "r2") for trailing revision
|
|
286
|
-
(
|
|
292
|
+
# Dotted minor accepted atomically (pubid#170): "r4.1" binds id "4.1"
|
|
293
|
+
(str("r") >>
|
|
294
|
+
(digits >> (str(".") >> digits).maybe).as(:edition_id)).as(:revision_simple) |
|
|
287
295
|
# Special patterns like "NCNR", "PERMIS", "BFRL"
|
|
288
296
|
str("NCNR") | str("PERMIS") | str("BFRL") |
|
|
289
297
|
# Just capital letters (e.g., "A", "B", "C") - standalone
|
|
@@ -303,15 +311,22 @@ module Pubid
|
|
|
303
311
|
# Enhanced: Support space-separated format from preprocessing (r1 separated from number)
|
|
304
312
|
rule(:edition) do
|
|
305
313
|
# Edition with "e" prefix: e2, e3, e2021 (1-4 digits for ID)
|
|
306
|
-
|
|
314
|
+
# Dotted minor accepted atomically (pubid#170): "e2006.1" binds id "2006.1"
|
|
315
|
+
(space.maybe >> str("e") >>
|
|
316
|
+
(digits >> (str(".") >> digits).maybe).as(:edition_id)).as(:edition_e) |
|
|
307
317
|
# Revision with "r" prefix and SPACE, with letter: r 5A (preserve format)
|
|
308
|
-
|
|
318
|
+
# Dotted minor accepted atomically (pubid#170)
|
|
319
|
+
(space >> str("r") >> (digits >> (str(".") >> digits).maybe).as(:edition_id) >>
|
|
320
|
+
match("[a-zA-Z]").as(:edition_letter)).as(:edition_r_with_space_letter) |
|
|
309
321
|
# Revision with "r" prefix and SPACE: r 5 (preserve format)
|
|
310
|
-
(space >> str("r") >>
|
|
322
|
+
(space >> str("r") >>
|
|
323
|
+
(digits >> (str(".") >> digits).maybe).as(:edition_id)).as(:edition_r_with_space) |
|
|
311
324
|
# Revision with "r" prefix NO space, with letter: r5A (compact format)
|
|
312
|
-
(str("r") >> digits
|
|
325
|
+
(str("r") >> (digits >> (str(".") >> digits).maybe).as(:edition_id) >>
|
|
326
|
+
match("[a-zA-Z]").as(:edition_letter)).as(:edition_r_no_space_letter) |
|
|
313
327
|
# Revision with "r" prefix NO space: r5 (compact format)
|
|
314
|
-
(str("r") >>
|
|
328
|
+
(str("r") >>
|
|
329
|
+
(digits >> (str(".") >> digits).maybe).as(:edition_id)).as(:edition_r_no_space) |
|
|
315
330
|
# Revision with "rev" prefix (verbose): rev2013, rev 2013
|
|
316
331
|
(space.maybe >> str("rev") >> space.maybe >> digits.as(:edition_id)).as(:edition_rev) |
|
|
317
332
|
# Historical with "-" prefix: -2, -3 (ONLY if followed by non-digit or end)
|
|
@@ -76,6 +76,7 @@ module Pubid
|
|
|
76
76
|
normalize_supplement_and_part!
|
|
77
77
|
normalize_version_notation!
|
|
78
78
|
normalize_edition_year_suffix!
|
|
79
|
+
normalize_glued_dotted_edition!
|
|
79
80
|
normalize_revision_with_letter!
|
|
80
81
|
normalize_version_dotted_spaces!
|
|
81
82
|
normalize_update_markers!
|
|
@@ -264,10 +265,24 @@ module Pubid
|
|
|
264
265
|
end
|
|
265
266
|
|
|
266
267
|
# Edition year suffix shorthand: "2006ed." → "e2006".
|
|
268
|
+
# A dotted minor after the dot stays attached (pubid#170): "2006ed.1" → "e2006.1",
|
|
269
|
+
# so the edition id binds atomically instead of corrupting into "e20061".
|
|
267
270
|
def normalize_edition_year_suffix!
|
|
271
|
+
@cleaned = @cleaned.gsub(/(\d{4})ed\.(\d+)/, 'e\1.\2')
|
|
268
272
|
@cleaned = @cleaned.gsub(/(\d{4})ed\./, 'e\1')
|
|
269
273
|
end
|
|
270
274
|
|
|
275
|
+
# A glued dotted e-edition needs the space the spaced form has (pubid#170):
|
|
276
|
+
# "800-53e2.1" → "800-53 e2.1", so the edition rule binds "2.1" atomically.
|
|
277
|
+
# The minor is 1-2 digits — a 4-digit tail is the additional-text year of
|
|
278
|
+
# forms like "NBS CIRC 11e2.1915", which must keep its existing tree.
|
|
279
|
+
# Only dotted e-editions are unglued; the dot-less glued form "800-53e2"
|
|
280
|
+
# keeps its number-bound tree. Mirrors the "v1.1" unglue in
|
|
281
|
+
# normalize_draft_and_volume!.
|
|
282
|
+
def normalize_glued_dotted_edition!
|
|
283
|
+
@cleaned = @cleaned.gsub(/(\d)e(\d+\.\d{1,2})(?!\d)/, '\1 e\2')
|
|
284
|
+
end
|
|
285
|
+
|
|
271
286
|
# Revision attached to a number with optional letter suffix. When
|
|
272
287
|
# a letter suffix is present, keep them together for the
|
|
273
288
|
# second_number grammar rule; otherwise insert a space before
|
data/lib/pubid/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pubid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.0.pre.alpha.
|
|
4
|
+
version: 2.0.0.pre.alpha.30
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
19
|
+
version: '0.8'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
26
|
+
version: '0.8'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: parslet
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -484,6 +484,8 @@ files:
|
|
|
484
484
|
- lib/pubid/evs/builder.rb
|
|
485
485
|
- lib/pubid/evs/identifier.rb
|
|
486
486
|
- lib/pubid/evs/identifiers.rb
|
|
487
|
+
- lib/pubid/evs/identifiers/estonian_standard.rb
|
|
488
|
+
- lib/pubid/evs/identifiers/international_adoption.rb
|
|
487
489
|
- lib/pubid/evs/identifiers/national_adoption.rb
|
|
488
490
|
- lib/pubid/evs/parser.rb
|
|
489
491
|
- lib/pubid/evs/renderer.rb
|
|
@@ -640,6 +642,7 @@ files:
|
|
|
640
642
|
- lib/pubid/ieee/identifiers/nesc/draft.rb
|
|
641
643
|
- lib/pubid/ieee/identifiers/nesc/edition.rb
|
|
642
644
|
- lib/pubid/ieee/identifiers/nesc/handbook.rb
|
|
645
|
+
- lib/pubid/ieee/identifiers/nesc/preprint.rb
|
|
643
646
|
- lib/pubid/ieee/identifiers/nesc/redline.rb
|
|
644
647
|
- lib/pubid/ieee/identifiers/nesc/standard.rb
|
|
645
648
|
- lib/pubid/ieee/identifiers/parenthetical_identifier.rb
|