pubid 2.0.0.pre.alpha.50 → 2.0.0.pre.alpha.52
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/lib/pubid/format_registry.rb +4 -1
- data/lib/pubid/iso/builder.rb +4 -0
- data/lib/pubid/iso/supplement_identifier.rb +23 -0
- data/lib/pubid/iso/urn_generator.rb +14 -52
- data/lib/pubid/iso/urn_parser.rb +52 -9
- data/lib/pubid/nist/parser.rb +0 -4
- data/lib/pubid/parsers/urn.rb +18 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid.rb +24 -11
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c83c28edc99ccf1e6167e7f6267cf04aedff8cf15629f2d778648eee0e842fd
|
|
4
|
+
data.tar.gz: b195d6a1b9cef28f3dcb711e7c5478efe16a99892de4a92899fb0adbc52638eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f6557ed875261cad34957e7e954d00e176edd68311594f058c261b25a15e54f70db606964f4652ff5971feacc5c124b4b6885c73ebd7ff33654fdc721d1df24
|
|
7
|
+
data.tar.gz: b448357f4887dcc7da87b580c0433ce6e358b624e49b23c1c9336e145a0a971c1c592e6eca6b148844d1ff128a9abf666065b649e664ea3af34a42f986b360eb
|
|
@@ -63,7 +63,10 @@ module Pubid
|
|
|
63
63
|
transformer = Class.new do
|
|
64
64
|
define_singleton_method(:name) { "Pubid#{format.to_s.capitalize}Transform" }
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
# Lutaml calls the transformer on the class (transformer_for
|
|
67
|
+
# returns the registered object as-is), so the hook is a
|
|
68
|
+
# singleton method.
|
|
69
|
+
define_singleton_method(:data_to_model) do |_model, data, _format, _options = {}|
|
|
67
70
|
data
|
|
68
71
|
end
|
|
69
72
|
end
|
data/lib/pubid/iso/builder.rb
CHANGED
|
@@ -315,6 +315,10 @@ module Pubid
|
|
|
315
315
|
value
|
|
316
316
|
end
|
|
317
317
|
|
|
318
|
+
when :supplement_version
|
|
319
|
+
# The RFC 5141 <supplversion> carried on supplement identifiers
|
|
320
|
+
value.to_s
|
|
321
|
+
|
|
318
322
|
when :stage
|
|
319
323
|
# Raw stage code from URN parser (e.g., "10.00", "50.00")
|
|
320
324
|
# Convert to type_with_stage format for builder
|
|
@@ -6,6 +6,11 @@ module Pubid
|
|
|
6
6
|
attribute :base, Identifier,
|
|
7
7
|
polymorphic: true
|
|
8
8
|
|
|
9
|
+
# The RFC 5141 <supplversion> (the corrected version of the
|
|
10
|
+
# supplement; published supplements are version 1). Distinct from
|
|
11
|
+
# the amendment/corrigendum <supplnumber>.
|
|
12
|
+
attribute :supplement_version, :string
|
|
13
|
+
|
|
9
14
|
key_value do
|
|
10
15
|
# Serialized key is "base" (matches JIS); the attribute/method stays
|
|
11
16
|
# `base`, which relaton-index's get_id_number depends on.
|
|
@@ -13,6 +18,24 @@ module Pubid
|
|
|
13
18
|
attribute: "_type",
|
|
14
19
|
class_map: Identifier::ISO_TYPE_MAP,
|
|
15
20
|
}
|
|
21
|
+
map "supplement_version",
|
|
22
|
+
with: { to: :supplement_version_to_kv, from: :supplement_version_from_kv }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def supplement_version_to_kv(model, doc)
|
|
26
|
+
return unless model.supplement_version
|
|
27
|
+
|
|
28
|
+
doc.add_child(
|
|
29
|
+
Lutaml::KeyValue::DataModel::Element.new(
|
|
30
|
+
"supplement_version", model.supplement_version.to_s,
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def supplement_version_from_kv(model, value)
|
|
36
|
+
return if value.nil? || value.to_s.empty?
|
|
37
|
+
|
|
38
|
+
model.supplement_version = value.to_i
|
|
16
39
|
end
|
|
17
40
|
|
|
18
41
|
# A supplement carries the publisher/copublishers of the document it
|
|
@@ -18,23 +18,6 @@ module Pubid
|
|
|
18
18
|
URN_CONTEXT = Rendering::RenderingContext.urn.freeze
|
|
19
19
|
private_constant :URN_CONTEXT
|
|
20
20
|
|
|
21
|
-
# Stage code mapping for RFC 5141-bis typed stages
|
|
22
|
-
TYPED_STAGE_MAP = {
|
|
23
|
-
wd: "WD",
|
|
24
|
-
wds: "WDS",
|
|
25
|
-
cd: "CD",
|
|
26
|
-
cdv: "CDV",
|
|
27
|
-
dis: "DIS",
|
|
28
|
-
fdis: "FDIS",
|
|
29
|
-
pdam: "PDAM",
|
|
30
|
-
dam: "DAM",
|
|
31
|
-
fdamd: "FDAM",
|
|
32
|
-
dcor: "DCOR",
|
|
33
|
-
fdcor: "FDCOR",
|
|
34
|
-
cdts: "CDTS",
|
|
35
|
-
dts: "DTS",
|
|
36
|
-
fdts: "FDTS",
|
|
37
|
-
}.freeze
|
|
38
21
|
|
|
39
22
|
TYPE_CODE_MAP = {
|
|
40
23
|
dir: "dir",
|
|
@@ -134,22 +117,17 @@ module Pubid
|
|
|
134
117
|
suppl_type = supp_gen.supplement_type_component
|
|
135
118
|
parts << suppl_type if suppl_type
|
|
136
119
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
120
|
+
# RFC 5141 supplement slots in order: number, year (the bis
|
|
121
|
+
# additive extension -- the legacy wire overloaded the number
|
|
122
|
+
# slot with the year), then the published version ("when a
|
|
123
|
+
# supplement is published, it is version 1").
|
|
124
|
+
parts << supp.number.to_s if supp.number
|
|
125
|
+
parts << supp.date.render(context: URN_CONTEXT) if supp.date
|
|
126
|
+
version = supp.supplement_version || 1
|
|
127
|
+
if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
|
|
128
|
+
parts << "v#{version}.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
|
|
146
129
|
else
|
|
147
|
-
parts <<
|
|
148
|
-
if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
|
|
149
|
-
parts << "v1.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
|
|
150
|
-
else
|
|
151
|
-
parts << "v1"
|
|
152
|
-
end
|
|
130
|
+
parts << "v#{version}"
|
|
153
131
|
end
|
|
154
132
|
|
|
155
133
|
if supp.languages&.any?
|
|
@@ -208,26 +186,10 @@ module Pubid
|
|
|
208
186
|
stage_code = identifier.typed_stage.stage_code
|
|
209
187
|
return nil if !stage_code || stage_code == :published
|
|
210
188
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
stage_abbr = if combined_key && TYPED_STAGE_MAP.key?(combined_key)
|
|
218
|
-
TYPED_STAGE_MAP[combined_key]
|
|
219
|
-
elsif TYPED_STAGE_MAP.key?(stage_code.to_sym)
|
|
220
|
-
TYPED_STAGE_MAP[stage_code.to_sym]
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
if stage_abbr
|
|
224
|
-
if identifier.stage_iteration
|
|
225
|
-
return "#{stage_abbr}.#{identifier.stage_iteration.render(context: URN_CONTEXT)}"
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
return stage_abbr
|
|
229
|
-
end
|
|
230
|
-
|
|
189
|
+
# RFC 5141 carries the stage as the harmonized code only
|
|
190
|
+
# ("stage-XX.XX[.vN]"); the typed abbreviations (CD, DIS, DAM...)
|
|
191
|
+
# live in the human face. Legacy abbreviation URNs are accepted
|
|
192
|
+
# on ingestion and re-canonicalized here.
|
|
231
193
|
harmonized_codes = identifier.typed_stage.harmonized_stages
|
|
232
194
|
return nil unless harmonized_codes&.any?
|
|
233
195
|
|
data/lib/pubid/iso/urn_parser.rb
CHANGED
|
@@ -175,6 +175,7 @@ module Pubid
|
|
|
175
175
|
while parts.any?
|
|
176
176
|
supp_type = nil
|
|
177
177
|
supp_number = nil
|
|
178
|
+
supp_version = nil
|
|
178
179
|
supp_year = nil
|
|
179
180
|
supp_stage = nil
|
|
180
181
|
|
|
@@ -203,14 +204,19 @@ module Pubid
|
|
|
203
204
|
end
|
|
204
205
|
end
|
|
205
206
|
|
|
206
|
-
# Check for version (v1, v2, etc.) after year or number
|
|
207
|
+
# Check for version (v1, v2, etc.) after year or number.
|
|
208
|
+
# Legacy year-overloaded wire ("amd:2007:v2" -- the number rode
|
|
209
|
+
# the version slot): a v-token with no preceding number carries
|
|
210
|
+
# the NUMBER. The RFC 5141 additive extension ("amd:1:2007:v2")
|
|
211
|
+
# keeps the number in its own slot, so a v-token after a number
|
|
212
|
+
# is the true <supplversion>.
|
|
207
213
|
if parts.first&.start_with?("v")
|
|
208
|
-
version_str = parts.shift
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
version_str = parts.shift.sub("v", "")
|
|
215
|
+
value = version_str.split(".").first.to_i
|
|
216
|
+
if supp_number.nil?
|
|
217
|
+
supp_number = value
|
|
218
|
+
else
|
|
219
|
+
supp_version = value
|
|
214
220
|
end
|
|
215
221
|
end
|
|
216
222
|
|
|
@@ -219,6 +225,19 @@ module Pubid
|
|
|
219
225
|
supp_year = parts.shift
|
|
220
226
|
end
|
|
221
227
|
|
|
228
|
+
# A v-token after the year ("amd:1:2007:v1") would otherwise be
|
|
229
|
+
# left for the next loop iteration, wrapping a type-less
|
|
230
|
+
# supplement around the real one and losing the base.
|
|
231
|
+
if parts.first&.start_with?("v")
|
|
232
|
+
version_str = parts.shift.sub("v", "")
|
|
233
|
+
value = version_str.split(".").first.to_i
|
|
234
|
+
if supp_number.nil?
|
|
235
|
+
supp_number = value
|
|
236
|
+
else
|
|
237
|
+
supp_version = value
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
222
241
|
# Check for language after supplement
|
|
223
242
|
supp_languages = nil
|
|
224
243
|
if parts.first && !parts.first.match(/^\d+$/) && !parts.first.match?(/^(amd|cor|sup|add|v\d+|stage-)/i)
|
|
@@ -228,6 +247,7 @@ module Pubid
|
|
|
228
247
|
supplements << {
|
|
229
248
|
type: supp_type,
|
|
230
249
|
number: supp_number,
|
|
250
|
+
version: supp_version,
|
|
231
251
|
year: supp_year,
|
|
232
252
|
stage: supp_stage,
|
|
233
253
|
languages: supp_languages,
|
|
@@ -425,12 +445,31 @@ module Pubid
|
|
|
425
445
|
supp_hash = {}
|
|
426
446
|
|
|
427
447
|
if supp[:stage]
|
|
428
|
-
|
|
448
|
+
# A harmonized code resolves through the deliverable type
|
|
449
|
+
# (like the base stage); a supplement-family abbreviation
|
|
450
|
+
# resolves by abbr -- the typed-stage code differs from the
|
|
451
|
+
# abbr ("fdamd" for FDAM), so the stage-code lookup misses.
|
|
452
|
+
typed_stage =
|
|
453
|
+
if supp[:stage].to_s.match?(/\A\d\d\.\d\d\z/)
|
|
454
|
+
# resolve within the supplement's own type family -- the
|
|
455
|
+
# umbrella lookup prefers the IS family, which would turn
|
|
456
|
+
# a staged Corrigendum into a plain IS
|
|
457
|
+
code_str = supp[:stage].to_s
|
|
458
|
+
type_str = supp[:type]&.to_s
|
|
459
|
+
candidates = Pubid::Iso.all_typed_stages
|
|
460
|
+
.select { |st| st.harmonized_stages&.include?(code_str) }
|
|
461
|
+
candidates.find { |st| st.type_code.to_s == type_str } ||
|
|
462
|
+
candidates.find { |st| st.type_code.to_s == "is" } ||
|
|
463
|
+
candidates.first
|
|
464
|
+
else
|
|
465
|
+
Pubid::Iso.locate_stage(supp[:stage].to_s.upcase) ||
|
|
466
|
+
Pubid::Iso.locate_stage_by_stage_code(supp[:stage])
|
|
467
|
+
end
|
|
429
468
|
supp_hash[:type_with_stage] = if
|
|
430
469
|
typed_stage
|
|
431
470
|
typed_stage.abbr.is_a?(Array) ? typed_stage.abbr.first : typed_stage.abbr
|
|
432
471
|
else
|
|
433
|
-
supp[:
|
|
472
|
+
supp[:type]&.to_s&.upcase
|
|
434
473
|
end
|
|
435
474
|
end
|
|
436
475
|
|
|
@@ -444,6 +483,10 @@ typed_stage
|
|
|
444
483
|
supp_hash[:year] = supp[:year].to_s
|
|
445
484
|
end
|
|
446
485
|
|
|
486
|
+
if supp[:version]
|
|
487
|
+
supp_hash[:supplement_version] = supp[:version].to_s
|
|
488
|
+
end
|
|
489
|
+
|
|
447
490
|
if supp[:languages]
|
|
448
491
|
supp_hash[:languages] = supp[:languages].join("/")
|
|
449
492
|
end
|
data/lib/pubid/nist/parser.rb
CHANGED
|
@@ -139,10 +139,6 @@ module Pubid
|
|
|
139
139
|
# Single letter: any letter not followed by excluded keywords
|
|
140
140
|
rule(:number_suffix) do
|
|
141
141
|
(str("U") >> lower_letter) |
|
|
142
|
-
# n+UPPERCASE annex suffix (e.g., 1nA, 85nB — the BH/HR/NCSTAR/SP
|
|
143
|
-
# annex designations, pubid#555). Before the general letter branch,
|
|
144
|
-
# which would consume the lone "n" and strand the capital letter.
|
|
145
|
-
(str("n") >> upper_letter) |
|
|
146
142
|
# An "r" directly followed by a digit is the revision marker (pubid#170),
|
|
147
143
|
# not a suffix — leave it for the second_number/edition rules.
|
|
148
144
|
# The guard sits before the letter so it tests the suffix start itself.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Parsers
|
|
5
|
+
# The :urn format's parse side. The Lutaml FormatRegistry mirror
|
|
6
|
+
# exposes it as Identifier.from_urn — the surface relaton-bib calls.
|
|
7
|
+
# It had a renderer but no parser, so every from_urn raised
|
|
8
|
+
# InvalidFormatError (metanorma-pdfa#108). Detects the flavor from
|
|
9
|
+
# the URN namespace and delegates to the flavor's UrnParser.
|
|
10
|
+
module Urn
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def call(string)
|
|
14
|
+
Pubid.parse_urn(string)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/pubid/version.rb
CHANGED
data/lib/pubid.rb
CHANGED
|
@@ -216,12 +216,14 @@ module Pubid
|
|
|
216
216
|
require "pubid/renderers/urn"
|
|
217
217
|
require "pubid/parsers/base"
|
|
218
218
|
require "pubid/parsers/mr_string"
|
|
219
|
+
require "pubid/parsers/urn"
|
|
219
220
|
|
|
220
221
|
# Initialize global format registry
|
|
221
222
|
Identifier.format_registry = FormatRegistry.new
|
|
222
223
|
Identifier.format_registry.register(:human, renderer: Renderers::HumanReadable)
|
|
223
224
|
Identifier.format_registry.register(:mr_string, renderer: Renderers::MrString)
|
|
224
|
-
Identifier.format_registry.register(:urn, renderer: Renderers::Urn
|
|
225
|
+
Identifier.format_registry.register(:urn, renderer: Renderers::Urn,
|
|
226
|
+
parser: Parsers::Urn)
|
|
225
227
|
|
|
226
228
|
# Unified parse entry point with auto-detection
|
|
227
229
|
#
|
|
@@ -267,21 +269,32 @@ module Pubid
|
|
|
267
269
|
parse_by_prefix(string)
|
|
268
270
|
end
|
|
269
271
|
when :urn
|
|
270
|
-
|
|
271
|
-
flavor = detect_flavor_from_urn(string)
|
|
272
|
-
flavor_module = Registry.get(flavor)
|
|
273
|
-
unless flavor_module
|
|
274
|
-
raise ArgumentError,
|
|
275
|
-
"Unknown flavor in URN: #{flavor}"
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
urn_parser = flavor_module.const_get(:UrnParser)
|
|
279
|
-
urn_parser.parse(string)
|
|
272
|
+
parse_urn(string)
|
|
280
273
|
else
|
|
281
274
|
parse_by_prefix(string)
|
|
282
275
|
end
|
|
283
276
|
end
|
|
284
277
|
|
|
278
|
+
# Parse an identifier URN, detecting the flavor from the URN namespace
|
|
279
|
+
# and delegating to the flavor's UrnParser. This is also the :urn
|
|
280
|
+
# format's parse side (Parsers::Urn), which the Lutaml FormatRegistry
|
|
281
|
+
# mirror exposes as Identifier.from_urn.
|
|
282
|
+
#
|
|
283
|
+
# @param string [String] the URN
|
|
284
|
+
# @return [Identifier] the parsed identifier
|
|
285
|
+
def self.parse_urn(string)
|
|
286
|
+
eager_load_flavors!
|
|
287
|
+
flavor = detect_flavor_from_urn(string)
|
|
288
|
+
flavor_module = Registry.get(flavor)
|
|
289
|
+
unless flavor_module
|
|
290
|
+
raise ArgumentError,
|
|
291
|
+
"Unknown flavor in URN: #{flavor}"
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
urn_parser = flavor_module.const_get(:UrnParser)
|
|
295
|
+
urn_parser.parse(string)
|
|
296
|
+
end
|
|
297
|
+
|
|
285
298
|
# Build an identifier from its serialized hash, without naming its flavor —
|
|
286
299
|
# the hash counterpart of {parse}.
|
|
287
300
|
#
|
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.
|
|
4
|
+
version: 2.0.0.pre.alpha.52
|
|
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-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
@@ -939,6 +939,7 @@ files:
|
|
|
939
939
|
- lib/pubid/parser/grammar.rb
|
|
940
940
|
- lib/pubid/parsers/base.rb
|
|
941
941
|
- lib/pubid/parsers/mr_string.rb
|
|
942
|
+
- lib/pubid/parsers/urn.rb
|
|
942
943
|
- lib/pubid/pg.rb
|
|
943
944
|
- lib/pubid/plateau.rb
|
|
944
945
|
- lib/pubid/plateau/builder.rb
|