pubid 2.0.22 → 2.0.24

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/data/parg/calconnect_pfs.json +1 -0
  3. data/data/parg/cen_pfs.json +1 -0
  4. data/data/parg/doi_pfs.json +1 -0
  5. data/data/parg/etsi_pfs.json +1 -0
  6. data/data/parg/iec.json +1 -1
  7. data/data/parg/nist.json +1 -1
  8. data/lib/pubid/calconnect_pfs/builder.rb +35 -0
  9. data/lib/pubid/calconnect_pfs/identifier.rb +84 -0
  10. data/lib/pubid/calconnect_pfs/identifiers/standard.rb +31 -0
  11. data/lib/pubid/calconnect_pfs/identifiers.rb +7 -0
  12. data/lib/pubid/calconnect_pfs/parser.rb +10 -0
  13. data/lib/pubid/calconnect_pfs/pubid_urn_schema.rb +17 -0
  14. data/lib/pubid/calconnect_pfs/renderer.rb +10 -0
  15. data/lib/pubid/calconnect_pfs/urn_generator.rb +30 -0
  16. data/lib/pubid/calconnect_pfs.rb +60 -0
  17. data/lib/pubid/cen_pfs/builder.rb +33 -0
  18. data/lib/pubid/cen_pfs/identifier.rb +64 -0
  19. data/lib/pubid/cen_pfs/identifiers/european_norm.rb +31 -0
  20. data/lib/pubid/cen_pfs/identifiers.rb +7 -0
  21. data/lib/pubid/cen_pfs/parser.rb +10 -0
  22. data/lib/pubid/cen_pfs/pubid_urn_schema.rb +15 -0
  23. data/lib/pubid/cen_pfs/renderer.rb +10 -0
  24. data/lib/pubid/cen_pfs/urn_generator.rb +12 -0
  25. data/lib/pubid/cen_pfs.rb +71 -0
  26. data/lib/pubid/doi_pfs/CLAUDE.md +72 -0
  27. data/lib/pubid/doi_pfs/builder.rb +18 -0
  28. data/lib/pubid/doi_pfs/identifier.rb +43 -0
  29. data/lib/pubid/doi_pfs/identifiers/resource.rb +31 -0
  30. data/lib/pubid/doi_pfs/identifiers.rb +7 -0
  31. data/lib/pubid/doi_pfs/parser.rb +10 -0
  32. data/lib/pubid/doi_pfs/pubid_urn_schema.rb +15 -0
  33. data/lib/pubid/doi_pfs/renderer.rb +10 -0
  34. data/lib/pubid/doi_pfs/urn_generator.rb +12 -0
  35. data/lib/pubid/doi_pfs.rb +60 -0
  36. data/lib/pubid/etsi_pfs/CLAUDE.md +95 -0
  37. data/lib/pubid/etsi_pfs/builder.rb +25 -0
  38. data/lib/pubid/etsi_pfs/identifier.rb +50 -0
  39. data/lib/pubid/etsi_pfs/identifiers/standard.rb +22 -0
  40. data/lib/pubid/etsi_pfs/identifiers.rb +7 -0
  41. data/lib/pubid/etsi_pfs/parser.rb +10 -0
  42. data/lib/pubid/etsi_pfs/pubid_urn_schema.rb +19 -0
  43. data/lib/pubid/etsi_pfs/renderer.rb +10 -0
  44. data/lib/pubid/etsi_pfs/urn_generator.rb +12 -0
  45. data/lib/pubid/etsi_pfs.rb +59 -0
  46. data/lib/pubid/itu/CLAUDE.md +25 -14
  47. data/lib/pubid/itu/builder.rb +7 -5
  48. data/lib/pubid/itu/identifiers/special_publication.rb +20 -17
  49. data/lib/pubid/itu/urn_generator.rb +3 -4
  50. data/lib/pubid/nist/CLAUDE.md +36 -0
  51. data/lib/pubid/nist/builder.rb +10 -0
  52. data/lib/pubid/nist/identifiers/base.rb +10 -0
  53. data/lib/pubid/nist/identifiers/special_publication.rb +15 -0
  54. data/lib/pubid/nist/router.rb +11 -0
  55. data/lib/pubid/version.rb +1 -1
  56. data/lib/pubid.rb +17 -0
  57. metadata +44 -2
@@ -16,10 +16,9 @@ module Pubid
16
16
  def generate_base_urn
17
17
  parts = ["urn", "itu"]
18
18
 
19
- # An Operational Bulletin is cross-bureau: its sector is a spelling,
20
- # not identity (see SpecialPublication#==), so it stays out of the URN.
21
- if identifier.sector &&
22
- !identifier.is_a?(Identifiers::SpecialPublication)
19
+ # An Operational Bulletin never carries a sector (#696), so it gets
20
+ # the `itu` segment here.
21
+ if identifier.sector
23
22
  sector = identifier.sector.to_s
24
23
  parts << sector.to_s.downcase
25
24
  else
@@ -184,3 +184,39 @@ Read this before you change `lib/pubid/nist/` or `spec/pubid/nist/`. The root
184
184
  nothing (its flag defaults to true, so it means a spelled form anyway).
185
185
  Locked by
186
186
  `spec/pubid/nist/bare_fips_publisher_spec.rb`.
187
+
188
+ - **The default-series plain-number branch (pubid#711).** A citation
189
+ shaped like the docnumber — "800-90B", the docid-derived citation face
190
+ of NIST.SP.800-90B — and its publisher-led spelling "NIST 800-90B"
191
+ carry NO series token, and the grammar's series alternatives never
192
+ reached them: every branch demanded a series token (or, after a bare
193
+ publisher, only the dated ISO-date digits). The grammar (nist.parg,
194
+ fleet compiler 1.3.126) gained two trailing `identifier` alternatives
195
+ that ride the SAME report-number tail as the series-bearing branches —
196
+ `(publisher) (space) (report_number) …` and bare `(report_number) …` —
197
+ placed LAST so PEG ordering leaves every previously accepted form on
198
+ its original alternative (they only catch inputs that previously
199
+ failed outright). The identity defaults onto the SP series: the Router
200
+ dispatches `SpecialPublication` when the parse carries no series and
201
+ no dated date, and the Builder fills `series` from the new
202
+ `Identifier.default_series` class method (SP is the default — the
203
+ docid of the real document is NIST.SP.800-90B). The publisher rides
204
+ the #704 machinery: `SpecialPublication.series_default_publisher` is
205
+ now "NIST", so the bare parse fills the publisher after
206
+ `publisher_was_parsed: false` and is `==` to the spelled form (URN-,
207
+ MR- and hash-equal but for that equality-ignored flag; the MR face is
208
+ the exact "NIST.SP.800-90B" DOI surface relaton-data-nist stores).
209
+ The SHORT face keeps the bare spelling (publisher suppressed);
210
+ the MR face always carries the publisher (`to_mr_style` prints
211
+ `(publisher || "NIST")`), so the bare parse lands on the DOI-style
212
+ face directly. The dated alternative keeps priority
213
+ ("NIST 2023-04-15 001" stays `DatedDocument`), and the routing probe
214
+ ("zzqx-nonsense-9714") still fails, so NIST is not disqualified as a
215
+ `Pubid.parse` fallback. `to_hash` of the two bare-series probes
216
+ ("SP 123", "SP 800-90B") gained `publisher: NIST` — the #704 ruling
217
+ generalized to the SP series; no corpus row moved. Locked by
218
+ `spec/pubid/nist/default_series_plain_number_spec.rb`; the corpus
219
+ round froze the four faces (the two publisher-led spellings as
220
+ non-normalized aliases of the canonical cases, the two bare ones as
221
+ canonical `publisher_was_parsed: false` cases) with the gem twin in
222
+ lockstep.
@@ -99,6 +99,16 @@ module Pubid
99
99
  # Locate the appropriate identifier class via Router
100
100
  identifier = @router.locate_identifier_klass(parsed_hash).new
101
101
 
102
+ # The default-series plain-number branch (pubid#711): the grammar's
103
+ # trailing alternatives carry no series token ("800-90B" /
104
+ # "NIST 800-90B"), so the identity gains the class's default series
105
+ # and parses == to the spelled "NIST SP 800-90B" form. The bare
106
+ # publisher rides the #704 rule below (apply_series_default_publisher).
107
+ if parsed_hash[:series].nil? &&
108
+ (default = identifier.class.default_series)
109
+ identifier.series = Components::Code.new(value: default)
110
+ end
111
+
102
112
  # Resolve the series policy once — every series-specific decision
103
113
  # flows through this object instead of branching on the parsed shape.
104
114
  series = Series.for(parsed_hash)
@@ -302,6 +302,16 @@ module Pubid
302
302
  nil
303
303
  end
304
304
 
305
+ # The series an input implies when it spells none — the grammar's
306
+ # default-series plain-number branch (pubid#711: "800-90B" /
307
+ # "NIST 800-90B" carry no series token). The Router dispatches the
308
+ # class from this default and the Builder fills the attribute, so a
309
+ # docnumber-shaped citation parses onto the same identity as the
310
+ # spelled form. nil: no default.
311
+ def self.default_series
312
+ nil
313
+ end
314
+
305
315
  # Fill the series default publisher on an id whose input spelled
306
316
  # none. Shared by the Builder and from_hash, so both construction
307
317
  # paths agree.
@@ -35,6 +35,21 @@ module Pubid
35
35
  { key: :sp,
36
36
  web: :special_publication, title: "NIST Special Publication", short: "SP" }
37
37
  end
38
+
39
+ # The default-series plain-number branch (pubid#711): a citation
40
+ # shaped like the docnumber ("800-90B", publisher-led
41
+ # "NIST 800-90B") names an SP document — the docid-derived
42
+ # citation of NIST.SP.800-90B is exactly "800-90B".
43
+ def default_series
44
+ "SP"
45
+ end
46
+
47
+ # A bare plain-number parse carries the series' NIST publisher
48
+ # (the #704 shape), so it is == to the spelled
49
+ # "NIST SP 800-90B" form a lookup compares against.
50
+ def series_default_publisher
51
+ "NIST"
52
+ end
38
53
  end
39
54
 
40
55
  def series_code
@@ -46,6 +46,17 @@ module Pubid
46
46
 
47
47
  series = parsed_hash[:series]&.to_s
48
48
 
49
+ # The default-series plain-number branch (pubid#711): the grammar's
50
+ # trailing alternatives accept a bare report number ("800-90B") and
51
+ # its publisher-led spelling ("NIST 800-90B") with NO series token.
52
+ # The SP series is the default: the docid-derived citation of
53
+ # NIST.SP.800-90B is exactly the bare docnumber "800-90B", and the
54
+ # Builder fills the same SP series the spelled form carries, so the
55
+ # two spellings are one identity to a lookup. No other branch can
56
+ # arrive here series-less (dated shapes returned above; every
57
+ # series-bearing branch captures :series).
58
+ return Identifiers::SpecialPublication if series.nil?
59
+
49
60
  # Handle compound series that include publisher (both space and dot separated)
50
61
  if series&.start_with?("NBS ")
51
62
  simple_series = series.sub("NBS ", "")
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.22"
4
+ VERSION = "2.0.24"
5
5
  end
data/lib/pubid.rb CHANGED
@@ -224,17 +224,34 @@ module Pubid
224
224
  autoload :Ashrae, "pubid/ashrae"
225
225
  autoload :Asme, "pubid/asme"
226
226
  autoload :Doi, "pubid/doi"
227
+ # The PFS-compiled dev alias of doi (pubid/pubid#706): registered
228
+ # beside the coded flavor, never routed by Pubid.parse (registry keys
229
+ # sort "doi" first).
230
+ autoload :DoiPfs, "pubid/doi_pfs"
227
231
  autoload :Easc, "pubid/easc"
228
232
  autoload :Astm, "pubid/astm"
229
233
  autoload :Bipm, "pubid/bipm"
230
234
  autoload :Bsi, "pubid/bsi"
231
235
  autoload :Calconnect, "pubid/calconnect"
236
+ # The PFS-compiled dev alias of calconnect (pubid/pubid#706 §8): the
237
+ # acceptance port, registered beside the coded flavor, never routed by
238
+ # Pubid.parse (registry keys sort the coded key first).
239
+ autoload :CalconnectPfs, "pubid/calconnect_pfs"
240
+ # The PFS-compiled module-composition surface of cen_cenelec
241
+ # (pubid/pubid#706 §4): the EN face composed from the module library —
242
+ # the measured boundary of what the modules absorb
243
+ # (spec/pubid/cen_pfs/parity_spec.rb's ledger).
244
+ autoload :CenPfs, "pubid/cen_pfs"
232
245
  autoload :Ccsds, "pubid/ccsds"
233
246
  autoload :CenCenelec, "pubid/cen_cenelec"
234
247
  autoload :Cie, "pubid/cie"
235
248
  autoload :Csa, "pubid/csa"
236
249
  autoload :Ecma, "pubid/ecma"
237
250
  autoload :Etsi, "pubid/etsi"
251
+ # The PFS-compiled dev alias of etsi (pubid/pubid#706): registered
252
+ # beside the coded flavor, never routed by Pubid.parse (registry keys
253
+ # sort "etsi" first).
254
+ autoload :EtsiPfs, "pubid/etsi_pfs"
238
255
  autoload :Evs, "pubid/evs"
239
256
  autoload :Gost, "pubid/gost"
240
257
  autoload :Gb, "pubid/gb"
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.22
4
+ version: 2.0.24
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-11-12 00:00:00.000000000 Z
11
+ date: 2026-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -91,15 +91,19 @@ files:
91
91
  - data/parg/bipm.parg
92
92
  - data/parg/bsi.json
93
93
  - data/parg/calconnect.json
94
+ - data/parg/calconnect_pfs.json
94
95
  - data/parg/ccsds.json
95
96
  - data/parg/cen_cenelec.json
96
97
  - data/parg/cen_cenelec.parg
98
+ - data/parg/cen_pfs.json
97
99
  - data/parg/cie.json
98
100
  - data/parg/csa.json
99
101
  - data/parg/doi.json
102
+ - data/parg/doi_pfs.json
100
103
  - data/parg/easc.json
101
104
  - data/parg/ecma.json
102
105
  - data/parg/etsi.json
106
+ - data/parg/etsi_pfs.json
103
107
  - data/parg/evs.json
104
108
  - data/parg/gb.json
105
109
  - data/parg/gost.json
@@ -351,6 +355,15 @@ files:
351
355
  - lib/pubid/calconnect/renderer.rb
352
356
  - lib/pubid/calconnect/urn_generator.rb
353
357
  - lib/pubid/calconnect/urn_parser.rb
358
+ - lib/pubid/calconnect_pfs.rb
359
+ - lib/pubid/calconnect_pfs/builder.rb
360
+ - lib/pubid/calconnect_pfs/identifier.rb
361
+ - lib/pubid/calconnect_pfs/identifiers.rb
362
+ - lib/pubid/calconnect_pfs/identifiers/standard.rb
363
+ - lib/pubid/calconnect_pfs/parser.rb
364
+ - lib/pubid/calconnect_pfs/pubid_urn_schema.rb
365
+ - lib/pubid/calconnect_pfs/renderer.rb
366
+ - lib/pubid/calconnect_pfs/urn_generator.rb
354
367
  - lib/pubid/ccsds.rb
355
368
  - lib/pubid/ccsds/builder.rb
356
369
  - lib/pubid/ccsds/identifier.rb
@@ -390,6 +403,15 @@ files:
390
403
  - lib/pubid/cen_cenelec/single_identifier.rb
391
404
  - lib/pubid/cen_cenelec/urn_generator.rb
392
405
  - lib/pubid/cen_cenelec/urn_parser.rb
406
+ - lib/pubid/cen_pfs.rb
407
+ - lib/pubid/cen_pfs/builder.rb
408
+ - lib/pubid/cen_pfs/identifier.rb
409
+ - lib/pubid/cen_pfs/identifiers.rb
410
+ - lib/pubid/cen_pfs/identifiers/european_norm.rb
411
+ - lib/pubid/cen_pfs/parser.rb
412
+ - lib/pubid/cen_pfs/pubid_urn_schema.rb
413
+ - lib/pubid/cen_pfs/renderer.rb
414
+ - lib/pubid/cen_pfs/urn_generator.rb
393
415
  - lib/pubid/cie.rb
394
416
  - lib/pubid/cie/CLAUDE.md
395
417
  - lib/pubid/cie/builder.rb
@@ -470,6 +492,16 @@ files:
470
492
  - lib/pubid/doi/parser.rb
471
493
  - lib/pubid/doi/pubid_urn_schema.rb
472
494
  - lib/pubid/doi/renderer.rb
495
+ - lib/pubid/doi_pfs.rb
496
+ - lib/pubid/doi_pfs/CLAUDE.md
497
+ - lib/pubid/doi_pfs/builder.rb
498
+ - lib/pubid/doi_pfs/identifier.rb
499
+ - lib/pubid/doi_pfs/identifiers.rb
500
+ - lib/pubid/doi_pfs/identifiers/resource.rb
501
+ - lib/pubid/doi_pfs/parser.rb
502
+ - lib/pubid/doi_pfs/pubid_urn_schema.rb
503
+ - lib/pubid/doi_pfs/renderer.rb
504
+ - lib/pubid/doi_pfs/urn_generator.rb
473
505
  - lib/pubid/easc.rb
474
506
  - lib/pubid/easc/builder.rb
475
507
  - lib/pubid/easc/identifier.rb
@@ -514,6 +546,16 @@ files:
514
546
  - lib/pubid/etsi/renderer.rb
515
547
  - lib/pubid/etsi/urn_generator.rb
516
548
  - lib/pubid/etsi/urn_parser.rb
549
+ - lib/pubid/etsi_pfs.rb
550
+ - lib/pubid/etsi_pfs/CLAUDE.md
551
+ - lib/pubid/etsi_pfs/builder.rb
552
+ - lib/pubid/etsi_pfs/identifier.rb
553
+ - lib/pubid/etsi_pfs/identifiers.rb
554
+ - lib/pubid/etsi_pfs/identifiers/standard.rb
555
+ - lib/pubid/etsi_pfs/parser.rb
556
+ - lib/pubid/etsi_pfs/pubid_urn_schema.rb
557
+ - lib/pubid/etsi_pfs/renderer.rb
558
+ - lib/pubid/etsi_pfs/urn_generator.rb
517
559
  - lib/pubid/evs.rb
518
560
  - lib/pubid/evs/CLAUDE.md
519
561
  - lib/pubid/evs/builder.rb