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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3536887018197616db633b2dda189aca2cca4fefd5f9c12cdc0fef1bd217e1cc
4
- data.tar.gz: a8761e51a146f907c3964f1263fcfe4e86a35cae5f62e005ea8020c4425e59a0
3
+ metadata.gz: 4013c9f2d03ae3ad7ebdafd0f22176d7c72bca2a584ce7ba5dc1c9734cd539f0
4
+ data.tar.gz: 6b1b1629bd55bef868ac6a8d094b29e573b5a398210bce5df1b5ff593d2484c2
5
5
  SHA512:
6
- metadata.gz: 97a946c6087270e564c588ec4d8817fd09ea2b945bcfbb304dd39c346ea8a68e624775c4afa16c93ed0633598458a188e96bdc923651896b1e71e19ac9b55c39
7
- data.tar.gz: e38a7dd24f3804a18dcb4ae67186542d509fe9cfad18a5d51a8f34b9ba740d313c0d3a82034f182d699864c90d8835acef255733ffe5410d0c3d318bf5e1b472
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
- define_method(:data_to_model) do |data, _format, _options = {}|
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
@@ -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
- if supp.date
138
- parts << supp.date.render(context: URN_CONTEXT)
139
- if supp.number
140
- if supp.stage_iteration && !supp.is_a?(Pubid::Iso::Identifiers::Supplement)
141
- parts << "v#{supp.number}.#{supp.stage_iteration.render(context: URN_CONTEXT)}"
142
- else
143
- parts << "v#{supp.number}"
144
- end
145
- end
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 << supp.number.to_s if supp.number
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
- combined_key = nil
212
- dtc = document_type_code&.to_s
213
- if dtc && dtc != "is" && dtc != ""
214
- combined_key = :"#{stage_code}#{dtc}"
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
 
@@ -34,7 +34,10 @@ module Pubid
34
34
  SUPPLEMENT_TYPE_MAP = {
35
35
  "amd" => :amd,
36
36
  "cor" => :cor,
37
- "sup" => :sup,
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
- supp_number = version_str.sub("v", "").to_i
210
- # Handle version with iteration (v1.2)
211
- if supp_number.to_s.include?(".")
212
- supp_number, = supp_number.to_s.split(".")
213
- supp_number = supp_number.to_i
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
- typed_stage = Pubid::Iso.locate_stage_by_stage_code(supp[:stage])
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[:stage].to_s.upcase
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pubid
4
- VERSION = "2.0.0.pre.alpha.51"
4
+ VERSION = "2.0.0.pre.alpha.53"
5
5
  end
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
- eager_load_flavors!
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.51
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