uuid-ncname 0.2.1 → 0.2.6

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: 9e388102139409aff9de824bcff21d8a7793796425d781e896deb04ad1032fce
4
- data.tar.gz: 06ff6b9f8f141db4fc5d3458c814be989f315b9f2bb3c77dc9a2ee81ba7d7b0c
3
+ metadata.gz: f82febb1e1498f1d602bd2225b730b7e9128b7ea7b811472465001ae9925e83d
4
+ data.tar.gz: 8f403882f98f9509c074e3b53c1aebe58ff0b0adbe9f248baf4df9ded59b7b25
5
5
  SHA512:
6
- metadata.gz: 66abf5bf9d94bf70b268c5e0a96f99b7579903f6e3dc3c697afcfb99a64acc58da32a1340269d5f93e2a9cec1cdb0f261da21d2c94c94462d5487a80a2301b4b
7
- data.tar.gz: 00e7081505f5a836bf5073e0b7a489a3b3a0e2620f54cc7619224786b09019fc5b9af43448a35393b6679a1256d4729f0a3f174d50d6ecb85a383a56fa5832c1
6
+ metadata.gz: b0c1948dd81504cd7241f2a5ad78e50f661b4d9b0868402fd3e393760a5ddf6d30be82f39b51d700e0ded7681efa65134fb0e37ffa27f2108c238ccb8d2cbdfe
7
+ data.tar.gz: 2c86dfc2b5ee4b1c1be7c1e8343e844bfa9df0a94ebf20b487fd5988b53df4e138ae05e44d5134b00c4e1092140d24042c3e1c5d90ad9238a87fea65ab165f3c
data/.gitignore CHANGED
@@ -7,6 +7,7 @@ syntax: glob
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
10
11
 
11
12
  # rspec failure tracking
12
13
  .rspec_status
data/README.md CHANGED
@@ -83,14 +83,13 @@ variants.
83
83
 
84
84
  Since I have already released this gem prior to this format change, I
85
85
  have added a `:version` parameter to both `to_ncname` and
86
- `from_ncname`. The version currently defaults to `0`, the old one, but
87
- will issue a warning if not explicitly set. Later I will change the
88
- default to `1`, while keeping the warning, then later still, finally
89
- remove the warning with 1 as the default. This should ensure that any
90
- code written during the transition produces the correct results.
86
+ `from_ncname`. The version, as of 0.2.4, now defaults to `1`, the
87
+ current one, but will still issue a warning if not explicitly
88
+ set. Later I will finally remove the warning. This should ensure that
89
+ any code written during the transition produces the correct results.
91
90
 
92
91
  > Unless you have to support identifiers generated from version 0.1.3
93
- > or newer, you should be running these methods with `version: 1`.
92
+ > or older, you should be running these methods with `version: 1`.
94
93
 
95
94
  ## Rationale & Method
96
95
 
@@ -116,8 +116,9 @@ module UUID::NCName
116
116
  ],
117
117
  ]
118
118
 
119
- def self.encode_version version
120
- ((version & 15) + 65).chr
119
+ def self.encode_version version, radix
120
+ offset = radix == 32 ? 97 : 65
121
+ ((version & 15) + offset).chr
121
122
  end
122
123
 
123
124
  def self.decode_version version
@@ -127,7 +128,7 @@ module UUID::NCName
127
128
  def self.warn_version version
128
129
  if version.nil?
129
130
  warn 'Set an explicit :version to remove this warning. See documentation.'
130
- version = 0
131
+ version = 1
131
132
  end
132
133
 
133
134
  raise 'Version must be 0 or 1' unless [0, 1].include? version
@@ -137,6 +138,27 @@ module UUID::NCName
137
138
 
138
139
  public
139
140
 
141
+ # This error gets thrown when a UUID-NCName token can't be
142
+ # positively determined to be one version or the other.
143
+ class AmbiguousToken < ArgumentError
144
+
145
+ # @return [String] The ambiguous token
146
+ attr_reader :token
147
+ # @return [String] The UUID when decoded using version 0
148
+ attr_reader :v0
149
+ # @return [String] The UUID when decoded using version 1
150
+ attr_reader :v1
151
+
152
+ # @param token [#to_s] The token in question
153
+ # @param v0 [#to_s] UUID decoded with decoding scheme version 0
154
+ # @param v1 [#to_s] UUID decoded with decoding scheme version 1
155
+
156
+ def initialize token, v0: nil, v1: nil
157
+ @v0 = v0 || from_ncname(token, version: 0)
158
+ @v1 = v1 || from_ncname(token, version: 1)
159
+ end
160
+ end
161
+
140
162
  # Converts a UUID (or object that when converted to a string looks
141
163
  # like a UUID) to an NCName. By default it produces the Base64
142
164
  # variant.
@@ -148,10 +170,10 @@ module UUID::NCName
148
170
  # @param radix [32, 64] either the number 32 or the number 64.
149
171
  #
150
172
  # @param version [0, 1] An optional formatting version, where 0 is
151
- # the naïve original version and 1 moves the `variant` nybble out
152
- # to the end of the identifier. You will be warned if you do not
153
- # set this parameter explicitly. The default is currently 0, but
154
- # will change in the next version.
173
+ # the naïve original version and 1 moves the +variant+ nybble out
174
+ # to the end of the identifier. You will be warned for the time
175
+ # being if you do not set this parameter explicitly. The default
176
+ # version is 1.
155
177
  #
156
178
  # @param align [true, false] Optional directive to treat the
157
179
  # terminating character as aligned to the numerical base of the
@@ -160,9 +182,10 @@ module UUID::NCName
160
182
  # Base64, the overhang is only ever 4 bits. This means that when
161
183
  # the terminating character is aligned, it will always be in the
162
184
  # range of the letters A through P in (the RFC 3548/4648
163
- # representations of) both Base32 and Base64. When `version` is 1
185
+ # representations of) both Base32 and Base64. When +version+ is 1
164
186
  # and the terminating character is aligned, RFC4122-compliant UUIDs
165
- # will always terminate with I, J, K, or L. Defaults to `true`.
187
+ # will always terminate with +I+, +J+, +K+, or +L+. Defaults to
188
+ # +true+.
166
189
  #
167
190
  # @return [String] The NCName-formatted UUID.
168
191
 
@@ -170,7 +193,7 @@ module UUID::NCName
170
193
  raise 'Radix must be either 32 or 64' unless [32, 64].include? radix
171
194
  raise 'UUID must be something stringable' if uuid.nil? or
172
195
  not uuid.respond_to? :to_s
173
- raise 'Align must be true or false' unless [true, false].include? align
196
+ align = !!align # coerce to a boolean
174
197
 
175
198
  # XXX remove this when appropriate
176
199
  version = warn_version(version)
@@ -195,14 +218,14 @@ module UUID::NCName
195
218
  raise 'Binary representation of UUID is shorter than 16 bytes' if
196
219
  bin.length < 16
197
220
 
198
- uuidver, content = TRANSFORM[version][0].call bin[0, 16]
221
+ uuidver, content = TRANSFORM[version].first.call bin[0, 16]
199
222
 
200
- encode_version(uuidver) + ENCODE[radix].call(content, align)
223
+ encode_version(uuidver, radix) + ENCODE[radix].call(content, align)
201
224
  end
202
225
 
203
226
  # Converts an NCName-encoded UUID back to its canonical
204
227
  # representation. Will return nil if the input doesn't match the
205
- # radix (if supplied) or is otherwise malformed. doesn't match
228
+ # radix (if supplied) or is otherwise malformed.
206
229
  #
207
230
  # @param ncname [#to_s] an NCName-encoded UUID, either a
208
231
  # 22-character (Base64) variant, or a 26-character (Base32) variant.
@@ -210,19 +233,22 @@ module UUID::NCName
210
233
  # @param radix [nil, 32, 64] Optional radix; will use heuristic if omitted.
211
234
  #
212
235
  # @param format [:str, :hex, :b64, :bin] An optional formatting
213
- # parameter; defaults to `:str`, the canonical string representation.
236
+ # parameter; defaults to +:str+, the canonical string representation.
214
237
  #
215
- # @param version [0, 1] See `to_ncname`. Defaults (for now) to 0.
238
+ # @param version [0, 1] See ::to_ncname. Defaults to 1.
216
239
  #
217
- # @param align [true, false, nil] See `to_ncname` for details.
218
- # Setting this parameter to `nil`, the default, will cause the
240
+ # @param align [nil, true, false] See ::to_ncname for details.
241
+ # Setting this parameter to +nil+, the default, will cause the
219
242
  # decoder to detect the alignment state from the identifier.
220
243
  #
244
+ # @param validate [false, true] Check that the ninth (the variant)
245
+ # octet is correctly masked _after_ decoding.
246
+ #
221
247
  # @return [String, nil] The corresponding UUID or nil if the input
222
248
  # is malformed.
223
249
 
224
250
  def self.from_ncname ncname,
225
- radix: nil, format: :str, version: nil, align: nil
251
+ radix: nil, format: :str, version: nil, align: nil, validate: false
226
252
  raise 'Format must be symbol-able' unless format.respond_to? :to_sym
227
253
  raise "Invalid format #{format}" unless FORMAT[format]
228
254
  raise 'Align must be true, false, or nil' unless
@@ -262,6 +288,9 @@ module UUID::NCName
262
288
 
263
289
  bin = TRANSFORM[version][1].call uuidver, content
264
290
 
291
+ # double-check the variant (high-order bits have to be 10)
292
+ return if validate and bin[8].ord >> 6 != 2
293
+
265
294
  FORMAT[format].call bin
266
295
  end
267
296
 
@@ -269,9 +298,9 @@ module UUID::NCName
269
298
  #
270
299
  # @param uuid [#to_s] The UUID
271
300
  #
272
- # @param version [0, 1] See `to_ncname`.
301
+ # @param version [0, 1] See ::to_ncname.
273
302
  #
274
- # @param align [true, false] See `to_ncname`.
303
+ # @param align [true, false] See ::to_ncname.
275
304
  #
276
305
  # @return [String] The Base64-encoded NCName
277
306
 
@@ -285,9 +314,9 @@ module UUID::NCName
285
314
  #
286
315
  # @param format [:str, :hex, :b64, :bin] The format
287
316
  #
288
- # @param version [0, 1] See `to_ncname`.
317
+ # @param version [0, 1] See ::to_ncname.
289
318
  #
290
- # @param align [true, false] See `to_ncname`.
319
+ # @param align [true, false] See ::to_ncname.
291
320
  #
292
321
  # @return [String, nil] The corresponding UUID or nil if the input
293
322
  # is malformed.
@@ -300,9 +329,9 @@ module UUID::NCName
300
329
  #
301
330
  # @param uuid [#to_s] The UUID
302
331
  #
303
- # @param version [0, 1] See `to_ncname`.
332
+ # @param version [0, 1] See ::to_ncname.
304
333
  #
305
- # @param align [true, false] See `to_ncname`.
334
+ # @param align [true, false] See ::to_ncname.
306
335
  #
307
336
  # @return [String] The Base32-encoded NCName
308
337
 
@@ -316,9 +345,9 @@ module UUID::NCName
316
345
  #
317
346
  # @param format [:str, :hex, :b64, :bin] The format
318
347
  #
319
- # @param version [0, 1] See `to_ncname`.
348
+ # @param version [0, 1] See ::to_ncname.
320
349
  #
321
- # @param align [true, false] See `to_ncname`.
350
+ # @param align [true, false] See ::to_ncname.
322
351
  #
323
352
  # @return [String, nil] The corresponding UUID or nil if the input
324
353
  # is malformed.
@@ -327,4 +356,46 @@ module UUID::NCName
327
356
  from_ncname ncname, radix: 32, format: format
328
357
  end
329
358
 
359
+ # Test if the given token is a UUID NCName, with a hint to its
360
+ # version. This method can positively identify a token as a UUID
361
+ # NCName, but there is a small subset of UUIDs which will produce
362
+ # tokens which are valid in both versions. The method returns
363
+ # +false+ if the token is invalid, otherwise it returns +0+ or +1+
364
+ # for the guessed version.
365
+ #
366
+ # @note Version 1 tokens always end with +I+, +J+, +K+, or +L+ (with
367
+ # base32 being case-insensitive), so tokens that end in something
368
+ # else will always be version 0.
369
+ #
370
+ # @param token [#to_s] The token to test
371
+ #
372
+ # @param strict [false, true]
373
+ #
374
+ # @return [false, 0, 1]
375
+ def self.valid? token, strict: false
376
+ token = token.to_s
377
+ if /^[A-Pa-p](?:[0-9A-Za-z_-]{21}|[2-7A-Za-z]{25})$/.match token
378
+ # false is definitely version zero but true is only maybe version 1
379
+ version = /^(?:.{21}[I-L]|.{25}[I-Li-l])$/.match(token) ? 1 : 0
380
+
381
+ # try decoding with validation on
382
+ uu = from_ncname token, version: version, validate: true
383
+
384
+ # note that version 1 will always return something because the
385
+ # method of detecting it is a version 1 also happens to be the
386
+ # method of determining whether or not it is valid.
387
+ return false unless uu
388
+
389
+ if version == 1 and strict
390
+ # but we can also check if the input is a valid version 0
391
+ u0 = from_ncname token, version: 0, validate: true
392
+ raise AmbiguousToken.new(token, v0: u0, v1: uu) if u0
393
+ end
394
+
395
+ version
396
+ else
397
+ false
398
+ end
399
+ end
400
+
330
401
  end
@@ -1,7 +1,10 @@
1
+ # this is here because it reasonable to expect a *class* in the
2
+ # namespace called UUID, so if you say `module UUID; module NCName`,
3
+ # it will croak with a "TypeError: UUID is not a module".
1
4
  unless Module.const_defined? 'UUID'
2
5
  module UUID; end
3
6
  end
4
7
 
5
8
  module UUID::NCName
6
- VERSION = "0.2.1"
9
+ VERSION = "0.2.6"
7
10
  end
@@ -33,9 +33,9 @@ DESC
33
33
  # spec.add_runtime_dependency 'uuidtools', '~> 2.1.5'
34
34
  spec.add_runtime_dependency 'base32', '~> 0.3.2'
35
35
 
36
- spec.add_development_dependency 'bundler', '~> 1.16'
37
- spec.add_development_dependency 'rake', '~> 10.0'
38
- spec.add_development_dependency 'rspec', '~> 3.0'
36
+ spec.add_development_dependency 'bundler', '~> 2.1'
37
+ spec.add_development_dependency 'rake', '~> 13.0'
38
+ spec.add_development_dependency 'rspec', '~> 3.9'
39
39
 
40
40
  # only need it for testing, who knew
41
41
  # spec.add_development_dependency 'uuidtools', '~> 2.1.5'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uuid-ncname
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Taylor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-25 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32
@@ -30,42 +30,42 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.16'
33
+ version: '2.1'
34
34
  type: :development
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.16'
40
+ version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '3.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: '3.9'
69
69
  description: |
70
70
  This module creates an isomorphic representation of a UUID which is
71
71
  guaranteed to fit into the grammar of the XML NCName construct, which
@@ -110,8 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  requirements: []
113
- rubyforge_project:
114
- rubygems_version: 2.7.6
113
+ rubygems_version: 3.1.2
115
114
  signing_key:
116
115
  specification_version: 4
117
116
  summary: Format a UUID as a valid NCName.