pubid 2.0.0.pre.alpha.30 → 2.0.0.pre.alpha.31

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.
@@ -316,7 +316,11 @@ module Pubid
316
316
  end
317
317
  end
318
318
  end
319
- if dash && parsed_hash[:year].nil?
319
+ # The draft's own dash date embeds onto the draft even when a
320
+ # base identity year is present ("…-2011/D4-2015-07": the 2011
321
+ # is the base's year, the 2015-07 the draft's); only the
322
+ # root-year assignment waits for an unoccupied year slot.
323
+ if dash
320
324
  joined = drafts.filter_map { |d| d.is_a?(Hash) ? d[:draft_version] : nil }
321
325
  .map { |v| v.is_a?(Hash) ? v[:value] : v.to_s }.join
322
326
  bare_joint_draft = parsed_hash[:joint_publishers] &&
@@ -335,7 +339,7 @@ module Pubid
335
339
  [joined, dash[:dash_year], dash[:dash_month]].compact.join("-")
336
340
  dash.delete(:dash_year)
337
341
  dash.delete(:dash_month)
338
- elsif dash[:dash_month] || dash_led
342
+ elsif (dash[:dash_month] || dash_led) && parsed_hash[:year].nil?
339
343
  parsed_hash[:year] = dash[:dash_year]
340
344
  parsed_hash[:month] = dash[:dash_month]
341
345
  else
@@ -955,12 +959,23 @@ module Pubid
955
959
  # exempt: their canonical is the ISO face, which prints the
956
960
  # date from the identity slots (", March 2017", pubid#216).
957
961
  if parsed[:draft_month] && parsed[:iso_stage].nil?
958
- draft = Components::Draft.new(
959
- version: draft_ver,
960
- month: extract_value(parsed[:draft_month]),
961
- year: extract_value(parsed[:draft_year]))
962
- draft.comma_before_month = true
963
- attributes[:draft] = draft.to_s.sub(%r{\A/}, "")
962
+ dm = extract_value(parsed[:draft_month]).to_s
963
+ dy = extract_value(parsed[:draft_year]).to_s
964
+ num = REV_MONTH_NUMBERS[dm.delete(".")]
965
+ if attributes[:publishers] == %w[IEEE CSA] && num && !dy.empty?
966
+ # The joint IEEE/CSA drafts glue their date into the
967
+ # designator with the month numeric (pubid ruling
968
+ # 2026-10-14: no comma dates on these rows).
969
+ draft = Components::Draft.new(version: "#{draft_ver}-#{dy}-#{num}")
970
+ attributes[:draft] = draft.to_s.sub(%r{\A/}, "")
971
+ else
972
+ draft = Components::Draft.new(
973
+ version: draft_ver,
974
+ month: dm,
975
+ year: dy)
976
+ draft.comma_before_month = true
977
+ attributes[:draft] = draft.to_s.sub(%r{\A/}, "")
978
+ end
964
979
  attributes.delete(:year) if parsed[:year].nil?
965
980
  attributes.delete(:month) if parsed[:month].nil?
966
981
  elsif parsed[:draft_year] && parsed[:iso_stage].nil?
@@ -971,6 +986,19 @@ module Pubid
971
986
  draft_year = extract_value(parsed[:draft_year]).to_s.sub(/\A[, ]+/, "")
972
987
  attributes[:draft] = "D#{draft_ver}, #{draft_year}"
973
988
  attributes.delete(:year) if parsed[:year].nil?
989
+ elsif attributes[:publishers] == %w[IEEE CSA] &&
990
+ parsed[:iso_stage].nil? &&
991
+ extract_value(parsed[:year]).to_s.match?(/\A(19|20)\d\d\z/) &&
992
+ extract_value(parsed[:month]).to_s.match?(/\A\d{1,2}\z/)
993
+ # The glued face re-parses with the date in the identity
994
+ # slots ("D2-2016-09" -> year/month + a bare D2): it
995
+ # normalizes back onto the draft-embedded date so the
996
+ # round trip closes on the CSA canonical.
997
+ draft = Components::Draft.new(
998
+ version: "#{draft_ver}-#{extract_value(parsed[:year])}-#{extract_value(parsed[:month])}")
999
+ attributes[:draft] = draft.to_s.sub(%r{\A/}, "")
1000
+ attributes.delete(:year)
1001
+ attributes.delete(:month)
974
1002
  else
975
1003
  attributes[:ieee_draft] = "D#{draft_ver}"
976
1004
  end
@@ -1850,13 +1878,18 @@ module Pubid
1850
1878
  month_slice = draft_data[:month]
1851
1879
  month = extract_value(month_slice) if month_slice
1852
1880
  year = extract_value(draft_data[:year]) if draft_data[:year]
1881
+ # The apostrophe-year catalogue convention ("P1484.20.1/D7,
1882
+ # May 07"): the 2-digit year expands with the <30 pivot so the
1883
+ # hash carries an unambiguous year.
1884
+ year = "#{year.to_i < 30 ? 20 : 19}#{year}" if year.to_s.match?(/\A\d{2}\z/)
1853
1885
  day = extract_value(draft_data[:day]) if draft_data[:day]
1854
1886
 
1855
1887
  # A REV-carrying draft embeds its print date into the designator
1856
1888
  # with the month canonicalized numeric (pubid ruling 2026-10-14):
1857
1889
  # "P802.11-REVmc/D8.0, Aug 2016" renders ".../D8.0-2016-08".
1858
1890
  # Drafts without a REV keep the comma face.
1859
- if (attributes[:revision] || attributes[:rev_bare]) && month && year
1891
+ if (attributes[:revision] || attributes[:rev_bare] ||
1892
+ attributes[:cor_number] || attributes[:cor_year]) && month && year
1860
1893
  number = REV_MONTH_NUMBERS[month.to_s.delete(".")]
1861
1894
  if number && version
1862
1895
  version = "#{version}-#{year}-#{number}"
@@ -1991,8 +2024,17 @@ module Pubid
1991
2024
  end
1992
2025
 
1993
2026
  if param_data[:revision_of]
1994
- attributes[:revision_of] =
1995
- extract_value(param_data[:revision_of])
2027
+ target = extract_value(param_data[:revision_of]).to_s.strip
2028
+ begin
2029
+ # The model types revision_of as an Identifier (the printed
2030
+ # target parses as one); feeding the raw string crashes
2031
+ # to_hash with Lutaml::Model::IncorrectModelError.
2032
+ attributes[:revision_of] = Identifier.parse(target)
2033
+ rescue Pubid::Errors::ParseError, StandardError
2034
+ # An unparseable printed target stays on the parenthetical
2035
+ # surface instead of poisoning the hash.
2036
+ attributes[:parenthetical_content] ||= target
2037
+ end
1996
2038
  end
1997
2039
  if param_data[:amendment_to]
1998
2040
  attributes[:amendment_to] =
@@ -1273,6 +1273,43 @@ module Pubid
1273
1273
  cleaned = cleaned.gsub("&amp;amp;", "&") # Double-encoded ampersand
1274
1274
  cleaned = cleaned.gsub("&amp;", "&") # Single-encoded ampersand
1275
1275
 
1276
+ # The joint IEEE/CSA catalogue spells the type word before the
1277
+ # project number ("IEEE/CSA Draft P844.1/D2, Sept, 2016"): the P
1278
+ # already carries the project semantics (docs/IEEE-DRAFT-STAGES.md
1279
+ # §1.1), so the redundant word drops and the joint route parses.
1280
+ cleaned = cleaned.gsub(%r{IEEE/CSA Draft (P[A-Z0-9])}, 'IEEE/CSA \1')
1281
+
1282
+ # The corrigendum's own draft follows the ordinal after a comma
1283
+ # ("P11073-10418-2011/Cor 1, D4, July 2015"): re-spell the comma as
1284
+ # the draft separator so the cor route's draft slot reaches it.
1285
+ cleaned = cleaned.gsub(%r{/Cor(?:rigendum)? (\d+), (D[A-Z0-9])}, '/Cor \1/\2')
1286
+
1287
+ # The corrigendum's own draft rides before the ordinal in the
1288
+ # house order ("PC37.101-2006/D2, 2007/Cor. 1"): the catalogue
1289
+ # spellings "…/Cor 1, D4, July 2015" and "…/Cor 1-201x/D5,
1290
+ # April 2012" re-order into it, with the draft's date glued
1291
+ # -YYYY-MM (pubid ruling 2026-10-14: no comma dates).
1292
+ cleaned = cleaned.gsub(
1293
+ %r{/Cor(?:rigendum)? (\d+(?:-[0-9xX]{4})?)/(D[A-Z0-9][^,]*), ([A-Za-z]+) (\d{4})}
1294
+ ) do
1295
+ month = ::Pubid::Ieee::Builder::REV_MONTH_NUMBERS[Regexp.last_match(3).capitalize]
1296
+ if month
1297
+ "/#{Regexp.last_match(2)}-#{Regexp.last_match(4)}-#{month}/Cor. #{Regexp.last_match(1)}"
1298
+ else
1299
+ Regexp.last_match(0)
1300
+ end
1301
+ end
1302
+ cleaned = cleaned.gsub(
1303
+ %r{/Cor(?:rigendum)? (\d+), (D[A-Z0-9][^,]*), ([A-Za-z]+) (\d{4})}
1304
+ ) do
1305
+ month = ::Pubid::Ieee::Builder::REV_MONTH_NUMBERS[Regexp.last_match(3).capitalize]
1306
+ if month
1307
+ "/#{Regexp.last_match(2)}-#{Regexp.last_match(4)}-#{month}/Cor. #{Regexp.last_match(1)}"
1308
+ else
1309
+ Regexp.last_match(0)
1310
+ end
1311
+ end
1312
+
1276
1313
  # NEW Phase 1: Fix number spacing issues (e.g., "C57.1 2.25" → "C57.12.25")
1277
1314
  # This handles cases where a space appears in the middle of a number
1278
1315
  cleaned = cleaned.gsub(/(\d+\.\d+)\s+(\d+\.)/, '\1\2')
@@ -195,7 +195,8 @@ module Pubid
195
195
  glued_month = id.month.to_s.match?(/\A\d{1,2}\z/)
196
196
  year_on_code = id.year && !id.edition &&
197
197
  (!id.month || glued_month) &&
198
- (!id.draft_obj || id.draft_obj&.year)
198
+ (!id.draft_obj || id.draft_obj&.year ||
199
+ id.draft_obj&.version.to_s.match?(/-\d{4}-\d{2}\z/))
199
200
  result += "-#{id.year}" if year_on_code
200
201
  result += "-#{id.month}" if glued_month
201
202
 
data/lib/pubid/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pubid
4
- VERSION = "2.0.0.pre.alpha.30"
4
+ VERSION = "2.0.0.pre.alpha.31"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.alpha.30
4
+ version: 2.0.0.pre.alpha.31
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-14 00:00:00.000000000 Z
11
+ date: 2026-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model