pubid 2.0.0.pre.alpha.45 → 2.0.0.pre.alpha.47

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6899d53fcf1708eacd4c4955c1005369f54fcbfd8dbbbaf73ab417c71fdfa1b
4
- data.tar.gz: 2c194ebf70e57cc7e840f7eec013eb0e4073261ba150a9f6bb94d0234a032d74
3
+ metadata.gz: cdd72b807af6dfe0a054a41ea6936289d3a7baa1d9f52dd6ca526a2092fe74ed
4
+ data.tar.gz: 766936316a70dde70df50e5090555a8004663ed33cc21e2058e8a34ac9b56917
5
5
  SHA512:
6
- metadata.gz: '047988bdc5488d32b23196662207015cc4fe728fe8dcdc43dde35f6041593a9e32e1b7eab22f35491a583193eb5fd74464e7e065c39a5e497178ec8c36fdc173'
7
- data.tar.gz: b752b405f2664ea6246886f8f0d888a56ca6da898b5a05b03b6355b02d46d787760630ae19792f1eeacd13c018c5e1eb02e3a6c585f938118f56d4c5f2147484
6
+ metadata.gz: 001d0cec827dee1c30411aed304e52e14eda70989fa180575f9dff377e34022dd3d37caf2b6bf4f20415102c38e4aeb1b52531351c741544f80a587e413cfbc2
7
+ data.tar.gz: 100d3d5314550b4fbb535440e7002e070e205b28f5faf3f4cd66dae6cd054790d41c202ab239c3f961d2ac0db253eefcc9fc5737aa69cc666cb340fdd8a5c213
@@ -195,7 +195,21 @@ module Pubid
195
195
  # @return [Pubid::Components::TypedStage, nil] the matching typed stage
196
196
  def self.locate_stage(abbr)
197
197
  abbr_str = abbr.to_s.upcase
198
- all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
198
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } } ||
199
+ # A harmonized stage code ("43.20") names the stage the same way an
200
+ # abbreviation does; consumers query by it (pubid#251), so an
201
+ # unmatched abbreviation falls through to the code tables.
202
+ locate_stage_by_harmonized_code(abbr)
203
+ end
204
+
205
+ # Lookup: harmonized stage code -> typed stage ("43.20" -> the FV EN
206
+ # entry). The codes are the CEN/CENELEC lifecycle ladder; every code a
207
+ # consumer can query must resolve (pubid#251).
208
+ # @param code [String, Symbol] the harmonized stage code to find
209
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
210
+ def self.locate_stage_by_harmonized_code(code)
211
+ code_str = code.to_s
212
+ all_typed_stages.find { |s| s.harmonized_stages.to_a.include?(code_str) }
199
213
  end
200
214
 
201
215
  # Lookup: typed-stage code -> typed stage ("pren" -> the prEN entry).
@@ -142,16 +142,31 @@ module Pubid
142
142
  elsif TYPED_STAGE_REVERSE_MAP.key?(parts.first&.upcase) ||
143
143
  (parts.first&.match?(/^[A-Za-z]+\.\d+$/) &&
144
144
  TYPED_STAGE_REVERSE_MAP.key?(parts.first.upcase.split(".").first))
145
- stage_abbr = parts.shift.upcase
146
- # Check for iteration (WD.2 format)
147
- if stage_abbr.include?(".")
148
- abbr_part, iteration_part = stage_abbr.split(".")
149
- stage_code = TYPED_STAGE_REVERSE_MAP[abbr_part]
150
- stage_from_abbr = stage_code
151
- stage_iteration = iteration_part.to_i
152
- else
153
- stage_code = TYPED_STAGE_REVERSE_MAP[stage_abbr]
154
- stage_from_abbr = stage_code
145
+ stage_abbr = parts.first.upcase
146
+ # The family comes from the abbreviation without its iteration
147
+ # ("FDAM.3" is still the amd family).
148
+ family = Pubid::Iso.locate_stage(stage_abbr.split(".").first)&.type_code&.to_s
149
+ # A supplement-family stage directly before its own supplement
150
+ # type token ("...:FDAM:amd:1:v1") names the SUPPLEMENT's stage:
151
+ # consuming it as the base's stage builds the base as a base-less
152
+ # supplement, which cannot render.
153
+ supplement_follows =
154
+ %w[amd cor suppl add].include?(family) &&
155
+ parts.drop(1).any? do |token|
156
+ family == SUPPLEMENT_TYPE_MAP[token.to_s.downcase]&.to_s
157
+ end
158
+ unless supplement_follows
159
+ parts.shift
160
+ # Check for iteration (WD.2 format)
161
+ if stage_abbr.include?(".")
162
+ abbr_part, iteration_part = stage_abbr.split(".")
163
+ stage_code = TYPED_STAGE_REVERSE_MAP[abbr_part]
164
+ stage_from_abbr = stage_code
165
+ stage_iteration = iteration_part.to_i
166
+ else
167
+ stage_code = TYPED_STAGE_REVERSE_MAP[stage_abbr]
168
+ stage_from_abbr = stage_code
169
+ end
155
170
  end
156
171
  end
157
172
 
@@ -397,6 +412,16 @@ module Pubid
397
412
  # Build supplements recursively (forward order: first supplement wraps base,
398
413
  # second wraps first, etc. -- matching URN left-to-right semantics)
399
414
  supplements.each do |supp|
415
+ # A bare language token with no supplement identity names the BASE
416
+ # document: wrapping it would build a supplement with no type,
417
+ # number or base attribute, and a plain standard drops its base —
418
+ # the whole document was lost, rendering "ISO (FR)".
419
+ if supp[:type].nil? && supp[:stage].nil? && supp[:number].nil? &&
420
+ supp[:year].nil? && supp[:languages]
421
+ base_hash[:languages] = supp[:languages].join("/")
422
+ next
423
+ end
424
+
400
425
  supp_hash = {}
401
426
 
402
427
  if supp[:stage]
data/lib/pubid/iso.rb CHANGED
@@ -223,7 +223,13 @@ module Pubid
223
223
  # @return [Pubid::Components::TypedStage, nil]
224
224
  def self.locate_stage_by_harmonized_code(harmonized_code)
225
225
  harmonized_str = harmonized_code.to_s
226
- all_typed_stages.find { |s| s.harmonized_stages&.include?(harmonized_str) }
226
+ candidates = all_typed_stages.select { |s| s.harmonized_stages&.include?(harmonized_str) }
227
+ # all_typed_stages walks the loaded identifier constants, so its order
228
+ # is load-order dependent and a bare "first match" flipped between
229
+ # processes (an IWA at 10.99 rendered "AWI Add"/"AWI Suppl"/"AWI"
230
+ # depending on the run). The IS family is the default document type;
231
+ # prefer it, then keep the registry order.
232
+ candidates.find { |s| s.type_code.to_s == "is" } || candidates.first
227
233
  end
228
234
 
229
235
  # Default typed stage used when no type_with_stage is present
@@ -72,3 +72,11 @@ Read this before you change `lib/pubid/nist/` or `spec/pubid/nist/`. The root
72
72
  (`"800-38.A.supp.add."` splits with a trailing `""` in JS but not in
73
73
  Ruby; keeping it appends a stray `.`). Locked by
74
74
  `spec/pubid/nist/urn_parser_spec.rb`.
75
+
76
+ - **FIPS MR keeps the parsed publisher.** `FederalInformationProcessingStandards`
77
+ sets `default_publisher` to `""`, and its `to_mr_style` once started from
78
+ `series_code` alone, so `NIST.FIPS.197-upd1.ipd` rendered `FIPS.197-upd1.ipd`
79
+ — not the DOI suffix NIST publishes. It now mirrors its own
80
+ `to_short_style`: the publisher prefixes only when the input carried one
81
+ (`NIST.`/`NBS.`), and a bare `FIPS 140-3` still renders `FIPS.140-3`.
82
+ Locked by `spec/pubid/nist/identifiers/fips_spec.rb`.
@@ -37,11 +37,12 @@ module Pubid
37
37
  ""
38
38
  end
39
39
 
40
- # Override to_mr_style to not add "NIST" prefix for FIPS
40
+ # Override to_mr_style so FIPS adds no default "NIST" prefix
41
41
  def to_mr_style
42
- # "FIPS.46e1977" (machine-readable with dots, no publisher prefix)
42
+ # "NIST.FIPS.197" keeps a parsed publisher (the DOI suffix NIST
43
+ # publishes); "FIPS.46e1977" has none and invents none.
43
44
  # Note: edition is appended directly to number without dot for FIPS
44
- result = series_code
45
+ result = [publisher, series_code].compact.join(".")
45
46
  result += ".#{number}" if number
46
47
 
47
48
  # FIPS uses dash notation for parts; render here and skip the generic
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.45"
4
+ VERSION = "2.0.0.pre.alpha.47"
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.45
4
+ version: 2.0.0.pre.alpha.47
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-20 00:00:00.000000000 Z
11
+ date: 2026-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model