pubid-iec 1.15.20 → 1.15.21

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: 3ccffba7aaa5a3e66b66a19ab5740b27eb6ff99934e3b16ad98a6892058b8996
4
- data.tar.gz: b8bc82a61191c48aa37001af8311ff1c374654086ced0f1b64322c982f370e70
3
+ metadata.gz: f6c4c33c3e0c5a6ac9eea2d75c8e305a022a87804281baa31e9ffc4e91f29888
4
+ data.tar.gz: f9d685bc29bf07032d97a97ff70daf1c324df1f0f10d5a42ca7bfa52a50f9308
5
5
  SHA512:
6
- metadata.gz: 5a651b8cd80493b51ef75fd6c3d94a30c0cee96164a2f2569c55ea645744f7ddc591bd974b40c94c489e06f4081db25f2bbe66205dd79892eb3ba332a751ac10
7
- data.tar.gz: 0734ee8afb0cb0ca7271c4ebbf7e4c80db97af1d57f1c332ba33075209365a36386d1ce2e16236388cae8abb5de08b8de11023a4953fe3ff2c5a47581561011a
6
+ metadata.gz: b15519521d3a6c26e0a89a6b1bb3b9995a4daec97a58d435ba626457ae7d014f3d098911f6fe2bc81ba5fcaed06199f6523065cfb292c23e2edf9caeec2b9315
7
+ data.tar.gz: ca1363b31d730ca72a0ad42cfdf9728c1622bef91b5489504f994e788b58a56573b20eab4436cd20ed45f02248d9eebc22cc1fa551dd23fce38dc892dae72b83
@@ -129,7 +129,11 @@ module Pubid::Iec
129
129
 
130
130
  def normalize_urn_params!(params)
131
131
  params[:publisher] = params[:publisher].to_s.upcase
132
- params[:copublisher] = params[:copublisher].to_s.upcase if params[:copublisher]
132
+ # copublisher may be an array (e.g. ISO/IEC/IEEE -> [iec, ieee]);
133
+ # upcase each element rather than the array's inspect string.
134
+ if params[:copublisher]
135
+ params[:copublisher] = Array(params[:copublisher]).map { |c| c.to_s.upcase }
136
+ end
133
137
  params[:type] = params[:type].to_s.upcase if params[:type]
134
138
  params[:number] = params[:number].to_s.upcase
135
139
 
@@ -142,8 +146,9 @@ module Pubid::Iec
142
146
  end
143
147
  end
144
148
 
145
- # Remove amendments/corrigendums parsed as bare strings from URN
146
- # (full supplement round-trip support to be added later)
149
+ # Canonical URN supplements parse into amendment/corrigendum objects
150
+ # (see ParserUrn#urn_supplements). This guard only drops any stray
151
+ # bare-string capture, which the canonical grammar no longer produces.
147
152
  params.delete(:amendments) if params[:amendments].is_a?(String)
148
153
  params.delete(:corrigendums) if params[:corrigendums].is_a?(String)
149
154
  end
@@ -64,20 +64,28 @@ module Pubid
64
64
  (dash >> array_to_str(VAP_CODES).as(:vap)).repeat
65
65
  end
66
66
 
67
- rule(:urn_edition) do
68
- (str("ed-") >> digits.as(:edition)).maybe
67
+ # Canonical deliverable slot: a deliverable code (csv/rlv/ser/…) or,
68
+ # when absent, the edition (ed-N). The two never co-occur.
69
+ rule(:urn_slot3) do
70
+ (urn_vap | (str("ed-") >> digits.as(:edition))).maybe
71
+ end
72
+
73
+ # Canonical adjunct: relation-marker ("::" normal, ":plus:"
74
+ # consolidated) + kind + ":" number + optional ":" date.
75
+ rule(:relation_marker) do
76
+ str(":plus:") | str("::")
69
77
  end
70
78
 
71
79
  rule(:urn_amendment) do
72
- colon >> str("amd").as(:amendments) >>
73
- (colon >> (year_digits | digits).as(:number)).maybe >>
74
- (colon >> str("v") >> digits.as(:iteration)).maybe
80
+ (relation_marker >> str("amd") >> colon >>
81
+ digits.as(:number) >>
82
+ (colon >> year_digits.as(:year)).maybe).as(:amendments)
75
83
  end
76
84
 
77
85
  rule(:urn_corrigendum) do
78
- colon >> str("cor").as(:corrigendums) >>
79
- (colon >> (year_digits | digits).as(:number)).maybe >>
80
- (colon >> str("v") >> digits.as(:iteration)).maybe
86
+ (relation_marker >> str("cor") >> colon >>
87
+ digits.as(:number) >>
88
+ (colon >> year_digits.as(:year)).maybe).as(:corrigendums)
81
89
  end
82
90
 
83
91
  rule(:urn_supplements) do
@@ -92,14 +100,17 @@ module Pubid
92
100
  (array_to_str(LANGUAGES) >> (dash >> array_to_str(LANGUAGES)).repeat).as(:language)
93
101
  end
94
102
 
103
+ # Positional structure: pub[:type]:number[-part][,conj]
104
+ # :date:stage:deliverable:language{adjuncts}[fragment]
95
105
  rule(:urn_identifier) do
96
106
  str("urn:iec:std:") >> urn_publisher_copublisher >> urn_type >>
97
107
  urn_number >> urn_part >> urn_conjuction_part >>
98
108
  (colon >> urn_year >>
99
- (colon >> (urn_stage | urn_vap).maybe >>
100
- (colon >> urn_edition >>
101
- urn_supplements >> urn_fragment >>
102
- (colon >> urn_language.maybe).maybe
109
+ (colon >> urn_stage.maybe >>
110
+ (colon >> urn_slot3 >>
111
+ (colon >> urn_language.maybe >>
112
+ urn_supplements >> urn_fragment
113
+ ).maybe
103
114
  ).maybe
104
115
  ).maybe
105
116
  ).maybe
@@ -2,10 +2,14 @@ module Pubid::Iec::Renderer
2
2
  class TrfUrn < Urn
3
3
 
4
4
  def render_identifier(params)
5
+ # Trailing ":" is the (always-empty) language slot; TRF URNs carry no
6
+ # language. Previously this colon came from the base #render appending
7
+ # ":#{lang}", which no longer runs (language is now a positional slot in
8
+ # the base render_identifier, which TrfUrn overrides).
5
9
  "urn:iec:std:%{publisher}%{copublisher}:trf%{trf_publisher}:%{number}"\
6
10
  "%{part}%{conjuction_part}%{year}%{vap}"\
7
11
  "%{version}%{part_version}"\
8
- "%{trf_version}" % params
12
+ "%{trf_version}:" % params
9
13
  end
10
14
 
11
15
  def render_trf_version(trf_version, _opts, _params)
@@ -52,22 +52,45 @@ module Pubid::Iec::Renderer
52
52
  WPUB: 95.99
53
53
  }.freeze
54
54
 
55
+ # Renders the ABNF-canonical IEC URN (ground truth in relaton-data-iec):
56
+ #
57
+ # urn:iec:std:{pub}[-{copub}][:{type}]:{number}[-{part}][,{conj}]
58
+ # :{date}:{stage}:{deliverable}:{language}{adjuncts}[{fragment}]
59
+ #
60
+ # The four positional slots after the number/part are always colon-
61
+ # separated even when empty. Amendments/corrigenda follow the language
62
+ # slot with a "::" (or ":plus:" for a consolidated amendment) relation-
63
+ # marker; see #render_amendments / #render_corrigendums.
55
64
  def render_identifier(params)
56
65
  result = "urn:iec:std:#{params[:publisher]}#{params[:copublisher]}" \
57
66
  "#{params[:type]}:#{params[:number]}" \
58
67
  "#{params[:part]}#{params[:conjuction_part]}"
59
68
 
60
- # Positional fields — always colon-separated even when empty
69
+ # Positional slots — always colon-separated even when empty.
61
70
  result += ":#{strip_leading_colon(params[:year])}"
62
71
 
63
- stage_value = [params[:stage], params[:vap], params[:urn_stage],
72
+ # Stage slot (deliverable/vap is no longer folded in here; it has its
73
+ # own canonical deliverable slot below).
74
+ stage_value = [params[:stage], params[:urn_stage],
64
75
  params[:corrigendum_stage], params[:iteration],
65
76
  params[:version], params[:part_version]].map(&:to_s).join
66
77
  result += ":#{strip_leading_colon(stage_value)}"
67
78
 
68
- result += ":#{strip_leading_colon(params[:edition])}"
79
+ # Deliverable slot: "ser" (all parts), a deliverable code (csv/rlv/…),
80
+ # or the edition (ed-N) when neither is present.
81
+ deliverable = deliverable_slot(params)
82
+ result += ":#{deliverable}"
83
+
84
+ # Language slot. A bare (undated, stage/language/adjunct-less) all-parts
85
+ # series omits the trailing empty language slot, matching the canonical
86
+ # relaton-data-iec form: urn:iec:std:iec:80000:::ser (not ...:ser:). A
87
+ # dated series (...:2026::ser:) or a deliverable (...::rlv:) keeps it.
88
+ unless bare_series?(deliverable, stage_value, params)
89
+ result += ":#{strip_leading_colon(params[:language].to_s)}"
90
+ end
69
91
 
70
- # Non-positional suffixes
92
+ # Adjuncts (amendments/corrigenda) with the relation-marker, then any
93
+ # fragment.
71
94
  result += params[:amendments].to_s
72
95
  result += params[:corrigendums].to_s
73
96
  result += params[:fragment].to_s
@@ -76,15 +99,9 @@ module Pubid::Iec::Renderer
76
99
  end
77
100
 
78
101
  def render(with_date: true, with_language_code: :iso, annotated: false, **args)
79
- base = render_base_identifier(**args.merge(
102
+ render_base_identifier(**args.merge(
80
103
  with_date: with_date, with_language_code: with_language_code, annotated: annotated,
81
104
  ))
82
- lang = strip_leading_colon(@prerendered_params[:language].to_s)
83
- if @prerendered_params.key?(:all_parts)
84
- "#{base}ser"
85
- else
86
- "#{base}:#{lang}"
87
- end
88
105
  end
89
106
 
90
107
  def render_part(part, _opts, _params)
@@ -127,12 +144,26 @@ module Pubid::Iec::Renderer
127
144
  ":#{type.downcase}"
128
145
  end
129
146
 
130
- def render_amendments(amendments, _opts, _params)
131
- amendments&.map(&:urn)&.join || ""
147
+ # Amendments render as "{marker}amd:{number}[:{date}]". The marker is
148
+ # ":plus:" when the base is a consolidation (CSV/CMV) the amendment is
149
+ # merged into the consolidated document — otherwise "::".
150
+ def render_amendments(amendments, _opts, params)
151
+ marker = consolidated_deliverable?(params) ? ":plus:" : "::"
152
+ Array(amendments).map do |amendment|
153
+ s = "#{marker}amd:#{amendment.number}"
154
+ s += ":#{amendment.year}" if amendment.year
155
+ s
156
+ end.join
132
157
  end
133
158
 
159
+ # Corrigenda always use the "::" relation-marker (they are separate
160
+ # corrections, never merged into a consolidation).
134
161
  def render_corrigendums(corrigendums, _opts, _params)
135
- corrigendums&.map(&:urn)&.join || ""
162
+ Array(corrigendums).map do |corrigendum|
163
+ s = "::cor:#{corrigendum.number}"
164
+ s += ":#{corrigendum.year}" if corrigendum.year
165
+ s
166
+ end.join
136
167
  end
137
168
 
138
169
  def render_language(language, _opts, _params)
@@ -145,6 +176,48 @@ module Pubid::Iec::Renderer
145
176
 
146
177
  private
147
178
 
179
+ # The canonical deliverable slot: "ser" for an all-parts series, else the
180
+ # rendered deliverable code (csv/rlv/cmv/exv/…), else the edition (ed-N).
181
+ # Deliverable and edition never co-occur in practice, so one slot serves
182
+ # both.
183
+ def deliverable_slot(params)
184
+ if present?(params[:all_parts])
185
+ "ser"
186
+ elsif present?(params[:vap])
187
+ strip_leading_colon(params[:vap])
188
+ elsif present?(params[:edition])
189
+ strip_leading_colon(params[:edition])
190
+ else
191
+ ""
192
+ end
193
+ end
194
+
195
+ # True for a bare all-parts series — deliverable "ser" with no date, stage,
196
+ # language or adjuncts — whose canonical URN drops the trailing language
197
+ # slot (urn:iec:std:iec:80000:::ser). Keyed on the rendered deliverable so
198
+ # it holds whether the series is carried as +all_parts+ or a +ser+ vap.
199
+ def bare_series?(deliverable, stage_value, params)
200
+ return false unless deliverable == "ser"
201
+ if present?(stage_value) || present?(params[:year]) ||
202
+ present?(params[:language])
203
+ return false
204
+ end
205
+
206
+ [params[:amendments], params[:corrigendums], params[:fragment]]
207
+ .all? { |adjunct| adjunct.to_s.empty? }
208
+ end
209
+
210
+ # True when the base document is a consolidation that merges its
211
+ # amendments (CSV/CMV deliverable).
212
+ def consolidated_deliverable?(params)
213
+ Array(params[:vap]).map { |v| v.to_s.downcase }
214
+ .any? { |v| %w[csv cmv].include?(v) }
215
+ end
216
+
217
+ def present?(value)
218
+ !value.nil? && !value.to_s.empty?
219
+ end
220
+
148
221
  def strip_leading_colon(value)
149
222
  s = value.to_s
150
223
  s.start_with?(":") ? s[1..] : s
@@ -1,5 +1,5 @@
1
1
  module Pubid
2
2
  module Iec
3
- VERSION = "1.15.20".freeze
3
+ VERSION = "1.15.21".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubid-iec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.20
4
+ version: 1.15.21
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-06-26 00:00:00.000000000 Z
11
+ date: 2026-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.15.20
33
+ version: 1.15.21
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.15.20
40
+ version: 1.15.21
41
41
  description: Library to generate, parse and manipulate IEC PubID.
42
42
  email:
43
43
  - open.source@ribose.com