uuidtools 2.1.0 → 3.0.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 +7 -0
- data/CHANGELOG +23 -0
- data/LICENSE.txt +202 -0
- data/README.md +37 -0
- data/Rakefile +10 -23
- data/lib/uuidtools/version.rb +16 -21
- data/lib/uuidtools.rb +397 -177
- data/spec/spec_helper.rb +2 -0
- data/spec/uuidtools/mac_address_spec.rb +456 -3
- data/spec/uuidtools/utility_spec.rb +5 -5
- data/spec/uuidtools/uuid_creation_spec.rb +51 -41
- data/spec/uuidtools/uuid_parsing_spec.rb +81 -43
- data/tasks/benchmark.rake +46 -27
- data/tasks/gem.rake +31 -18
- data/tasks/rspec.rake +55 -0
- data/tasks/yard.rake +22 -0
- data/uuidtools.gemspec +28 -0
- metadata +84 -71
- data/LICENSE +0 -20
- data/README +0 -13
- data/tasks/clobber.rake +0 -2
- data/tasks/rdoc.rake +0 -29
- data/tasks/rubyforge.rake +0 -89
- data/tasks/spec.rake +0 -64
data/lib/uuidtools.rb
CHANGED
|
@@ -1,26 +1,21 @@
|
|
|
1
|
+
# encoding:utf-8
|
|
1
2
|
#--
|
|
2
|
-
#
|
|
3
|
+
# Copyright (C) 2005-2014 Bob Aman
|
|
3
4
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
-
# the following conditions:
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
11
8
|
#
|
|
12
|
-
#
|
|
13
|
-
# included in all copies or substantial portions of the Software.
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
10
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
22
16
|
#++
|
|
23
17
|
|
|
18
|
+
|
|
24
19
|
$:.unshift(File.dirname(__FILE__))
|
|
25
20
|
|
|
26
21
|
require 'uri'
|
|
@@ -38,30 +33,50 @@ rescue LoadError
|
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
module UUIDTools
|
|
41
|
-
|
|
42
|
-
#
|
|
36
|
+
##
|
|
43
37
|
# UUIDTools was designed to be a simple library for generating any
|
|
44
38
|
# of the various types of UUIDs. It conforms to RFC 4122 whenever
|
|
45
39
|
# possible.
|
|
46
40
|
#
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
41
|
+
# @example
|
|
42
|
+
# UUID.md5_create(UUID_DNS_NAMESPACE, "www.widgets.com")
|
|
43
|
+
# # => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29>
|
|
44
|
+
# UUID.sha1_create(UUID_DNS_NAMESPACE, "www.widgets.com")
|
|
45
|
+
# # => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
|
|
46
|
+
# UUID.timestamp_create
|
|
47
|
+
# # => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>
|
|
48
|
+
# UUID.random_create
|
|
49
|
+
# # => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
|
|
56
50
|
class UUID
|
|
57
51
|
include Comparable
|
|
58
52
|
|
|
53
|
+
##
|
|
54
|
+
# @api private
|
|
59
55
|
@@last_timestamp = nil
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# @api private
|
|
60
59
|
@@last_node_id = nil
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# @api private
|
|
61
63
|
@@last_clock_sequence = nil
|
|
64
|
+
|
|
65
|
+
##
|
|
66
|
+
# @api private
|
|
62
67
|
@@state_file = nil
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# @api private
|
|
63
71
|
@@mutex = Mutex.new
|
|
64
72
|
|
|
73
|
+
##
|
|
74
|
+
# Creates a new UUID structure from its component values.
|
|
75
|
+
# @see UUID.md5_create
|
|
76
|
+
# @see UUID.sha1_create
|
|
77
|
+
# @see UUID.timestamp_create
|
|
78
|
+
# @see UUID.random_create
|
|
79
|
+
# @api private
|
|
65
80
|
def initialize(time_low, time_mid, time_hi_and_version,
|
|
66
81
|
clock_seq_hi_and_reserved, clock_seq_low, nodes)
|
|
67
82
|
unless time_low >= 0 && time_low < 4294967296
|
|
@@ -110,22 +125,38 @@ module UUIDTools
|
|
|
110
125
|
@nodes = nodes
|
|
111
126
|
end
|
|
112
127
|
|
|
128
|
+
##
|
|
129
|
+
# Returns the value of attribute `time_low`
|
|
113
130
|
attr_accessor :time_low
|
|
131
|
+
|
|
132
|
+
##
|
|
133
|
+
# Returns the value of attribute `time_mid`
|
|
114
134
|
attr_accessor :time_mid
|
|
135
|
+
|
|
136
|
+
##
|
|
137
|
+
# Returns the value of attribute `time_hi_and_version`
|
|
115
138
|
attr_accessor :time_hi_and_version
|
|
139
|
+
|
|
140
|
+
##
|
|
141
|
+
# Returns the value of attribute `clock_seq_hi_and_reserved`
|
|
116
142
|
attr_accessor :clock_seq_hi_and_reserved
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# Returns the value of attribute `clock_seq_low`
|
|
117
146
|
attr_accessor :clock_seq_low
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
# Returns the value of attribute `nodes`
|
|
118
150
|
attr_accessor :nodes
|
|
119
151
|
|
|
152
|
+
##
|
|
120
153
|
# Parses a UUID from a string.
|
|
121
154
|
def self.parse(uuid_string)
|
|
122
155
|
unless uuid_string.kind_of? String
|
|
123
156
|
raise TypeError,
|
|
124
157
|
"Expected String, got #{uuid_string.class.name} instead."
|
|
125
158
|
end
|
|
126
|
-
uuid_components = uuid_string.downcase.scan(
|
|
127
|
-
Regexp.new("^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-" +
|
|
128
|
-
"([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})$")).first
|
|
159
|
+
uuid_components = uuid_string.downcase.scan(UUIDTools::UUID_REGEXP).first
|
|
129
160
|
raise ArgumentError, "Invalid UUID format." if uuid_components.nil?
|
|
130
161
|
time_low = uuid_components[0].to_i(16)
|
|
131
162
|
time_mid = uuid_components[1].to_i(16)
|
|
@@ -133,52 +164,114 @@ module UUIDTools
|
|
|
133
164
|
clock_seq_hi_and_reserved = uuid_components[3].to_i(16)
|
|
134
165
|
clock_seq_low = uuid_components[4].to_i(16)
|
|
135
166
|
nodes = []
|
|
136
|
-
|
|
167
|
+
6.times do |i|
|
|
137
168
|
nodes << uuid_components[5][(i * 2)..(i * 2) + 1].to_i(16)
|
|
138
169
|
end
|
|
139
170
|
return self.new(time_low, time_mid, time_hi_and_version,
|
|
140
171
|
clock_seq_hi_and_reserved, clock_seq_low, nodes)
|
|
141
172
|
end
|
|
142
173
|
|
|
174
|
+
##
|
|
143
175
|
# Parses a UUID from a raw byte string.
|
|
144
176
|
def self.parse_raw(raw_string)
|
|
145
177
|
unless raw_string.kind_of? String
|
|
146
178
|
raise TypeError,
|
|
147
179
|
"Expected String, got #{raw_string.class.name} instead."
|
|
148
180
|
end
|
|
149
|
-
integer = self.convert_byte_string_to_int(raw_string)
|
|
150
181
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
if raw_string.respond_to?(:force_encoding)
|
|
183
|
+
raw_string.force_encoding(Encoding::ASCII_8BIT)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
raw_length = raw_string.length
|
|
187
|
+
if raw_length < 16
|
|
188
|
+
# Option A: Enforce raw_string be 16 characters (More strict)
|
|
189
|
+
#raise ArgumentError,
|
|
190
|
+
# "Expected 16 bytes, got #{raw_string.length} instead."
|
|
191
|
+
|
|
192
|
+
# Option B: Pad raw_string to 16 characters (Compatible with existing behavior)
|
|
193
|
+
raw_string = raw_string.rjust(16, "\0")
|
|
194
|
+
elsif raw_length > 16
|
|
195
|
+
# NOTE: As per "Option B" above, existing behavior would use the lower
|
|
196
|
+
# 128-bits of an overly long raw_string instead of using the upper 128-bits.
|
|
197
|
+
start_index = raw_length - 16
|
|
198
|
+
raw_string = raw_string[start_index...raw_length]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
raw_bytes = []
|
|
202
|
+
if raw_string[0].respond_to? :ord
|
|
203
|
+
for i in 0...raw_string.size
|
|
204
|
+
raw_bytes << raw_string[i].ord
|
|
205
|
+
end
|
|
206
|
+
else
|
|
207
|
+
raw_bytes = raw_string
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
time_low = ((raw_bytes[0] << 24) +
|
|
211
|
+
(raw_bytes[1] << 16) +
|
|
212
|
+
(raw_bytes[2] << 8) +
|
|
213
|
+
raw_bytes[3])
|
|
214
|
+
time_mid = ((raw_bytes[4] << 8) +
|
|
215
|
+
raw_bytes[5])
|
|
216
|
+
time_hi_and_version = ((raw_bytes[6] << 8) +
|
|
217
|
+
raw_bytes[7])
|
|
218
|
+
clock_seq_hi_and_reserved = raw_bytes[8]
|
|
219
|
+
clock_seq_low = raw_bytes[9]
|
|
156
220
|
nodes = []
|
|
157
|
-
for i in
|
|
158
|
-
nodes <<
|
|
221
|
+
for i in 10...16
|
|
222
|
+
nodes << raw_bytes[i]
|
|
159
223
|
end
|
|
224
|
+
|
|
160
225
|
return self.new(time_low, time_mid, time_hi_and_version,
|
|
161
|
-
|
|
226
|
+
clock_seq_hi_and_reserved, clock_seq_low, nodes)
|
|
162
227
|
end
|
|
163
228
|
|
|
229
|
+
##
|
|
164
230
|
# Parses a UUID from an Integer.
|
|
165
231
|
def self.parse_int(uuid_int)
|
|
166
232
|
unless uuid_int.kind_of?(Integer)
|
|
167
233
|
raise ArgumentError,
|
|
168
234
|
"Expected Integer, got #{uuid_int.class.name} instead."
|
|
169
235
|
end
|
|
170
|
-
|
|
236
|
+
|
|
237
|
+
time_low = (uuid_int >> 96) & 0xFFFFFFFF
|
|
238
|
+
time_mid = (uuid_int >> 80) & 0xFFFF
|
|
239
|
+
time_hi_and_version = (uuid_int >> 64) & 0xFFFF
|
|
240
|
+
clock_seq_hi_and_reserved = (uuid_int >> 56) & 0xFF
|
|
241
|
+
clock_seq_low = (uuid_int >> 48) & 0xFF
|
|
242
|
+
nodes = []
|
|
243
|
+
for i in 0..5
|
|
244
|
+
nodes << ((uuid_int >> (40 - (i * 8))) & 0xFF)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
return self.new(time_low, time_mid, time_hi_and_version,
|
|
248
|
+
clock_seq_hi_and_reserved, clock_seq_low, nodes)
|
|
171
249
|
end
|
|
172
250
|
|
|
251
|
+
##
|
|
173
252
|
# Parse a UUID from a hexdigest String.
|
|
174
|
-
def self.parse_hexdigest(
|
|
175
|
-
unless
|
|
253
|
+
def self.parse_hexdigest(uuid_hex)
|
|
254
|
+
unless uuid_hex.kind_of?(String)
|
|
176
255
|
raise ArgumentError,
|
|
177
|
-
"Expected String, got #{
|
|
256
|
+
"Expected String, got #{uuid_hex.class.name} instead."
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
time_low = uuid_hex[0...8].to_i(16)
|
|
260
|
+
time_mid = uuid_hex[8...12].to_i(16)
|
|
261
|
+
time_hi_and_version = uuid_hex[12...16].to_i(16)
|
|
262
|
+
clock_seq_hi_and_reserved = uuid_hex[16...18].to_i(16)
|
|
263
|
+
clock_seq_low = uuid_hex[18...20].to_i(16)
|
|
264
|
+
nodes_string = uuid_hex[20...32]
|
|
265
|
+
nodes = []
|
|
266
|
+
for i in 0..5
|
|
267
|
+
nodes << nodes_string[(i * 2)..(i * 2) + 1].to_i(16)
|
|
178
268
|
end
|
|
179
|
-
|
|
269
|
+
|
|
270
|
+
return self.new(time_low, time_mid, time_hi_and_version,
|
|
271
|
+
clock_seq_hi_and_reserved, clock_seq_low, nodes)
|
|
180
272
|
end
|
|
181
273
|
|
|
274
|
+
##
|
|
182
275
|
# Creates a UUID from a random value.
|
|
183
276
|
def self.random_create()
|
|
184
277
|
new_uuid = self.parse_raw(SecureRandom.random_bytes(16))
|
|
@@ -189,6 +282,7 @@ module UUIDTools
|
|
|
189
282
|
return new_uuid
|
|
190
283
|
end
|
|
191
284
|
|
|
285
|
+
##
|
|
192
286
|
# Creates a UUID from a timestamp.
|
|
193
287
|
def self.timestamp_create(timestamp=nil)
|
|
194
288
|
# We need a lock here to prevent two threads from ever
|
|
@@ -213,7 +307,7 @@ module UUIDTools
|
|
|
213
307
|
nodes = SecureRandom.random_bytes(6).unpack("C*")
|
|
214
308
|
nodes[0] |= 0b00000001
|
|
215
309
|
end
|
|
216
|
-
|
|
310
|
+
6.times do |i|
|
|
217
311
|
node_id += (nodes[i] << (40 - (i * 8)))
|
|
218
312
|
end
|
|
219
313
|
clock_sequence = @@last_clock_sequence
|
|
@@ -248,16 +342,19 @@ module UUIDTools
|
|
|
248
342
|
end
|
|
249
343
|
end
|
|
250
344
|
|
|
345
|
+
##
|
|
251
346
|
# Creates a UUID using the MD5 hash. (Version 3)
|
|
252
347
|
def self.md5_create(namespace, name)
|
|
253
348
|
return self.create_from_hash(Digest::MD5, namespace, name)
|
|
254
349
|
end
|
|
255
350
|
|
|
351
|
+
##
|
|
256
352
|
# Creates a UUID using the SHA1 hash. (Version 5)
|
|
257
353
|
def self.sha1_create(namespace, name)
|
|
258
354
|
return self.create_from_hash(Digest::SHA1, namespace, name)
|
|
259
355
|
end
|
|
260
356
|
|
|
357
|
+
##
|
|
261
358
|
# This method applies only to version 1 UUIDs.
|
|
262
359
|
# Checks if the node ID was generated from a random number
|
|
263
360
|
# or from an IEEE 802 address (MAC address).
|
|
@@ -269,6 +366,7 @@ module UUIDTools
|
|
|
269
366
|
return ((self.nodes.first & 0x01) == 1)
|
|
270
367
|
end
|
|
271
368
|
|
|
369
|
+
##
|
|
272
370
|
# Returns true if this UUID is the
|
|
273
371
|
# nil UUID (00000000-0000-0000-0000-000000000000).
|
|
274
372
|
def nil_uuid?
|
|
@@ -283,6 +381,7 @@ module UUIDTools
|
|
|
283
381
|
return true
|
|
284
382
|
end
|
|
285
383
|
|
|
384
|
+
##
|
|
286
385
|
# Returns the UUID version type.
|
|
287
386
|
# Possible values:
|
|
288
387
|
# 1 - Time-based with unique or random host identifier
|
|
@@ -294,6 +393,7 @@ module UUIDTools
|
|
|
294
393
|
return (time_hi_and_version >> 12)
|
|
295
394
|
end
|
|
296
395
|
|
|
396
|
+
##
|
|
297
397
|
# Returns the UUID variant.
|
|
298
398
|
# Possible values:
|
|
299
399
|
# 0b000 - Reserved, NCS backward compatibility.
|
|
@@ -313,16 +413,13 @@ module UUIDTools
|
|
|
313
413
|
return (result >> 6)
|
|
314
414
|
end
|
|
315
415
|
|
|
416
|
+
##
|
|
316
417
|
# Returns true if this UUID is valid.
|
|
317
418
|
def valid?
|
|
318
|
-
|
|
319
|
-
(1..5).include?(self.version)
|
|
320
|
-
return true
|
|
321
|
-
else
|
|
322
|
-
return false
|
|
323
|
-
end
|
|
419
|
+
return self.variant == 0b100 && (1..8).cover?(self.version)
|
|
324
420
|
end
|
|
325
421
|
|
|
422
|
+
##
|
|
326
423
|
# Returns the IEEE 802 address used to generate this UUID or
|
|
327
424
|
# nil if a MAC address was not used.
|
|
328
425
|
def mac_address
|
|
@@ -333,6 +430,7 @@ module UUIDTools
|
|
|
333
430
|
end).join(":")
|
|
334
431
|
end
|
|
335
432
|
|
|
433
|
+
##
|
|
336
434
|
# Returns the timestamp used to generate this UUID
|
|
337
435
|
def timestamp
|
|
338
436
|
return nil if self.version != 1
|
|
@@ -345,8 +443,10 @@ module UUIDTools
|
|
|
345
443
|
(gmt_timestamp_100_nanoseconds - 0x01B21DD213814000) / 10000000.0)
|
|
346
444
|
end
|
|
347
445
|
|
|
446
|
+
##
|
|
348
447
|
# Compares two UUIDs lexically
|
|
349
448
|
def <=>(other_uuid)
|
|
449
|
+
return nil unless other_uuid.is_a?(UUIDTools::UUID)
|
|
350
450
|
check = self.time_low <=> other_uuid.time_low
|
|
351
451
|
return check if check != 0
|
|
352
452
|
check = self.time_mid <=> other_uuid.time_mid
|
|
@@ -358,7 +458,7 @@ module UUIDTools
|
|
|
358
458
|
return check if check != 0
|
|
359
459
|
check = self.clock_seq_low <=> other_uuid.clock_seq_low
|
|
360
460
|
return check if check != 0
|
|
361
|
-
|
|
461
|
+
6.times do |i|
|
|
362
462
|
if (self.nodes[i] < other_uuid.nodes[i])
|
|
363
463
|
return -1
|
|
364
464
|
end
|
|
@@ -369,169 +469,252 @@ module UUIDTools
|
|
|
369
469
|
return 0
|
|
370
470
|
end
|
|
371
471
|
|
|
472
|
+
##
|
|
372
473
|
# Returns a representation of the object's state
|
|
373
474
|
def inspect
|
|
374
475
|
return "#<UUID:0x#{self.object_id.to_s(16)} UUID:#{self.to_s}>"
|
|
375
476
|
end
|
|
376
477
|
|
|
478
|
+
##
|
|
377
479
|
# Returns the hex digest of the UUID object.
|
|
378
480
|
def hexdigest
|
|
379
|
-
|
|
481
|
+
(self.frozen? ?
|
|
482
|
+
generate_hexdigest : (@hexdigest ||= generate_hexdigest)
|
|
483
|
+
).dup
|
|
380
484
|
end
|
|
381
485
|
|
|
486
|
+
##
|
|
382
487
|
# Returns the raw bytes that represent this UUID.
|
|
383
488
|
def raw
|
|
384
|
-
|
|
489
|
+
(self.frozen? ? generate_raw : (@raw ||= generate_raw)).dup
|
|
385
490
|
end
|
|
386
491
|
|
|
492
|
+
##
|
|
387
493
|
# Returns a string representation for this UUID.
|
|
388
494
|
def to_s
|
|
389
|
-
|
|
390
|
-
@time_hi_and_version, @clock_seq_hi_and_reserved, @clock_seq_low);
|
|
391
|
-
for i in 0..5
|
|
392
|
-
result << sprintf("%2.2x", @nodes[i])
|
|
393
|
-
end
|
|
394
|
-
return result.downcase
|
|
495
|
+
(self.frozen? ? generate_s : (@string ||= generate_s)).dup
|
|
395
496
|
end
|
|
396
497
|
alias_method :to_str, :to_s
|
|
397
498
|
|
|
499
|
+
##
|
|
398
500
|
# Returns an integer representation for this UUID.
|
|
399
501
|
def to_i
|
|
400
|
-
@integer ||=
|
|
502
|
+
self.frozen? ? generate_i : (@integer ||= generate_i)
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
##
|
|
506
|
+
# Returns a URI string for this UUID.
|
|
507
|
+
def to_uri
|
|
508
|
+
return "urn:uuid:#{self.to_s}"
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
##
|
|
512
|
+
# Returns an integer hash value.
|
|
513
|
+
def hash
|
|
514
|
+
self.frozen? ? generate_hash : (@hash ||= generate_hash)
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
protected
|
|
518
|
+
##
|
|
519
|
+
# Generates the hex digest of the UUID object.
|
|
520
|
+
#
|
|
521
|
+
# @api private
|
|
522
|
+
def generate_hexdigest
|
|
523
|
+
return self.to_i.to_s(16).rjust(32, "0")
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
# Generates an integer hash value.
|
|
527
|
+
#
|
|
528
|
+
# @api private
|
|
529
|
+
def generate_hash
|
|
530
|
+
return self.to_i % 0x3fffffff
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
##
|
|
534
|
+
# Generates an integer representation for this UUID.
|
|
535
|
+
#
|
|
536
|
+
# @api private
|
|
537
|
+
def generate_i
|
|
538
|
+
return (begin
|
|
401
539
|
bytes = (time_low << 96) + (time_mid << 80) +
|
|
402
540
|
(time_hi_and_version << 64) + (clock_seq_hi_and_reserved << 56) +
|
|
403
541
|
(clock_seq_low << 48)
|
|
404
|
-
|
|
542
|
+
6.times do |i|
|
|
405
543
|
bytes += (nodes[i] << (40 - (i * 8)))
|
|
406
544
|
end
|
|
407
545
|
bytes
|
|
408
546
|
end)
|
|
409
547
|
end
|
|
410
548
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
549
|
+
##
|
|
550
|
+
# Generates a string representation for this UUID.
|
|
551
|
+
#
|
|
552
|
+
# @api private
|
|
553
|
+
def generate_s
|
|
554
|
+
result = sprintf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", @time_low, @time_mid,
|
|
555
|
+
@time_hi_and_version, @clock_seq_hi_and_reserved, @clock_seq_low);
|
|
556
|
+
6.times do |i|
|
|
557
|
+
result << sprintf("%2.2x", @nodes[i])
|
|
558
|
+
end
|
|
559
|
+
return result.downcase
|
|
414
560
|
end
|
|
415
561
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
562
|
+
##
|
|
563
|
+
# Generates the raw bytes that represent this UUID.
|
|
564
|
+
#
|
|
565
|
+
# @api private
|
|
566
|
+
def generate_raw
|
|
567
|
+
return self.class.convert_int_to_byte_string(self.to_i, 16)
|
|
419
568
|
end
|
|
420
569
|
|
|
570
|
+
public
|
|
571
|
+
##
|
|
421
572
|
# Returns true if this UUID is exactly equal to the other UUID.
|
|
422
573
|
def eql?(other)
|
|
423
574
|
return self == other
|
|
424
575
|
end
|
|
425
576
|
|
|
577
|
+
#
|
|
578
|
+
# Determine what OS we're running on. Helps decide how to find the MAC
|
|
579
|
+
#
|
|
580
|
+
def self.os_class
|
|
581
|
+
require 'rbconfig'
|
|
582
|
+
os_platform = RbConfig::CONFIG['target_os']
|
|
583
|
+
if (os_platform =~ /win/i && !(os_platform =~ /darwin/i)) ||
|
|
584
|
+
os_platform =~ /w32/i
|
|
585
|
+
:windows
|
|
586
|
+
elsif os_platform =~ /solaris/i
|
|
587
|
+
:solaris
|
|
588
|
+
elsif os_platform =~ /netbsd/i
|
|
589
|
+
:netbsd
|
|
590
|
+
elsif os_platform =~ /openbsd/i
|
|
591
|
+
:openbsd
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# making these class variables helps with testing
|
|
596
|
+
@ipconfig_command = "ipconfig"
|
|
597
|
+
@ipconfig_path_default = "c:\\windows\\system32\\ipconfig.exe"
|
|
598
|
+
@ifconfig_command = "ifconfig"
|
|
599
|
+
@ifconfig_path_default = "/sbin/ifconfig"
|
|
600
|
+
@ip_command = "ip"
|
|
601
|
+
@ip_path_default = "/sbin/ip"
|
|
602
|
+
|
|
603
|
+
class << self
|
|
604
|
+
attr_accessor :ipconfig_command, :ipconfig_path_default
|
|
605
|
+
attr_accessor :ifconfig_command, :ifconfig_path_default
|
|
606
|
+
attr_accessor :ip_command, :ip_path_default
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
#
|
|
610
|
+
# Find the path of the ipconfig command if it is present
|
|
611
|
+
#
|
|
612
|
+
def self.ipconfig_path
|
|
613
|
+
path = `where #{UUID.ipconfig_command}`.strip
|
|
614
|
+
path = UUID.ipconfig_path_default if path == "" && File.exist?(UUID.ipconfig_path_default)
|
|
615
|
+
return (path === "" ? nil : path)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
#
|
|
619
|
+
# Find the path of the ifconfig(8) command if it is present
|
|
620
|
+
#
|
|
621
|
+
def self.ifconfig_path
|
|
622
|
+
path = `which #{UUID.ifconfig_command} 2>/dev/null`.strip
|
|
623
|
+
path = UUID.ifconfig_path_default if path == "" && File.exist?(UUID.ifconfig_path_default)
|
|
624
|
+
return (path === "" ? nil : path)
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
#
|
|
628
|
+
# Find the path of the ip(8) command if it is present
|
|
629
|
+
#
|
|
630
|
+
def self.ip_path
|
|
631
|
+
path = `which #{UUID.ip_command} 2>/dev/null`.strip
|
|
632
|
+
path = UUID.ip_path_default if path == "" && File.exist?(UUID.ip_path_default)
|
|
633
|
+
return (path === "" ? nil : path)
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
#
|
|
637
|
+
# Call the ipconfig command that is found
|
|
638
|
+
#
|
|
639
|
+
def self.ipconfig(all = nil)
|
|
640
|
+
ipconfig_path = UUID.ipconfig_path
|
|
641
|
+
command =
|
|
642
|
+
if ipconfig_path
|
|
643
|
+
"#{ipconfig_path}#{all ? ' /all' : ''}"
|
|
644
|
+
end
|
|
645
|
+
`#{command}` if command
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
#
|
|
649
|
+
# Call the ifconfig or ip command that is found
|
|
650
|
+
#
|
|
651
|
+
def self.ifconfig(all = nil)
|
|
652
|
+
ifconfig_path = UUID.ifconfig_path
|
|
653
|
+
ip_path = UUID.ip_path
|
|
654
|
+
command =
|
|
655
|
+
if ifconfig_path
|
|
656
|
+
"#{ifconfig_path}#{all ? ' -a' : ''}"
|
|
657
|
+
elsif ip_path
|
|
658
|
+
"#{ip_path} addr list"
|
|
659
|
+
end
|
|
660
|
+
`#{command}` if command
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Match and return the first Mac address found
|
|
664
|
+
def self.first_mac(instring)
|
|
665
|
+
return nil if instring.nil?
|
|
666
|
+
|
|
667
|
+
mac_regexps = [
|
|
668
|
+
Regexp.new("address:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
669
|
+
Regexp.new("addr:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
670
|
+
Regexp.new("ether:? (#{(["[0-9a-fA-F]{1,2}"] * 6).join(":")})"),
|
|
671
|
+
Regexp.new("HWaddr:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
672
|
+
Regexp.new("link/ether? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
673
|
+
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
674
|
+
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join("-")})")
|
|
675
|
+
]
|
|
676
|
+
parse_mac = lambda do |output|
|
|
677
|
+
(mac_regexps.map do |regexp|
|
|
678
|
+
result = output[regexp, 1]
|
|
679
|
+
result.downcase.gsub(/-/, ":") if result != nil
|
|
680
|
+
end).compact.first
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
mac = parse_mac.call(instring)
|
|
684
|
+
if mac
|
|
685
|
+
# expand octets that were compressed (solaris)
|
|
686
|
+
return (mac.split(':').map do |octet|
|
|
687
|
+
(octet.length == 1 ? "0#{octet}" : octet)
|
|
688
|
+
end).join(':')
|
|
689
|
+
else
|
|
690
|
+
return nil
|
|
691
|
+
end
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
##
|
|
426
695
|
# Returns the MAC address of the current computer's network card.
|
|
427
696
|
# Returns nil if a MAC address could not be found.
|
|
428
|
-
def self.mac_address
|
|
697
|
+
def self.mac_address
|
|
429
698
|
if !defined?(@@mac_address)
|
|
699
|
+
@@mac_address = nil
|
|
430
700
|
require 'rbconfig'
|
|
431
|
-
|
|
432
|
-
os_class =
|
|
433
|
-
|
|
434
|
-
os_platform =~ /w32/i
|
|
435
|
-
os_class = :windows
|
|
436
|
-
elsif os_platform =~ /solaris/i
|
|
437
|
-
os_class = :solaris
|
|
438
|
-
elsif os_platform =~ /netbsd/i
|
|
439
|
-
os_class = :netbsd
|
|
440
|
-
elsif os_platform =~ /openbsd/i
|
|
441
|
-
os_class = :openbsd
|
|
442
|
-
end
|
|
443
|
-
mac_regexps = [
|
|
444
|
-
Regexp.new("address:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
445
|
-
Regexp.new("addr:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
446
|
-
Regexp.new("ether:? (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
447
|
-
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"),
|
|
448
|
-
Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join("-")})")
|
|
449
|
-
]
|
|
450
|
-
parse_mac = lambda do |output|
|
|
451
|
-
(mac_regexps.map do |regexp|
|
|
452
|
-
result = output[regexp, 1]
|
|
453
|
-
result.downcase.gsub(/-/, ":") if result != nil
|
|
454
|
-
end).compact.first
|
|
455
|
-
end
|
|
701
|
+
|
|
702
|
+
os_class = UUID.os_class
|
|
703
|
+
|
|
456
704
|
if os_class == :windows
|
|
457
|
-
script_in_path = true
|
|
458
|
-
else
|
|
459
|
-
script_in_path = Kernel.system("which ifconfig 2>&1 > /dev/null")
|
|
460
|
-
end
|
|
461
|
-
if os_class == :solaris
|
|
462
|
-
begin
|
|
463
|
-
ifconfig_output =
|
|
464
|
-
(script_in_path ? `ifconfig -a` : `/sbin/ifconfig -a`)
|
|
465
|
-
ip_addresses = ifconfig_output.scan(
|
|
466
|
-
/inet\s?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
|
|
467
|
-
ip = ip_addresses.find {|addr| addr[0] != '127.0.0.1'}[0]
|
|
468
|
-
@@mac_address = `/usr/sbin/arp #{ip}`.split(' ')[3]
|
|
469
|
-
rescue Exception
|
|
470
|
-
end
|
|
471
|
-
if @@mac_address == "" || @@mac_address == nil
|
|
472
|
-
begin
|
|
473
|
-
ifconfig_output =
|
|
474
|
-
(script_in_path ?
|
|
475
|
-
`ifconfig -a` : `/sbin/ifconfig -a`).split(' ')
|
|
476
|
-
index = ifconfig_output.index("inet") + 1
|
|
477
|
-
ip = ifconfig_output[index]
|
|
478
|
-
@@mac_address = `arp #{ip}`.split(' ')[3]
|
|
479
|
-
rescue Exception
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
elsif os_class == :windows
|
|
483
705
|
begin
|
|
484
|
-
|
|
706
|
+
ipconfig_output = UUID.ipconfig(:all)
|
|
707
|
+
@@mac_address = UUID.first_mac ipconfig_output
|
|
485
708
|
rescue
|
|
486
709
|
end
|
|
487
710
|
else
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
)
|
|
493
|
-
elsif os_class == :openbsd
|
|
494
|
-
@@mac_address = parse_mac.call(
|
|
495
|
-
script_in_path ? `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`
|
|
496
|
-
)
|
|
497
|
-
elsif File.exists?('/sbin/ifconfig')
|
|
498
|
-
@@mac_address = parse_mac.call(
|
|
499
|
-
script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`
|
|
500
|
-
)
|
|
501
|
-
if @@mac_address == nil
|
|
502
|
-
@@mac_address = parse_mac.call(
|
|
503
|
-
script_in_path ?
|
|
504
|
-
`ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`
|
|
505
|
-
)
|
|
506
|
-
end
|
|
507
|
-
if @@mac_address == nil
|
|
508
|
-
@@mac_address = parse_mac.call(
|
|
509
|
-
script_in_path ?
|
|
510
|
-
`ifconfig | grep HWaddr | cut -c39- 2>&1` :
|
|
511
|
-
`/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`
|
|
512
|
-
)
|
|
513
|
-
end
|
|
514
|
-
else
|
|
515
|
-
@@mac_address = parse_mac.call(
|
|
516
|
-
script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`
|
|
517
|
-
)
|
|
518
|
-
if @@mac_address == nil
|
|
519
|
-
@@mac_address = parse_mac.call(
|
|
520
|
-
script_in_path ?
|
|
521
|
-
`ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`
|
|
522
|
-
)
|
|
523
|
-
end
|
|
524
|
-
if @@mac_address == nil
|
|
525
|
-
@@mac_address = parse_mac.call(
|
|
526
|
-
script_in_path ?
|
|
527
|
-
`ifconfig | grep HWaddr | cut -c39- 2>&1` :
|
|
528
|
-
`/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`
|
|
529
|
-
)
|
|
530
|
-
end
|
|
531
|
-
end
|
|
532
|
-
rescue
|
|
711
|
+
ifconfig_output = UUID.ifconfig(:all)
|
|
712
|
+
if ifconfig_output
|
|
713
|
+
# linux, bsd, macos, solaris
|
|
714
|
+
@@mac_address = UUID.first_mac ifconfig_output
|
|
533
715
|
end
|
|
534
716
|
end
|
|
717
|
+
|
|
535
718
|
if @@mac_address != nil
|
|
536
719
|
if @@mac_address.respond_to?(:to_str)
|
|
537
720
|
@@mac_address = @@mac_address.to_str
|
|
@@ -552,6 +735,7 @@ module UUIDTools
|
|
|
552
735
|
return @@mac_address
|
|
553
736
|
end
|
|
554
737
|
|
|
738
|
+
##
|
|
555
739
|
# Allows users to set the MAC address manually in cases where the MAC
|
|
556
740
|
# address cannot be obtained programatically.
|
|
557
741
|
def self.mac_address=(new_mac_address)
|
|
@@ -561,8 +745,12 @@ module UUIDTools
|
|
|
561
745
|
# The following methods are not part of the public API,
|
|
562
746
|
# and generally should not be called directly.
|
|
563
747
|
|
|
748
|
+
|
|
749
|
+
##
|
|
564
750
|
# Creates a new UUID from a SHA1 or MD5 hash
|
|
565
|
-
|
|
751
|
+
#
|
|
752
|
+
# @api private
|
|
753
|
+
def self.create_from_hash(hash_class, namespace, name)
|
|
566
754
|
if hash_class == Digest::MD5
|
|
567
755
|
version = 3
|
|
568
756
|
elsif hash_class == Digest::SHA1
|
|
@@ -585,28 +773,60 @@ module UUIDTools
|
|
|
585
773
|
return new_uuid
|
|
586
774
|
end
|
|
587
775
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
776
|
+
##
|
|
777
|
+
# @api private
|
|
778
|
+
def self.convert_int_to_byte_string(integer, size)
|
|
779
|
+
byte_string = +""
|
|
780
|
+
if byte_string.respond_to?(:force_encoding)
|
|
781
|
+
byte_string.force_encoding(Encoding::ASCII_8BIT)
|
|
782
|
+
end
|
|
783
|
+
size.times do |i|
|
|
591
784
|
byte_string << ((integer >> (((size - 1) - i) * 8)) & 0xFF)
|
|
592
785
|
end
|
|
593
786
|
return byte_string
|
|
594
787
|
end
|
|
595
788
|
|
|
596
|
-
|
|
789
|
+
##
|
|
790
|
+
# @api private
|
|
791
|
+
def self.convert_byte_string_to_int(byte_string)
|
|
792
|
+
if byte_string.respond_to?(:force_encoding)
|
|
793
|
+
byte_string.force_encoding(Encoding::ASCII_8BIT)
|
|
794
|
+
end
|
|
795
|
+
|
|
597
796
|
integer = 0
|
|
598
797
|
size = byte_string.size
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
byte_string[i].ord
|
|
602
|
-
|
|
798
|
+
if byte_string[0].respond_to? :ord
|
|
799
|
+
for i in 0...size
|
|
800
|
+
integer += (byte_string[i].ord << (((size - 1) - i) * 8))
|
|
801
|
+
end
|
|
802
|
+
else
|
|
803
|
+
for i in 0...size
|
|
804
|
+
integer += (byte_string[i] << (((size - 1) - i) * 8))
|
|
805
|
+
end
|
|
603
806
|
end
|
|
807
|
+
|
|
604
808
|
return integer
|
|
605
809
|
end
|
|
606
810
|
end
|
|
607
811
|
|
|
812
|
+
##
|
|
813
|
+
# Constant Regexp that matches a UUID and captures its components.
|
|
814
|
+
UUID_REGEXP = Regexp.new("\\A([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-" +
|
|
815
|
+
"([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})\\z")
|
|
816
|
+
|
|
817
|
+
##
|
|
818
|
+
# Constant that represents the DNS namespace.
|
|
608
819
|
UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
|
820
|
+
|
|
821
|
+
##
|
|
822
|
+
# Constant that represents the URL namespace.
|
|
609
823
|
UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
|
824
|
+
|
|
825
|
+
##
|
|
826
|
+
# Constant that represents the OID namespace.
|
|
610
827
|
UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
|
828
|
+
|
|
829
|
+
##
|
|
830
|
+
# Constant that represents the X500 namespace.
|
|
611
831
|
UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
|
612
832
|
end
|