uuid-ncname 0.2.5 → 0.4.0
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/.gitignore +2 -0
- data/.yardopts +5 -0
- data/README.md +66 -69
- data/lib/uuid/ncname/version.rb +1 -1
- data/lib/uuid/ncname.rb +157 -55
- data/uuid-ncname.gemspec +5 -4
- metadata +28 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 471f6d4d6e5124454b7bcc1a7ab46fc3f6fbf6951f4ba988c80a9b04f0051be1
|
|
4
|
+
data.tar.gz: 03265d39a6f8b4c38ad9d86ddab9753563216c4ac3421a5cff9f38f1e536d4e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 311e0f9856467d875782d37ac759ec2479d74276ad2ec427588954ab22335e233d69f2d32e6ceaf20a24e91eba8a2cd780721f89f5a829c7acf346ab78b20401
|
|
7
|
+
data.tar.gz: d9458bc9b998ac9fb0d5450e66a73d49bbc5bd546250d221045c4b17361cc9a02fa9a0c9b2dbf012686e4bc0c60336635b6946e7f531a8ba80900336e24affa9
|
data/.gitignore
CHANGED
data/.yardopts
ADDED
data/README.md
CHANGED
|
@@ -7,19 +7,17 @@ require 'uuidtools'
|
|
|
7
7
|
uu = UUIDTools::UUID.random_create
|
|
8
8
|
# => #<UUID:0x3fff0e597ef8 UUID:df521e0a-9d57-4f04-9a95-fc2888decc5a>
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
nc64 = UUID::NCName.to_ncname uu, version: 1
|
|
10
|
+
nc64 = UUID::NCName.to_ncname uu
|
|
13
11
|
# => "E31IeCp1X8EqV_CiI3sxaJ"
|
|
14
12
|
|
|
15
|
-
nc32 = UUID::NCName.to_ncname_32 uu
|
|
13
|
+
nc32 = UUID::NCName.to_ncname_32 uu
|
|
16
14
|
# => "E35jb4cu5k7yevfp4fcen5tc2j"
|
|
17
15
|
|
|
18
|
-
orig = UUID::NCName.from_ncname nc64
|
|
16
|
+
orig = UUID::NCName.from_ncname nc64
|
|
19
17
|
# => "df521e0a-9d57-4f04-9a95-fc2888decc5a"
|
|
20
18
|
|
|
21
|
-
orig == UUID::NCName.from_ncname nc32
|
|
22
|
-
orig == uu.to_s
|
|
19
|
+
orig == UUID::NCName.from_ncname nc32 # => true
|
|
20
|
+
orig == uu.to_s # => true
|
|
23
21
|
|
|
24
22
|
# then you can turn it back into an object or whatever
|
|
25
23
|
uu == UUIDTools::UUID.parse(orig) # => true
|
|
@@ -27,69 +25,12 @@ uu == UUIDTools::UUID.parse(orig) # => true
|
|
|
27
25
|
|
|
28
26
|
## Description
|
|
29
27
|
|
|
30
|
-
The purpose of this module is to devise an alternative
|
|
28
|
+
The purpose of this module is to [devise an alternative
|
|
29
|
+
representation](https://datatracker.ietf.org/doc/html/draft-taylor-uuid-ncname)
|
|
31
30
|
of the [UUID](http://tools.ietf.org/html/rfc4122) which conforms to
|
|
32
|
-
the constraints of various other identifiers such as NCName, and
|
|
33
|
-
[isomorphic](http://en.wikipedia.org/wiki/Isomorphism)
|
|
34
|
-
them.
|
|
35
|
-
|
|
36
|
-
## _FORMAT DEPRECATION NOTICE_
|
|
37
|
-
|
|
38
|
-
After careful consideration, I have decided to change the UUID-NCName
|
|
39
|
-
format in a minor yet incompatible way. In particular, I have moved
|
|
40
|
-
the nybble containing
|
|
41
|
-
the [`variant`](https://tools.ietf.org/html/rfc4122#section-4.1.1) to
|
|
42
|
-
the very end of the identifier, whereas it previously was mixed into
|
|
43
|
-
the middle somewhere.
|
|
44
|
-
|
|
45
|
-
This can be considered an application
|
|
46
|
-
of [Postel's Law](https://en.wikipedia.org/wiki/Postel%27s_law), based
|
|
47
|
-
on the assumption that these identifiers will be generated through
|
|
48
|
-
other methods, and potentially naïvely. Like the `version` field, the
|
|
49
|
-
`variant` field has a limited acceptable range of values. If, for
|
|
50
|
-
example, one were to attempt to generate a conforming identifier by
|
|
51
|
-
simply generating a random Base32 or Base64 string, it will be
|
|
52
|
-
difficult to ensure that the `variant` field will indeed conform when
|
|
53
|
-
the identifier is converted to a standard UUID. By moving the
|
|
54
|
-
`variant` field out to the end of the identifier, everything between
|
|
55
|
-
the `version` and `variant` bookends can be generated randomly without
|
|
56
|
-
any further consideration, like so:
|
|
57
|
-
|
|
58
|
-
```ruby
|
|
59
|
-
B64_ALPHA = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + %w(- _)
|
|
60
|
-
|
|
61
|
-
def make_cheapo_b64_uuid_ncname
|
|
62
|
-
vals = (1..20).map { rand 64 } # generate the content
|
|
63
|
-
vals.push(rand(4) + 8) # last digit is special
|
|
64
|
-
'E' + vals.map { |v| B64_ALPHA[v] }.join('') # 'E' for UUID v4
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# voilà:
|
|
68
|
-
|
|
69
|
-
cheap = make_cheapo_b64_uuid_ncname
|
|
70
|
-
# => "EXSVv8ezPbSKWoKOkBNWKL"
|
|
71
|
-
|
|
72
|
-
# now try changing it to a standard UUID:
|
|
73
|
-
|
|
74
|
-
UUID::NCName.from_ncname cheap, version: 1
|
|
75
|
-
# => "5d256ff1-eccf-46d2-b296-a0a3a404d58a"
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Furthermore, since the default behaviour is to align the bits of the
|
|
79
|
-
last byte to the size of the encoding symbol, and since the `variant`
|
|
80
|
-
bits are masked, a compliant RFC4122 UUID will _always_ end with `I`,
|
|
81
|
-
`J`, `K`, or `L`, in _both_ Base32 (case-insensitive) and Base64
|
|
82
|
-
variants.
|
|
83
|
-
|
|
84
|
-
Since I have already released this gem prior to this format change, I
|
|
85
|
-
have added a `:version` parameter to both `to_ncname` and
|
|
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.
|
|
90
|
-
|
|
91
|
-
> Unless you have to support identifiers generated from version 0.1.3
|
|
92
|
-
> or older, you should be running these methods with `version: 1`.
|
|
31
|
+
the constraints of various other identifiers such as NCName, and
|
|
32
|
+
create an [isomorphic](http://en.wikipedia.org/wiki/Isomorphism)
|
|
33
|
+
mapping between them.
|
|
93
34
|
|
|
94
35
|
## Rationale & Method
|
|
95
36
|
|
|
@@ -198,6 +139,62 @@ representation should be adequate for placeholder symbols in just
|
|
|
198
139
|
about any programming language, save for those which do not permit
|
|
199
140
|
identifiers as long as 26 characters (which are extremely scarce).
|
|
200
141
|
|
|
142
|
+
## _FORMAT DEPRECATION NOTICE_
|
|
143
|
+
|
|
144
|
+
After careful consideration, I have decided to change the UUID-NCName
|
|
145
|
+
format in a minor yet incompatible way. In particular, I have moved
|
|
146
|
+
the nybble containing
|
|
147
|
+
the [`variant`](https://tools.ietf.org/html/rfc4122#section-4.1.1) to
|
|
148
|
+
the very end of the identifier, whereas it previously was mixed into
|
|
149
|
+
the middle somewhere.
|
|
150
|
+
|
|
151
|
+
This can be considered an application
|
|
152
|
+
of [Postel's Law](https://en.wikipedia.org/wiki/Postel%27s_law), based
|
|
153
|
+
on the assumption that these identifiers will be generated through
|
|
154
|
+
other methods, and potentially naïvely. Like the `version` field, the
|
|
155
|
+
`variant` field has a limited acceptable range of values. If, for
|
|
156
|
+
example, one were to attempt to generate a conforming identifier by
|
|
157
|
+
simply generating a random Base32 or Base64 string, it will be
|
|
158
|
+
difficult to ensure that the `variant` field will indeed conform when
|
|
159
|
+
the identifier is converted to a standard UUID. By moving the
|
|
160
|
+
`variant` field out to the end of the identifier, everything between
|
|
161
|
+
the `version` and `variant` bookends can be generated randomly without
|
|
162
|
+
any further consideration, like so:
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
B64_ALPHA = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + %w(- _)
|
|
166
|
+
|
|
167
|
+
def make_cheapo_b64_uuid_ncname
|
|
168
|
+
vals = (1..20).map { rand 64 } # generate the content
|
|
169
|
+
vals.push(rand(4) + 8) # last digit is special
|
|
170
|
+
'E' + vals.map { |v| B64_ALPHA[v] }.join('') # 'E' for UUID v4
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# voilà:
|
|
174
|
+
|
|
175
|
+
cheap = make_cheapo_b64_uuid_ncname
|
|
176
|
+
# => "EXSVv8ezPbSKWoKOkBNWKL"
|
|
177
|
+
|
|
178
|
+
# now try changing it to a standard UUID:
|
|
179
|
+
|
|
180
|
+
UUID::NCName.from_ncname cheap, version: 1
|
|
181
|
+
# => "5d256ff1-eccf-46d2-b296-a0a3a404d58a"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Furthermore, since the default behaviour is to align the bits of the
|
|
185
|
+
last byte to the size of the encoding symbol, and since the `variant`
|
|
186
|
+
bits are masked, a compliant RFC4122 UUID will _always_ end with `I`,
|
|
187
|
+
`J`, `K`, or `L`, in _both_ Base32 (case-insensitive) and Base64
|
|
188
|
+
variants.
|
|
189
|
+
|
|
190
|
+
Since I have already released this gem prior to this format change, I
|
|
191
|
+
have added a `:version` parameter to both `to_ncname` and
|
|
192
|
+
`from_ncname`. This parameter, which controls the compact UUID spec
|
|
193
|
+
behaviour, defaults to `1`, as of the _module_ version 0.2.4.
|
|
194
|
+
|
|
195
|
+
> Unless you have to support identifiers generated from version 0.1.3
|
|
196
|
+
> or older, you should be running these methods with `version: 1`.
|
|
197
|
+
|
|
201
198
|
## Documentation
|
|
202
199
|
|
|
203
200
|
Generated and deposited
|
data/lib/uuid/ncname/version.rb
CHANGED
data/lib/uuid/ncname.rb
CHANGED
|
@@ -3,11 +3,20 @@ require "uuid/ncname/version"
|
|
|
3
3
|
|
|
4
4
|
require 'base64'
|
|
5
5
|
require 'base32'
|
|
6
|
+
require 'base58'
|
|
6
7
|
|
|
7
8
|
module UUID::NCName
|
|
8
9
|
|
|
9
10
|
private
|
|
10
11
|
|
|
12
|
+
MATCH = /^([A-Pa-p]) # zero-width boundary and version bookend
|
|
13
|
+
([2-7A-Za-z]{24}|[-0-9A-Z_a-z]{20}| # base32 and 64
|
|
14
|
+
(?:[1-9A-HJ-NP-Za-km-z]{15}_{6}|[1-9A-HJ-NP-Za-km-z]{16}_{5}|
|
|
15
|
+
[1-9A-HJ-NP-Za-km-z]{17}_{4}|[1-9A-HJ-NP-Za-km-z]{18}___|
|
|
16
|
+
[1-9A-HJ-NP-Za-km-z]{19}__|[1-9A-HJ-NP-Za-km-z]{20}_|
|
|
17
|
+
[1-9A-HJ-NP-Za-km-z]{21})) # base58 with underscore pad
|
|
18
|
+
([-0-9A-Z_a-z])$/x.freeze # lax variant bookend and zero-width boundary
|
|
19
|
+
|
|
11
20
|
ENCODE = {
|
|
12
21
|
32 => -> (bin, align = true) {
|
|
13
22
|
if align
|
|
@@ -18,7 +27,15 @@ module UUID::NCName
|
|
|
18
27
|
|
|
19
28
|
out = ::Base32.encode bin
|
|
20
29
|
|
|
21
|
-
out.downcase[0, 25]
|
|
30
|
+
out.downcase[0, 25] # clip off the padding
|
|
31
|
+
},
|
|
32
|
+
58 => -> (bin, _) {
|
|
33
|
+
variant = bin[-1].ord >> 4
|
|
34
|
+
# note the bitcoin alphabet is the one used in draft-msporny-base58
|
|
35
|
+
out = ::Base58.binary_to_base58(bin.chop, :bitcoin)
|
|
36
|
+
# we need to pad base58 with underscores because it is variable length
|
|
37
|
+
out + (?_ * (21 - out.length)) +
|
|
38
|
+
encode_version(variant) # encode_version does variant too
|
|
22
39
|
},
|
|
23
40
|
64 => -> (bin, align = true) {
|
|
24
41
|
if align
|
|
@@ -29,10 +46,11 @@ module UUID::NCName
|
|
|
29
46
|
|
|
30
47
|
out = ::Base64.urlsafe_encode64 bin
|
|
31
48
|
|
|
32
|
-
out[0, 21]
|
|
49
|
+
out[0, 21] # clip off the padding
|
|
33
50
|
},
|
|
34
51
|
}
|
|
35
52
|
|
|
53
|
+
# note the version symbol is already removed
|
|
36
54
|
DECODE = {
|
|
37
55
|
32 => -> (str, align = true) {
|
|
38
56
|
str = str.upcase[0, 25] + 'A======'
|
|
@@ -41,6 +59,14 @@ module UUID::NCName
|
|
|
41
59
|
|
|
42
60
|
out.pack 'C*'
|
|
43
61
|
},
|
|
62
|
+
58 => -> (str, _) {
|
|
63
|
+
variant = decode_version(str[-1]) << 4
|
|
64
|
+
# warn str
|
|
65
|
+
str = str.chop.tr ?_, ''
|
|
66
|
+
# warn str
|
|
67
|
+
# warn ::Base58.base58_to_binary(str, :bitcoin).length
|
|
68
|
+
::Base58.base58_to_binary(str, :bitcoin) + variant.chr.b
|
|
69
|
+
},
|
|
44
70
|
64 => -> (str, align = true) {
|
|
45
71
|
str = str[0, 21] + 'A=='
|
|
46
72
|
out = ::Base64.urlsafe_decode64(str).unpack 'C*'
|
|
@@ -54,6 +80,7 @@ module UUID::NCName
|
|
|
54
80
|
|
|
55
81
|
FORMAT = {
|
|
56
82
|
str: -> bin { UUF % bin.unpack('C*') },
|
|
83
|
+
urn: -> bin { "urn:uuid:#{UUF % bin.unpack('C*')}" },
|
|
57
84
|
hex: -> bin { bin.unpack 'H*' },
|
|
58
85
|
b64: -> bin { ::Base64.strict_encode64 bin },
|
|
59
86
|
bin: -> bin { bin },
|
|
@@ -102,7 +129,10 @@ module UUID::NCName
|
|
|
102
129
|
-> (version, data) {
|
|
103
130
|
version &= 0xf
|
|
104
131
|
|
|
132
|
+
# warn data.length
|
|
133
|
+
|
|
105
134
|
list = data.unpack 'N4'
|
|
135
|
+
# warn list.inspect
|
|
106
136
|
variant = (list[3] & 0xf0) << 24
|
|
107
137
|
list[3] >>= 8
|
|
108
138
|
list[3] |= ((list[2] & 0xff) << 24)
|
|
@@ -116,14 +146,25 @@ module UUID::NCName
|
|
|
116
146
|
],
|
|
117
147
|
]
|
|
118
148
|
|
|
119
|
-
def self.encode_version version
|
|
120
|
-
|
|
149
|
+
def self.encode_version version, radix = 64
|
|
150
|
+
offset = radix == 32 ? 97 : 65
|
|
151
|
+
((version & 15) + offset).chr
|
|
121
152
|
end
|
|
122
153
|
|
|
123
154
|
def self.decode_version version
|
|
124
155
|
(version.upcase.ord - 65) % 16
|
|
125
156
|
end
|
|
126
157
|
|
|
158
|
+
def self.assert_version version
|
|
159
|
+
version = 1 unless version
|
|
160
|
+
raise ArgumentError, "version #{version.inspect} is not an integer" unless
|
|
161
|
+
version.respond_to? :to_i
|
|
162
|
+
version = version.to_i
|
|
163
|
+
raise ArgumentError, "there is no version #{version}" unless
|
|
164
|
+
TRANSFORM[version]
|
|
165
|
+
version
|
|
166
|
+
end
|
|
167
|
+
|
|
127
168
|
def self.warn_version version
|
|
128
169
|
if version.nil?
|
|
129
170
|
warn 'Set an explicit :version to remove this warning. See documentation.'
|
|
@@ -137,6 +178,27 @@ module UUID::NCName
|
|
|
137
178
|
|
|
138
179
|
public
|
|
139
180
|
|
|
181
|
+
# This error gets thrown when a UUID-NCName token can't be
|
|
182
|
+
# positively determined to be one version or the other.
|
|
183
|
+
class AmbiguousToken < ArgumentError
|
|
184
|
+
|
|
185
|
+
# @return [String] The ambiguous token
|
|
186
|
+
attr_reader :token
|
|
187
|
+
# @return [String] The UUID when decoded using version 0
|
|
188
|
+
attr_reader :v0
|
|
189
|
+
# @return [String] The UUID when decoded using version 1
|
|
190
|
+
attr_reader :v1
|
|
191
|
+
|
|
192
|
+
# @param token [#to_s] The token in question
|
|
193
|
+
# @param v0 [#to_s] UUID decoded with decoding scheme version 0
|
|
194
|
+
# @param v1 [#to_s] UUID decoded with decoding scheme version 1
|
|
195
|
+
|
|
196
|
+
def initialize token, v0: nil, v1: nil
|
|
197
|
+
@v0 = v0 || from_ncname(token, version: 0)
|
|
198
|
+
@v1 = v1 || from_ncname(token, version: 1)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
140
202
|
# Converts a UUID (or object that when converted to a string looks
|
|
141
203
|
# like a UUID) to an NCName. By default it produces the Base64
|
|
142
204
|
# variant.
|
|
@@ -149,9 +211,7 @@ module UUID::NCName
|
|
|
149
211
|
#
|
|
150
212
|
# @param version [0, 1] An optional formatting version, where 0 is
|
|
151
213
|
# the naïve original version and 1 moves the `variant` nybble out
|
|
152
|
-
# to the end of the identifier.
|
|
153
|
-
# being if you do not set this parameter explicitly. The default
|
|
154
|
-
# version is 1.
|
|
214
|
+
# to the end of the identifier. The default version is 1.
|
|
155
215
|
#
|
|
156
216
|
# @param align [true, false] Optional directive to treat the
|
|
157
217
|
# terminating character as aligned to the numerical base of the
|
|
@@ -162,18 +222,21 @@ module UUID::NCName
|
|
|
162
222
|
# range of the letters A through P in (the RFC 3548/4648
|
|
163
223
|
# representations of) both Base32 and Base64. When `version` is 1
|
|
164
224
|
# and the terminating character is aligned, RFC4122-compliant UUIDs
|
|
165
|
-
# will always terminate with I
|
|
225
|
+
# will always terminate with `I`, `J`, `K`, or `L`. Defaults to
|
|
226
|
+
# `true`.
|
|
166
227
|
#
|
|
167
228
|
# @return [String] The NCName-formatted UUID.
|
|
168
|
-
|
|
229
|
+
#
|
|
169
230
|
def self.to_ncname uuid, radix: 64, version: nil, align: true
|
|
170
|
-
raise 'Radix must be either 32 or 64' unless
|
|
231
|
+
raise 'Radix must be either 32, 58, or 64' unless
|
|
232
|
+
[32, 58, 64].include? radix
|
|
171
233
|
raise 'UUID must be something stringable' if uuid.nil? or
|
|
172
234
|
not uuid.respond_to? :to_s
|
|
173
|
-
|
|
235
|
+
align = !!align # coerce to a boolean
|
|
174
236
|
|
|
175
237
|
# XXX remove this when appropriate
|
|
176
|
-
version = warn_version(version)
|
|
238
|
+
# version = warn_version(version)
|
|
239
|
+
version = assert_version version
|
|
177
240
|
|
|
178
241
|
uuid = uuid.to_s
|
|
179
242
|
bin = nil
|
|
@@ -195,9 +258,9 @@ module UUID::NCName
|
|
|
195
258
|
raise 'Binary representation of UUID is shorter than 16 bytes' if
|
|
196
259
|
bin.length < 16
|
|
197
260
|
|
|
198
|
-
uuidver, content = TRANSFORM[version]
|
|
261
|
+
uuidver, content = TRANSFORM[version].first.call bin[0, 16]
|
|
199
262
|
|
|
200
|
-
encode_version(uuidver) + ENCODE[radix].call(content, align)
|
|
263
|
+
encode_version(uuidver, radix) + ENCODE[radix].call(content, align)
|
|
201
264
|
end
|
|
202
265
|
|
|
203
266
|
# Converts an NCName-encoded UUID back to its canonical
|
|
@@ -207,9 +270,10 @@ module UUID::NCName
|
|
|
207
270
|
# @param ncname [#to_s] an NCName-encoded UUID, either a
|
|
208
271
|
# 22-character (Base64) variant, or a 26-character (Base32) variant.
|
|
209
272
|
#
|
|
210
|
-
# @param radix [nil, 32, 64] Optional radix; will use heuristic
|
|
273
|
+
# @param radix [nil, 32, 58, 64] Optional radix; will use a heuristic
|
|
274
|
+
# if omitted.
|
|
211
275
|
#
|
|
212
|
-
# @param format [:str, :hex, :b64, :bin] An optional formatting
|
|
276
|
+
# @param format [:str, :urn, :hex, :b64, :bin] An optional formatting
|
|
213
277
|
# parameter; defaults to `:str`, the canonical string representation.
|
|
214
278
|
#
|
|
215
279
|
# @param version [0, 1] See ::to_ncname. Defaults to 1.
|
|
@@ -218,12 +282,12 @@ module UUID::NCName
|
|
|
218
282
|
# Setting this parameter to `nil`, the default, will cause the
|
|
219
283
|
# decoder to detect the alignment state from the identifier.
|
|
220
284
|
#
|
|
221
|
-
# @param validate [false, true] Check that the ninth
|
|
222
|
-
# correctly masked _after_ decoding.
|
|
285
|
+
# @param validate [false, true] Check that the ninth (the variant)
|
|
286
|
+
# octet is correctly masked _after_ decoding.
|
|
223
287
|
#
|
|
224
288
|
# @return [String, nil] The corresponding UUID or nil if the input
|
|
225
289
|
# is malformed.
|
|
226
|
-
|
|
290
|
+
#
|
|
227
291
|
def self.from_ncname ncname,
|
|
228
292
|
radix: nil, format: :str, version: nil, align: nil, validate: false
|
|
229
293
|
raise 'Format must be symbol-able' unless format.respond_to? :to_sym
|
|
@@ -232,34 +296,31 @@ module UUID::NCName
|
|
|
232
296
|
[true, false, nil].include? align
|
|
233
297
|
|
|
234
298
|
# XXX remove this when appropriate
|
|
235
|
-
version = warn_version version
|
|
299
|
+
# version = warn_version version
|
|
300
|
+
version = assert_version version
|
|
236
301
|
|
|
237
302
|
return unless ncname and ncname.respond_to? :to_s
|
|
238
303
|
|
|
239
304
|
ncname = ncname.to_s.strip.gsub(/\s+/, '')
|
|
240
|
-
match =
|
|
305
|
+
match = MATCH.match(ncname) or return
|
|
306
|
+
return if align and !/[A-Pa-p]$/.match? ncname # MATCH is lax
|
|
241
307
|
|
|
308
|
+
# determine the radix from the input
|
|
242
309
|
if radix
|
|
243
|
-
raise "Radix must be 32 or 64, not #{radix}" unless
|
|
244
|
-
|
|
310
|
+
raise ArgumentError, "Radix must be 32, 58, or 64, not #{radix}" unless
|
|
311
|
+
[32, 58, 64].any? radix
|
|
312
|
+
return unless { 32 => 26, 58 => 23, 64 => 22 }[radix] == ncname.length
|
|
245
313
|
else
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
radix = 64
|
|
250
|
-
elsif len >= 26
|
|
251
|
-
radix = 32
|
|
252
|
-
elsif len >= 22
|
|
253
|
-
radix = 64
|
|
254
|
-
else
|
|
255
|
-
# uh will this ever get executed now that i put in that return?
|
|
256
|
-
raise "Not sure what to do with an identifier of length #{len}."
|
|
257
|
-
end
|
|
314
|
+
radix = { 26 => 32, 23 => 58, 22 => 64}[ncname.length] or
|
|
315
|
+
raise ArgumentError,
|
|
316
|
+
"Not sure what to do with an identifier of length #{ncname.length}."
|
|
258
317
|
end
|
|
259
318
|
|
|
260
|
-
|
|
319
|
+
# note MATCH separates the variant
|
|
320
|
+
uuidver, *content = match.captures
|
|
321
|
+
content = content.join
|
|
261
322
|
|
|
262
|
-
align = !!(
|
|
323
|
+
align = !!(/[A-Pa-p]$/.match? content) if align.nil?
|
|
263
324
|
uuidver = decode_version uuidver
|
|
264
325
|
content = DECODE[radix].call content, align
|
|
265
326
|
|
|
@@ -280,7 +341,7 @@ module UUID::NCName
|
|
|
280
341
|
# @param align [true, false] See ::to_ncname.
|
|
281
342
|
#
|
|
282
343
|
# @return [String] The Base64-encoded NCName
|
|
283
|
-
|
|
344
|
+
#
|
|
284
345
|
def self.to_ncname_64 uuid, version: nil, align: true
|
|
285
346
|
to_ncname uuid, version: version, align: align
|
|
286
347
|
end
|
|
@@ -297,9 +358,42 @@ module UUID::NCName
|
|
|
297
358
|
#
|
|
298
359
|
# @return [String, nil] The corresponding UUID or nil if the input
|
|
299
360
|
# is malformed.
|
|
300
|
-
|
|
361
|
+
#
|
|
301
362
|
def self.from_ncname_64 ncname, format: :str, version: nil, align: nil
|
|
302
|
-
from_ncname ncname,
|
|
363
|
+
from_ncname ncname,
|
|
364
|
+
radix: 64, format: format, version: version, align: align
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Shorthand for conversion to the Base58 version
|
|
368
|
+
#
|
|
369
|
+
# @param uuid [#to_s] The UUID
|
|
370
|
+
#
|
|
371
|
+
# @param version [0, 1] See ::to_ncname.
|
|
372
|
+
#
|
|
373
|
+
# @param align [true, false] See ::to_ncname.
|
|
374
|
+
#
|
|
375
|
+
# @return [String] The Base58-encoded NCName
|
|
376
|
+
#
|
|
377
|
+
def self.to_ncname_58 uuid, version: nil, align: true
|
|
378
|
+
to_ncname uuid, radix: 58, version: version, align: align
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Shorthand for conversion from the Base58 version
|
|
382
|
+
#
|
|
383
|
+
# @param ncname [#to_s] The Base58 variant of the NCName-encoded UUID
|
|
384
|
+
#
|
|
385
|
+
# @param format [:str, :hex, :b64, :bin] The format
|
|
386
|
+
#
|
|
387
|
+
# @param version [0, 1] See ::to_ncname.
|
|
388
|
+
#
|
|
389
|
+
# @param align [true, false] See ::to_ncname.
|
|
390
|
+
#
|
|
391
|
+
# @return [String, nil] The corresponding UUID or nil if the input
|
|
392
|
+
# is malformed.
|
|
393
|
+
#
|
|
394
|
+
def self.from_ncname_58 ncname, format: :str, version: nil, align: nil
|
|
395
|
+
from_ncname ncname,
|
|
396
|
+
radix: 58, format: format, version: version, align: align
|
|
303
397
|
end
|
|
304
398
|
|
|
305
399
|
# Shorthand for conversion to the Base32 version
|
|
@@ -311,7 +405,7 @@ module UUID::NCName
|
|
|
311
405
|
# @param align [true, false] See ::to_ncname.
|
|
312
406
|
#
|
|
313
407
|
# @return [String] The Base32-encoded NCName
|
|
314
|
-
|
|
408
|
+
#
|
|
315
409
|
def self.to_ncname_32 uuid, version: nil, align: true
|
|
316
410
|
to_ncname uuid, radix: 32, version: version, align: align
|
|
317
411
|
end
|
|
@@ -328,9 +422,10 @@ module UUID::NCName
|
|
|
328
422
|
#
|
|
329
423
|
# @return [String, nil] The corresponding UUID or nil if the input
|
|
330
424
|
# is malformed.
|
|
331
|
-
|
|
425
|
+
#
|
|
332
426
|
def self.from_ncname_32 ncname, format: :str, version: nil, align: nil
|
|
333
|
-
from_ncname ncname,
|
|
427
|
+
from_ncname ncname,
|
|
428
|
+
radix: 32, format: format, version: version, align: align
|
|
334
429
|
end
|
|
335
430
|
|
|
336
431
|
# Test if the given token is a UUID NCName, with a hint to its
|
|
@@ -340,30 +435,37 @@ module UUID::NCName
|
|
|
340
435
|
# `false` if the token is invalid, otherwise it returns `0` or `1`
|
|
341
436
|
# for the guessed version.
|
|
342
437
|
#
|
|
343
|
-
# @note Version 1 tokens always end with I
|
|
344
|
-
# being case-insensitive), so tokens that end in something
|
|
345
|
-
# be version 0.
|
|
438
|
+
# @note Version 1 tokens always end with `I`, `J`, `K`, or `L` (with
|
|
439
|
+
# base32 being case-insensitive), so tokens that end in something
|
|
440
|
+
# else will always be version 0.
|
|
346
441
|
#
|
|
347
442
|
# @param token [#to_s] The token to test
|
|
348
443
|
#
|
|
444
|
+
# @param strict [false, true]
|
|
445
|
+
#
|
|
349
446
|
# @return [false, 0, 1]
|
|
350
|
-
|
|
447
|
+
#
|
|
448
|
+
def self.valid? token, strict: false
|
|
351
449
|
token = token.to_s
|
|
352
|
-
if
|
|
450
|
+
if MATCH.match? token
|
|
353
451
|
# false is definitely version zero but true is only maybe version 1
|
|
354
452
|
version = /^(?:.{21}[I-L]|.{25}[I-Li-l])$/.match(token) ? 1 : 0
|
|
355
453
|
|
|
356
454
|
# try decoding with validation on
|
|
357
455
|
uu = from_ncname token, version: version, validate: true
|
|
358
456
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
version
|
|
457
|
+
# note that version 1 will always return something because the
|
|
458
|
+
# method of detecting it is a version 1 also happens to be the
|
|
459
|
+
# method of determining whether or not it is valid.
|
|
460
|
+
return false unless uu
|
|
461
|
+
|
|
462
|
+
if version == 1 and strict
|
|
463
|
+
# but we can also check if the input is a valid version 0
|
|
464
|
+
u0 = from_ncname token, version: 0, validate: true
|
|
465
|
+
raise AmbiguousToken.new(token, v0: u0, v1: uu) if u0
|
|
366
466
|
end
|
|
467
|
+
|
|
468
|
+
version
|
|
367
469
|
else
|
|
368
470
|
false
|
|
369
471
|
end
|
data/uuid-ncname.gemspec
CHANGED
|
@@ -27,15 +27,16 @@ DESC
|
|
|
27
27
|
spec.require_paths = ["lib"]
|
|
28
28
|
|
|
29
29
|
# we use named parameters
|
|
30
|
-
spec.required_ruby_version = '
|
|
30
|
+
spec.required_ruby_version = '>= 2.0'
|
|
31
31
|
|
|
32
32
|
# surprisingly do not need this
|
|
33
33
|
# spec.add_runtime_dependency 'uuidtools', '~> 2.1.5'
|
|
34
34
|
spec.add_runtime_dependency 'base32', '~> 0.3.2'
|
|
35
|
+
spec.add_runtime_dependency 'base58', '~> 0.2.3'
|
|
35
36
|
|
|
36
|
-
spec.add_development_dependency 'bundler', '~>
|
|
37
|
-
spec.add_development_dependency 'rake', '~>
|
|
38
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
|
37
|
+
spec.add_development_dependency 'bundler', '~> 2.2'
|
|
38
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.10'
|
|
39
40
|
|
|
40
41
|
# only need it for testing, who knew
|
|
41
42
|
# 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.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dorian Taylor
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-11-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base32
|
|
@@ -24,48 +24,62 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 0.3.2
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: base58
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.2.3
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.2.3
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: bundler
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
30
44
|
requirements:
|
|
31
45
|
- - "~>"
|
|
32
46
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
47
|
+
version: '2.2'
|
|
34
48
|
type: :development
|
|
35
49
|
prerelease: false
|
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
51
|
requirements:
|
|
38
52
|
- - "~>"
|
|
39
53
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
54
|
+
version: '2.2'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: rake
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
45
59
|
- - "~>"
|
|
46
60
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
61
|
+
version: '13.0'
|
|
48
62
|
type: :development
|
|
49
63
|
prerelease: false
|
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
65
|
requirements:
|
|
52
66
|
- - "~>"
|
|
53
67
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
68
|
+
version: '13.0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rspec
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
73
|
- - "~>"
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '3.
|
|
75
|
+
version: '3.10'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
80
|
- - "~>"
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '3.
|
|
82
|
+
version: '3.10'
|
|
69
83
|
description: |
|
|
70
84
|
This module creates an isomorphic representation of a UUID which is
|
|
71
85
|
guaranteed to fit into the grammar of the XML NCName construct, which
|
|
@@ -81,6 +95,7 @@ files:
|
|
|
81
95
|
- ".gitignore"
|
|
82
96
|
- ".rspec"
|
|
83
97
|
- ".travis.yml"
|
|
98
|
+
- ".yardopts"
|
|
84
99
|
- Gemfile
|
|
85
100
|
- LICENSE
|
|
86
101
|
- README.md
|
|
@@ -95,13 +110,13 @@ homepage: https://github.com/doriantaylor/rb-uuid-ncname
|
|
|
95
110
|
licenses:
|
|
96
111
|
- Apache-2.0
|
|
97
112
|
metadata: {}
|
|
98
|
-
post_install_message:
|
|
113
|
+
post_install_message:
|
|
99
114
|
rdoc_options: []
|
|
100
115
|
require_paths:
|
|
101
116
|
- lib
|
|
102
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
118
|
requirements:
|
|
104
|
-
- - "
|
|
119
|
+
- - ">="
|
|
105
120
|
- !ruby/object:Gem::Version
|
|
106
121
|
version: '2.0'
|
|
107
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
@@ -110,8 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
110
125
|
- !ruby/object:Gem::Version
|
|
111
126
|
version: '0'
|
|
112
127
|
requirements: []
|
|
113
|
-
rubygems_version: 3.
|
|
114
|
-
signing_key:
|
|
128
|
+
rubygems_version: 3.2.22
|
|
129
|
+
signing_key:
|
|
115
130
|
specification_version: 4
|
|
116
131
|
summary: Format a UUID as a valid NCName.
|
|
117
132
|
test_files: []
|