pubid 2.0.0.pre.alpha.51 → 2.0.0.pre.alpha.53
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 +62 -11
- data/lib/pubid/parsers/urn.rb +18 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid.rb +24 -11
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4013c9f2d03ae3ad7ebdafd0f22176d7c72bca2a584ce7ba5dc1c9734cd539f0
|
|
4
|
+
data.tar.gz: 6b1b1629bd55bef868ac6a8d094b29e573b5a398210bce5df1b5ff593d2484c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3f4b9358cc7a97ef6bd7e586573fa9fda3af7745f39140b0002a2f1a2322052ee75b49a5183d2b58ae0a948f5e654570b920132fce14a4aa8f8b7f0e02dfd6e
|
|
7
|
+
data.tar.gz: d5563fa6632491b80a6f9795db6f9b9b8f5906285f58f8f3ee13d7a2514aa1bf750ccdf5bce4a3d6545300121b6cc3ae70913bd34fdd8dfc3b26b9465723758a
|
|
@@ -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
|
@@ -34,7 +34,10 @@ module Pubid
|
|
|
34
34
|
SUPPLEMENT_TYPE_MAP = {
|
|
35
35
|
"amd" => :amd,
|
|
36
36
|
"cor" => :cor,
|
|
37
|
-
|
|
37
|
+
# the generic Supplement type key (:suppl, the human grammar's
|
|
38
|
+
# own) -- :sup resolves the Directives Supplement row, whose
|
|
39
|
+
# render needs the supplement_publisher a guide chain never has
|
|
40
|
+
"sup" => :suppl,
|
|
38
41
|
"add" => :add,
|
|
39
42
|
}.freeze
|
|
40
43
|
|
|
@@ -88,7 +91,12 @@ module Pubid
|
|
|
88
91
|
type_code = parse_type(parts.first) if parts.first && TYPE_CODE_REVERSE_MAP.key?(parts.first.downcase)
|
|
89
92
|
parts.shift if type_code
|
|
90
93
|
|
|
91
|
-
# Parse number
|
|
94
|
+
# Parse number -- REQUIRED by the RFC 5141 docidentifier rule
|
|
95
|
+
# (originator [":" type] ":" docnumber); a URN without one
|
|
96
|
+
# ("urn:iso:std:iso") is not a valid NSS, and building it
|
|
97
|
+
# silently produced the identity-free "ISO "
|
|
98
|
+
raise Errors::UrnParseError, "missing docnumber: #{urn}" if parts.empty?
|
|
99
|
+
|
|
92
100
|
number_part = parts.shift
|
|
93
101
|
number, part, subpart = parse_number_part(number_part)
|
|
94
102
|
|
|
@@ -175,6 +183,7 @@ module Pubid
|
|
|
175
183
|
while parts.any?
|
|
176
184
|
supp_type = nil
|
|
177
185
|
supp_number = nil
|
|
186
|
+
supp_version = nil
|
|
178
187
|
supp_year = nil
|
|
179
188
|
supp_stage = nil
|
|
180
189
|
|
|
@@ -203,14 +212,19 @@ module Pubid
|
|
|
203
212
|
end
|
|
204
213
|
end
|
|
205
214
|
|
|
206
|
-
# Check for version (v1, v2, etc.) after year or number
|
|
215
|
+
# Check for version (v1, v2, etc.) after year or number.
|
|
216
|
+
# Legacy year-overloaded wire ("amd:2007:v2" -- the number rode
|
|
217
|
+
# the version slot): a v-token with no preceding number carries
|
|
218
|
+
# the NUMBER. The RFC 5141 additive extension ("amd:1:2007:v2")
|
|
219
|
+
# keeps the number in its own slot, so a v-token after a number
|
|
220
|
+
# is the true <supplversion>.
|
|
207
221
|
if parts.first&.start_with?("v")
|
|
208
|
-
version_str = parts.shift
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
222
|
+
version_str = parts.shift.sub("v", "")
|
|
223
|
+
value = version_str.split(".").first.to_i
|
|
224
|
+
if supp_number.nil?
|
|
225
|
+
supp_number = value
|
|
226
|
+
else
|
|
227
|
+
supp_version = value
|
|
214
228
|
end
|
|
215
229
|
end
|
|
216
230
|
|
|
@@ -219,6 +233,19 @@ module Pubid
|
|
|
219
233
|
supp_year = parts.shift
|
|
220
234
|
end
|
|
221
235
|
|
|
236
|
+
# A v-token after the year ("amd:1:2007:v1") would otherwise be
|
|
237
|
+
# left for the next loop iteration, wrapping a type-less
|
|
238
|
+
# supplement around the real one and losing the base.
|
|
239
|
+
if parts.first&.start_with?("v")
|
|
240
|
+
version_str = parts.shift.sub("v", "")
|
|
241
|
+
value = version_str.split(".").first.to_i
|
|
242
|
+
if supp_number.nil?
|
|
243
|
+
supp_number = value
|
|
244
|
+
else
|
|
245
|
+
supp_version = value
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
222
249
|
# Check for language after supplement
|
|
223
250
|
supp_languages = nil
|
|
224
251
|
if parts.first && !parts.first.match(/^\d+$/) && !parts.first.match?(/^(amd|cor|sup|add|v\d+|stage-)/i)
|
|
@@ -228,6 +255,7 @@ module Pubid
|
|
|
228
255
|
supplements << {
|
|
229
256
|
type: supp_type,
|
|
230
257
|
number: supp_number,
|
|
258
|
+
version: supp_version,
|
|
231
259
|
year: supp_year,
|
|
232
260
|
stage: supp_stage,
|
|
233
261
|
languages: supp_languages,
|
|
@@ -425,12 +453,31 @@ module Pubid
|
|
|
425
453
|
supp_hash = {}
|
|
426
454
|
|
|
427
455
|
if supp[:stage]
|
|
428
|
-
|
|
456
|
+
# A harmonized code resolves through the deliverable type
|
|
457
|
+
# (like the base stage); a supplement-family abbreviation
|
|
458
|
+
# resolves by abbr -- the typed-stage code differs from the
|
|
459
|
+
# abbr ("fdamd" for FDAM), so the stage-code lookup misses.
|
|
460
|
+
typed_stage =
|
|
461
|
+
if supp[:stage].to_s.match?(/\A\d\d\.\d\d\z/)
|
|
462
|
+
# resolve within the supplement's own type family -- the
|
|
463
|
+
# umbrella lookup prefers the IS family, which would turn
|
|
464
|
+
# a staged Corrigendum into a plain IS
|
|
465
|
+
code_str = supp[:stage].to_s
|
|
466
|
+
type_str = supp[:type]&.to_s
|
|
467
|
+
candidates = Pubid::Iso.all_typed_stages
|
|
468
|
+
.select { |st| st.harmonized_stages&.include?(code_str) }
|
|
469
|
+
candidates.find { |st| st.type_code.to_s == type_str } ||
|
|
470
|
+
candidates.find { |st| st.type_code.to_s == "is" } ||
|
|
471
|
+
candidates.first
|
|
472
|
+
else
|
|
473
|
+
Pubid::Iso.locate_stage(supp[:stage].to_s.upcase) ||
|
|
474
|
+
Pubid::Iso.locate_stage_by_stage_code(supp[:stage])
|
|
475
|
+
end
|
|
429
476
|
supp_hash[:type_with_stage] = if
|
|
430
477
|
typed_stage
|
|
431
478
|
typed_stage.abbr.is_a?(Array) ? typed_stage.abbr.first : typed_stage.abbr
|
|
432
479
|
else
|
|
433
|
-
supp[:
|
|
480
|
+
supp[:type]&.to_s&.upcase
|
|
434
481
|
end
|
|
435
482
|
end
|
|
436
483
|
|
|
@@ -444,6 +491,10 @@ typed_stage
|
|
|
444
491
|
supp_hash[:year] = supp[:year].to_s
|
|
445
492
|
end
|
|
446
493
|
|
|
494
|
+
if supp[:version]
|
|
495
|
+
supp_hash[:supplement_version] = supp[:version].to_s
|
|
496
|
+
end
|
|
497
|
+
|
|
447
498
|
if supp[:languages]
|
|
448
499
|
supp_hash[:languages] = supp[:languages].join("/")
|
|
449
500
|
end
|
|
@@ -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,7 +1,7 @@
|
|
|
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.53
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -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
|