uuidtools 1.0.7 → 2.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.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ == UUIDTools 2.0.0
2
+ * moved to its own module to avoid collisions
1
3
  == UUIDTools 1.0.7
2
4
  * fixed incompatible SecureRandom implementation
3
5
  == UUIDTools 1.0.6
data/Rakefile CHANGED
@@ -8,7 +8,6 @@ require 'rake/testtask'
8
8
  require 'rake/rdoctask'
9
9
  require 'rake/packagetask'
10
10
  require 'rake/gempackagetask'
11
- require 'rake/contrib/rubyforgepublisher'
12
11
  require 'spec/rake/spectask'
13
12
 
14
13
  require File.join(File.dirname(__FILE__), 'lib/uuidtools', 'version')
@@ -37,553 +37,554 @@ rescue LoadError
37
37
  require File.join(File.dirname(__FILE__), 'compat', 'securerandom')
38
38
  end
39
39
 
40
- #= uuidtools.rb
41
- #
42
- # UUIDTools was designed to be a simple library for generating any
43
- # of the various types of UUIDs. It conforms to RFC 4122 whenever
44
- # possible.
45
- #
46
- #== Example
47
- # UUID.md5_create(UUID_DNS_NAMESPACE, "www.widgets.com")
48
- # => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29>
49
- # UUID.sha1_create(UUID_DNS_NAMESPACE, "www.widgets.com")
50
- # => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
51
- # UUID.timestamp_create
52
- # => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>
53
- # UUID.random_create
54
- # => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
55
- class UUID
56
- include Comparable
57
-
58
- @@last_timestamp = nil
59
- @@last_node_id = nil
60
- @@last_clock_sequence = nil
61
- @@state_file = nil
62
- @@mutex = Mutex.new
63
-
64
- def initialize(time_low, time_mid, time_hi_and_version,
65
- clock_seq_hi_and_reserved, clock_seq_low, nodes)
66
- unless time_low >= 0 && time_low < 4294967296
67
- raise ArgumentError,
68
- "Expected unsigned 32-bit number for time_low, got #{time_low}."
69
- end
70
- unless time_mid >= 0 && time_mid < 65536
71
- raise ArgumentError,
72
- "Expected unsigned 16-bit number for time_mid, got #{time_mid}."
73
- end
74
- unless time_hi_and_version >= 0 && time_hi_and_version < 65536
75
- raise ArgumentError,
76
- "Expected unsigned 16-bit number for time_hi_and_version, " +
77
- "got #{time_hi_and_version}."
78
- end
79
- unless clock_seq_hi_and_reserved >= 0 && clock_seq_hi_and_reserved < 256
80
- raise ArgumentError,
81
- "Expected unsigned 8-bit number for clock_seq_hi_and_reserved, " +
82
- "got #{clock_seq_hi_and_reserved}."
83
- end
84
- unless clock_seq_low >= 0 && clock_seq_low < 256
85
- raise ArgumentError,
86
- "Expected unsigned 8-bit number for clock_seq_low, " +
87
- "got #{clock_seq_low}."
88
- end
89
- unless nodes.kind_of?(Enumerable)
90
- raise TypeError,
91
- "Expected Enumerable, got #{nodes.class.name}."
92
- end
93
- unless nodes.size == 6
94
- raise ArgumentError,
95
- "Expected nodes to have size of 6."
96
- end
97
- for node in nodes
98
- unless node >= 0 && node < 256
40
+ module UUIDTools
41
+ #= uuidtools.rb
42
+ #
43
+ # UUIDTools was designed to be a simple library for generating any
44
+ # of the various types of UUIDs. It conforms to RFC 4122 whenever
45
+ # possible.
46
+ #
47
+ #== Example
48
+ # UUID.md5_create(UUID_DNS_NAMESPACE, "www.widgets.com")
49
+ # => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29>
50
+ # UUID.sha1_create(UUID_DNS_NAMESPACE, "www.widgets.com")
51
+ # => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>
52
+ # UUID.timestamp_create
53
+ # => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>
54
+ # UUID.random_create
55
+ # => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
56
+ class UUID
57
+ include Comparable
58
+
59
+ @@last_timestamp = nil
60
+ @@last_node_id = nil
61
+ @@last_clock_sequence = nil
62
+ @@state_file = nil
63
+ @@mutex = Mutex.new
64
+
65
+ def initialize(time_low, time_mid, time_hi_and_version,
66
+ clock_seq_hi_and_reserved, clock_seq_low, nodes)
67
+ unless time_low >= 0 && time_low < 4294967296
99
68
  raise ArgumentError,
100
- "Expected unsigned 8-bit number for each node, " +
101
- "got #{node}."
69
+ "Expected unsigned 32-bit number for time_low, got #{time_low}."
102
70
  end
103
- end
104
- @time_low = time_low
105
- @time_mid = time_mid
106
- @time_hi_and_version = time_hi_and_version
107
- @clock_seq_hi_and_reserved = clock_seq_hi_and_reserved
108
- @clock_seq_low = clock_seq_low
109
- @nodes = nodes
110
- end
111
-
112
- attr_accessor :time_low
113
- attr_accessor :time_mid
114
- attr_accessor :time_hi_and_version
115
- attr_accessor :clock_seq_hi_and_reserved
116
- attr_accessor :clock_seq_low
117
- attr_accessor :nodes
118
-
119
- # Parses a UUID from a string.
120
- def self.parse(uuid_string)
121
- unless uuid_string.kind_of? String
122
- raise TypeError,
123
- "Expected String, got #{uuid_string.class.name} instead."
124
- end
125
- uuid_components = uuid_string.downcase.scan(
126
- Regexp.new("^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-" +
127
- "([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})$")).first
128
- raise ArgumentError, "Invalid UUID format." if uuid_components.nil?
129
- time_low = uuid_components[0].to_i(16)
130
- time_mid = uuid_components[1].to_i(16)
131
- time_hi_and_version = uuid_components[2].to_i(16)
132
- clock_seq_hi_and_reserved = uuid_components[3].to_i(16)
133
- clock_seq_low = uuid_components[4].to_i(16)
134
- nodes = []
135
- for i in 0..5
136
- nodes << uuid_components[5][(i * 2)..(i * 2) + 1].to_i(16)
137
- end
138
- return self.new(time_low, time_mid, time_hi_and_version,
139
- clock_seq_hi_and_reserved, clock_seq_low, nodes)
140
- end
141
-
142
- # Parses a UUID from a raw byte string.
143
- def self.parse_raw(raw_string)
144
- unless raw_string.kind_of? String
145
- raise TypeError,
146
- "Expected String, got #{raw_string.class.name} instead."
147
- end
148
- integer = self.convert_byte_string_to_int(raw_string)
149
-
150
- time_low = (integer >> 96) & 0xFFFFFFFF
151
- time_mid = (integer >> 80) & 0xFFFF
152
- time_hi_and_version = (integer >> 64) & 0xFFFF
153
- clock_seq_hi_and_reserved = (integer >> 56) & 0xFF
154
- clock_seq_low = (integer >> 48) & 0xFF
155
- nodes = []
156
- for i in 0..5
157
- nodes << ((integer >> (40 - (i * 8))) & 0xFF)
158
- end
159
- return self.new(time_low, time_mid, time_hi_and_version,
160
- clock_seq_hi_and_reserved, clock_seq_low, nodes)
161
- end
162
-
163
- # Creates a UUID from a random value.
164
- def self.random_create()
165
- new_uuid = self.parse_raw(SecureRandom.random_bytes(16))
166
- new_uuid.time_hi_and_version &= 0x0FFF
167
- new_uuid.time_hi_and_version |= (4 << 12)
168
- new_uuid.clock_seq_hi_and_reserved &= 0x3F
169
- new_uuid.clock_seq_hi_and_reserved |= 0x80
170
- return new_uuid
171
- end
172
-
173
- # Creates a UUID from a timestamp.
174
- def self.timestamp_create(timestamp=nil)
175
- # We need a lock here to prevent two threads from ever
176
- # getting the same timestamp.
177
- @@mutex.synchronize do
178
- # Always use GMT to generate UUIDs.
179
- if timestamp.nil?
180
- gmt_timestamp = Time.now.gmtime
181
- else
182
- gmt_timestamp = timestamp.gmtime
71
+ unless time_mid >= 0 && time_mid < 65536
72
+ raise ArgumentError,
73
+ "Expected unsigned 16-bit number for time_mid, got #{time_mid}."
183
74
  end
184
- # Convert to 100 nanosecond blocks
185
- gmt_timestamp_100_nanoseconds = (gmt_timestamp.tv_sec * 10000000) +
186
- (gmt_timestamp.tv_usec * 10) + 0x01B21DD213814000
187
- mac_address = self.mac_address
188
- node_id = 0
189
- if mac_address != nil
190
- nodes = mac_address.split(":").collect do |octet|
191
- octet.to_i(16)
192
- end
193
- else
194
- nodes = SecureRandom.random_bytes(6).split("").map do |chr|
195
- # Ruby 1.9 / Ruby 1.8
196
- chr.respond_to?(:ord) ? chr.ord : chr.sum(8)
197
- end
198
- nodes[0] |= 0b00000001
75
+ unless time_hi_and_version >= 0 && time_hi_and_version < 65536
76
+ raise ArgumentError,
77
+ "Expected unsigned 16-bit number for time_hi_and_version, " +
78
+ "got #{time_hi_and_version}."
199
79
  end
200
- for i in 0..5
201
- node_id += (nodes[i] << (40 - (i * 8)))
80
+ unless clock_seq_hi_and_reserved >= 0 && clock_seq_hi_and_reserved < 256
81
+ raise ArgumentError,
82
+ "Expected unsigned 8-bit number for clock_seq_hi_and_reserved, " +
83
+ "got #{clock_seq_hi_and_reserved}."
202
84
  end
203
- clock_sequence = @@last_clock_sequence
204
- if clock_sequence.nil?
205
- clock_sequence = self.convert_byte_string_to_int(
206
- SecureRandom.random_bytes(16)
207
- )
85
+ unless clock_seq_low >= 0 && clock_seq_low < 256
86
+ raise ArgumentError,
87
+ "Expected unsigned 8-bit number for clock_seq_low, " +
88
+ "got #{clock_seq_low}."
208
89
  end
209
- if @@last_node_id != nil && @@last_node_id != node_id
210
- # The node id has changed. Change the clock id.
211
- clock_sequence = self.convert_byte_string_to_int(
212
- SecureRandom.random_bytes(16)
213
- )
214
- elsif @@last_timestamp != nil &&
215
- gmt_timestamp_100_nanoseconds <= @@last_timestamp
216
- clock_sequence = clock_sequence + 1
90
+ unless nodes.kind_of?(Enumerable)
91
+ raise TypeError,
92
+ "Expected Enumerable, got #{nodes.class.name}."
93
+ end
94
+ unless nodes.size == 6
95
+ raise ArgumentError,
96
+ "Expected nodes to have size of 6."
217
97
  end
218
- @@last_timestamp = gmt_timestamp_100_nanoseconds
219
- @@last_node_id = node_id
220
- @@last_clock_sequence = clock_sequence
221
-
222
- time_low = gmt_timestamp_100_nanoseconds & 0xFFFFFFFF
223
- time_mid = ((gmt_timestamp_100_nanoseconds >> 32) & 0xFFFF)
224
- time_hi_and_version = ((gmt_timestamp_100_nanoseconds >> 48) & 0x0FFF)
225
- time_hi_and_version |= (1 << 12)
226
- clock_seq_low = clock_sequence & 0xFF;
227
- clock_seq_hi_and_reserved = (clock_sequence & 0x3F00) >> 8
228
- clock_seq_hi_and_reserved |= 0x80
98
+ for node in nodes
99
+ unless node >= 0 && node < 256
100
+ raise ArgumentError,
101
+ "Expected unsigned 8-bit number for each node, " +
102
+ "got #{node}."
103
+ end
104
+ end
105
+ @time_low = time_low
106
+ @time_mid = time_mid
107
+ @time_hi_and_version = time_hi_and_version
108
+ @clock_seq_hi_and_reserved = clock_seq_hi_and_reserved
109
+ @clock_seq_low = clock_seq_low
110
+ @nodes = nodes
111
+ end
229
112
 
113
+ attr_accessor :time_low
114
+ attr_accessor :time_mid
115
+ attr_accessor :time_hi_and_version
116
+ attr_accessor :clock_seq_hi_and_reserved
117
+ attr_accessor :clock_seq_low
118
+ attr_accessor :nodes
119
+
120
+ # Parses a UUID from a string.
121
+ def self.parse(uuid_string)
122
+ unless uuid_string.kind_of? String
123
+ raise TypeError,
124
+ "Expected String, got #{uuid_string.class.name} instead."
125
+ 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
129
+ raise ArgumentError, "Invalid UUID format." if uuid_components.nil?
130
+ time_low = uuid_components[0].to_i(16)
131
+ time_mid = uuid_components[1].to_i(16)
132
+ time_hi_and_version = uuid_components[2].to_i(16)
133
+ clock_seq_hi_and_reserved = uuid_components[3].to_i(16)
134
+ clock_seq_low = uuid_components[4].to_i(16)
135
+ nodes = []
136
+ for i in 0..5
137
+ nodes << uuid_components[5][(i * 2)..(i * 2) + 1].to_i(16)
138
+ end
230
139
  return self.new(time_low, time_mid, time_hi_and_version,
231
140
  clock_seq_hi_and_reserved, clock_seq_low, nodes)
232
141
  end
233
- end
234
142
 
235
- # Creates a UUID using the MD5 hash. (Version 3)
236
- def self.md5_create(namespace, name)
237
- return self.create_from_hash(Digest::MD5, namespace, name)
238
- end
143
+ # Parses a UUID from a raw byte string.
144
+ def self.parse_raw(raw_string)
145
+ unless raw_string.kind_of? String
146
+ raise TypeError,
147
+ "Expected String, got #{raw_string.class.name} instead."
148
+ end
149
+ integer = self.convert_byte_string_to_int(raw_string)
150
+
151
+ time_low = (integer >> 96) & 0xFFFFFFFF
152
+ time_mid = (integer >> 80) & 0xFFFF
153
+ time_hi_and_version = (integer >> 64) & 0xFFFF
154
+ clock_seq_hi_and_reserved = (integer >> 56) & 0xFF
155
+ clock_seq_low = (integer >> 48) & 0xFF
156
+ nodes = []
157
+ for i in 0..5
158
+ nodes << ((integer >> (40 - (i * 8))) & 0xFF)
159
+ end
160
+ return self.new(time_low, time_mid, time_hi_and_version,
161
+ clock_seq_hi_and_reserved, clock_seq_low, nodes)
162
+ end
239
163
 
240
- # Creates a UUID using the SHA1 hash. (Version 5)
241
- def self.sha1_create(namespace, name)
242
- return self.create_from_hash(Digest::SHA1, namespace, name)
243
- end
164
+ # Creates a UUID from a random value.
165
+ def self.random_create()
166
+ new_uuid = self.parse_raw(SecureRandom.random_bytes(16))
167
+ new_uuid.time_hi_and_version &= 0x0FFF
168
+ new_uuid.time_hi_and_version |= (4 << 12)
169
+ new_uuid.clock_seq_hi_and_reserved &= 0x3F
170
+ new_uuid.clock_seq_hi_and_reserved |= 0x80
171
+ return new_uuid
172
+ end
244
173
 
245
- # This method applies only to version 1 UUIDs.
246
- # Checks if the node ID was generated from a random number
247
- # or from an IEEE 802 address (MAC address).
248
- # Always returns false for UUIDs that aren't version 1.
249
- # This should not be confused with version 4 UUIDs where
250
- # more than just the node id is random.
251
- def random_node_id?
252
- return false if self.version != 1
253
- return ((self.nodes.first & 0x01) == 1)
254
- end
174
+ # Creates a UUID from a timestamp.
175
+ def self.timestamp_create(timestamp=nil)
176
+ # We need a lock here to prevent two threads from ever
177
+ # getting the same timestamp.
178
+ @@mutex.synchronize do
179
+ # Always use GMT to generate UUIDs.
180
+ if timestamp.nil?
181
+ gmt_timestamp = Time.now.gmtime
182
+ else
183
+ gmt_timestamp = timestamp.gmtime
184
+ end
185
+ # Convert to 100 nanosecond blocks
186
+ gmt_timestamp_100_nanoseconds = (gmt_timestamp.tv_sec * 10000000) +
187
+ (gmt_timestamp.tv_usec * 10) + 0x01B21DD213814000
188
+ mac_address = self.mac_address
189
+ node_id = 0
190
+ if mac_address != nil
191
+ nodes = mac_address.split(":").collect do |octet|
192
+ octet.to_i(16)
193
+ end
194
+ else
195
+ nodes = []
196
+ SecureRandom.random_bytes(6).each_byte { |chr| nodes << chr }
197
+ nodes[0] |= 0b00000001
198
+ end
199
+ for i in 0..5
200
+ node_id += (nodes[i] << (40 - (i * 8)))
201
+ end
202
+ clock_sequence = @@last_clock_sequence
203
+ if clock_sequence.nil?
204
+ clock_sequence = self.convert_byte_string_to_int(
205
+ SecureRandom.random_bytes(16)
206
+ )
207
+ end
208
+ if @@last_node_id != nil && @@last_node_id != node_id
209
+ # The node id has changed. Change the clock id.
210
+ clock_sequence = self.convert_byte_string_to_int(
211
+ SecureRandom.random_bytes(16)
212
+ )
213
+ elsif @@last_timestamp != nil &&
214
+ gmt_timestamp_100_nanoseconds <= @@last_timestamp
215
+ clock_sequence = clock_sequence + 1
216
+ end
217
+ @@last_timestamp = gmt_timestamp_100_nanoseconds
218
+ @@last_node_id = node_id
219
+ @@last_clock_sequence = clock_sequence
220
+
221
+ time_low = gmt_timestamp_100_nanoseconds & 0xFFFFFFFF
222
+ time_mid = ((gmt_timestamp_100_nanoseconds >> 32) & 0xFFFF)
223
+ time_hi_and_version = ((gmt_timestamp_100_nanoseconds >> 48) & 0x0FFF)
224
+ time_hi_and_version |= (1 << 12)
225
+ clock_seq_low = clock_sequence & 0xFF;
226
+ clock_seq_hi_and_reserved = (clock_sequence & 0x3F00) >> 8
227
+ clock_seq_hi_and_reserved |= 0x80
228
+
229
+ return self.new(time_low, time_mid, time_hi_and_version,
230
+ clock_seq_hi_and_reserved, clock_seq_low, nodes)
231
+ end
232
+ end
255
233
 
256
- # Returns true if this UUID is the
257
- # nil UUID (00000000-0000-0000-0000-000000000000).
258
- def nil_uuid?
259
- return false if self.time_low != 0
260
- return false if self.time_mid != 0
261
- return false if self.time_hi_and_version != 0
262
- return false if self.clock_seq_hi_and_reserved != 0
263
- return false if self.clock_seq_low != 0
264
- self.nodes.each do |node|
265
- return false if node != 0
234
+ # Creates a UUID using the MD5 hash. (Version 3)
235
+ def self.md5_create(namespace, name)
236
+ return self.create_from_hash(Digest::MD5, namespace, name)
266
237
  end
267
- return true
268
- end
269
238
 
270
- # Returns the UUID version type.
271
- # Possible values:
272
- # 1 - Time-based with unique or random host identifier
273
- # 2 - DCE Security version (with POSIX UIDs)
274
- # 3 - Name-based (MD5 hash)
275
- # 4 - Random
276
- # 5 - Name-based (SHA-1 hash)
277
- def version
278
- return (time_hi_and_version >> 12)
279
- end
239
+ # Creates a UUID using the SHA1 hash. (Version 5)
240
+ def self.sha1_create(namespace, name)
241
+ return self.create_from_hash(Digest::SHA1, namespace, name)
242
+ end
280
243
 
281
- # Returns the UUID variant.
282
- # Possible values:
283
- # 0b000 - Reserved, NCS backward compatibility.
284
- # 0b100 - The variant specified in this document.
285
- # 0b110 - Reserved, Microsoft Corporation backward compatibility.
286
- # 0b111 - Reserved for future definition.
287
- def variant
288
- variant_raw = (clock_seq_hi_and_reserved >> 5)
289
- result = nil
290
- if (variant_raw >> 2) == 0
291
- result = 0x000
292
- elsif (variant_raw >> 1) == 2
293
- result = 0x100
294
- else
295
- result = variant_raw
244
+ # This method applies only to version 1 UUIDs.
245
+ # Checks if the node ID was generated from a random number
246
+ # or from an IEEE 802 address (MAC address).
247
+ # Always returns false for UUIDs that aren't version 1.
248
+ # This should not be confused with version 4 UUIDs where
249
+ # more than just the node id is random.
250
+ def random_node_id?
251
+ return false if self.version != 1
252
+ return ((self.nodes.first & 0x01) == 1)
296
253
  end
297
- return (result >> 6)
298
- end
299
254
 
300
- # Returns true if this UUID is valid.
301
- def valid?
302
- if [0b000, 0b100, 0b110, 0b111].include?(self.variant) &&
303
- (1..5).include?(self.version)
255
+ # Returns true if this UUID is the
256
+ # nil UUID (00000000-0000-0000-0000-000000000000).
257
+ def nil_uuid?
258
+ return false if self.time_low != 0
259
+ return false if self.time_mid != 0
260
+ return false if self.time_hi_and_version != 0
261
+ return false if self.clock_seq_hi_and_reserved != 0
262
+ return false if self.clock_seq_low != 0
263
+ self.nodes.each do |node|
264
+ return false if node != 0
265
+ end
304
266
  return true
305
- else
306
- return false
307
267
  end
308
- end
309
268
 
310
- # Returns the IEEE 802 address used to generate this UUID or
311
- # nil if a MAC address was not used.
312
- def mac_address
313
- return nil if self.version != 1
314
- return nil if self.random_node_id?
315
- return (self.nodes.collect do |node|
316
- sprintf("%2.2x", node)
317
- end).join(":")
318
- end
319
-
320
- # Returns the timestamp used to generate this UUID
321
- def timestamp
322
- return nil if self.version != 1
323
- gmt_timestamp_100_nanoseconds = 0
324
- gmt_timestamp_100_nanoseconds +=
325
- ((self.time_hi_and_version & 0x0FFF) << 48)
326
- gmt_timestamp_100_nanoseconds += (self.time_mid << 32)
327
- gmt_timestamp_100_nanoseconds += self.time_low
328
- return Time.at(
329
- (gmt_timestamp_100_nanoseconds - 0x01B21DD213814000) / 10000000.0)
330
- end
269
+ # Returns the UUID version type.
270
+ # Possible values:
271
+ # 1 - Time-based with unique or random host identifier
272
+ # 2 - DCE Security version (with POSIX UIDs)
273
+ # 3 - Name-based (MD5 hash)
274
+ # 4 - Random
275
+ # 5 - Name-based (SHA-1 hash)
276
+ def version
277
+ return (time_hi_and_version >> 12)
278
+ end
331
279
 
332
- # Compares two UUIDs lexically
333
- def <=>(other_uuid)
334
- check = self.time_low <=> other_uuid.time_low
335
- return check if check != 0
336
- check = self.time_mid <=> other_uuid.time_mid
337
- return check if check != 0
338
- check = self.time_hi_and_version <=> other_uuid.time_hi_and_version
339
- return check if check != 0
340
- check = self.clock_seq_hi_and_reserved <=>
341
- other_uuid.clock_seq_hi_and_reserved
342
- return check if check != 0
343
- check = self.clock_seq_low <=> other_uuid.clock_seq_low
344
- return check if check != 0
345
- for i in 0..5
346
- if (self.nodes[i] < other_uuid.nodes[i])
347
- return -1
280
+ # Returns the UUID variant.
281
+ # Possible values:
282
+ # 0b000 - Reserved, NCS backward compatibility.
283
+ # 0b100 - The variant specified in this document.
284
+ # 0b110 - Reserved, Microsoft Corporation backward compatibility.
285
+ # 0b111 - Reserved for future definition.
286
+ def variant
287
+ variant_raw = (clock_seq_hi_and_reserved >> 5)
288
+ result = nil
289
+ if (variant_raw >> 2) == 0
290
+ result = 0x000
291
+ elsif (variant_raw >> 1) == 2
292
+ result = 0x100
293
+ else
294
+ result = variant_raw
348
295
  end
349
- if (self.nodes[i] > other_uuid.nodes[i])
350
- return 1
296
+ return (result >> 6)
297
+ end
298
+
299
+ # Returns true if this UUID is valid.
300
+ def valid?
301
+ if [0b000, 0b100, 0b110, 0b111].include?(self.variant) &&
302
+ (1..5).include?(self.version)
303
+ return true
304
+ else
305
+ return false
351
306
  end
352
307
  end
353
- return 0
354
- end
355
308
 
356
- # Returns a representation of the object's state
357
- def inspect
358
- return "#<UUID:0x#{self.object_id.to_s(16)} UUID:#{self.to_s}>"
359
- end
309
+ # Returns the IEEE 802 address used to generate this UUID or
310
+ # nil if a MAC address was not used.
311
+ def mac_address
312
+ return nil if self.version != 1
313
+ return nil if self.random_node_id?
314
+ return (self.nodes.collect do |node|
315
+ sprintf("%2.2x", node)
316
+ end).join(":")
317
+ end
360
318
 
361
- # Returns the hex digest of the UUID object.
362
- def hexdigest
363
- return self.to_i.to_s(16).rjust(32, "0")
364
- end
319
+ # Returns the timestamp used to generate this UUID
320
+ def timestamp
321
+ return nil if self.version != 1
322
+ gmt_timestamp_100_nanoseconds = 0
323
+ gmt_timestamp_100_nanoseconds +=
324
+ ((self.time_hi_and_version & 0x0FFF) << 48)
325
+ gmt_timestamp_100_nanoseconds += (self.time_mid << 32)
326
+ gmt_timestamp_100_nanoseconds += self.time_low
327
+ return Time.at(
328
+ (gmt_timestamp_100_nanoseconds - 0x01B21DD213814000) / 10000000.0)
329
+ end
365
330
 
366
- # Returns the raw bytes that represent this UUID.
367
- def raw
368
- return self.class.convert_int_to_byte_string(self.to_i, 16)
369
- end
331
+ # Compares two UUIDs lexically
332
+ def <=>(other_uuid)
333
+ check = self.time_low <=> other_uuid.time_low
334
+ return check if check != 0
335
+ check = self.time_mid <=> other_uuid.time_mid
336
+ return check if check != 0
337
+ check = self.time_hi_and_version <=> other_uuid.time_hi_and_version
338
+ return check if check != 0
339
+ check = self.clock_seq_hi_and_reserved <=>
340
+ other_uuid.clock_seq_hi_and_reserved
341
+ return check if check != 0
342
+ check = self.clock_seq_low <=> other_uuid.clock_seq_low
343
+ return check if check != 0
344
+ for i in 0..5
345
+ if (self.nodes[i] < other_uuid.nodes[i])
346
+ return -1
347
+ end
348
+ if (self.nodes[i] > other_uuid.nodes[i])
349
+ return 1
350
+ end
351
+ end
352
+ return 0
353
+ end
370
354
 
371
- # Returns a string representation for this UUID.
372
- def to_s
373
- result = sprintf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", @time_low, @time_mid,
374
- @time_hi_and_version, @clock_seq_hi_and_reserved, @clock_seq_low);
375
- for i in 0..5
376
- result << sprintf("%2.2x", @nodes[i])
355
+ # Returns a representation of the object's state
356
+ def inspect
357
+ return "#<UUID:0x#{self.object_id.to_s(16)} UUID:#{self.to_s}>"
377
358
  end
378
- return result.downcase
379
- end
380
- alias_method :to_str, :to_s
381
-
382
- # Returns an integer representation for this UUID.
383
- def to_i
384
- @integer ||= (begin
385
- bytes = (time_low << 96) + (time_mid << 80) +
386
- (time_hi_and_version << 64) + (clock_seq_hi_and_reserved << 56) +
387
- (clock_seq_low << 48)
359
+
360
+ # Returns the hex digest of the UUID object.
361
+ def hexdigest
362
+ return self.to_i.to_s(16).rjust(32, "0")
363
+ end
364
+
365
+ # Returns the raw bytes that represent this UUID.
366
+ def raw
367
+ return self.class.convert_int_to_byte_string(self.to_i, 16)
368
+ end
369
+
370
+ # Returns a string representation for this UUID.
371
+ def to_s
372
+ result = sprintf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", @time_low, @time_mid,
373
+ @time_hi_and_version, @clock_seq_hi_and_reserved, @clock_seq_low);
388
374
  for i in 0..5
389
- bytes += (nodes[i] << (40 - (i * 8)))
375
+ result << sprintf("%2.2x", @nodes[i])
390
376
  end
391
- bytes
392
- end)
393
- end
377
+ return result.downcase
378
+ end
379
+ alias_method :to_str, :to_s
380
+
381
+ # Returns an integer representation for this UUID.
382
+ def to_i
383
+ @integer ||= (begin
384
+ bytes = (time_low << 96) + (time_mid << 80) +
385
+ (time_hi_and_version << 64) + (clock_seq_hi_and_reserved << 56) +
386
+ (clock_seq_low << 48)
387
+ for i in 0..5
388
+ bytes += (nodes[i] << (40 - (i * 8)))
389
+ end
390
+ bytes
391
+ end)
392
+ end
394
393
 
395
- # Returns a URI string for this UUID.
396
- def to_uri
397
- return "urn:uuid:#{self.to_s}"
398
- end
394
+ # Returns a URI string for this UUID.
395
+ def to_uri
396
+ return "urn:uuid:#{self.to_s}"
397
+ end
399
398
 
400
- # Returns an integer hash value.
401
- def hash
402
- @hash ||= self.to_i % 0x3fffffff
403
- end
399
+ # Returns an integer hash value.
400
+ def hash
401
+ @hash ||= self.to_i % 0x3fffffff
402
+ end
404
403
 
405
- # Returns true if this UUID is exactly equal to the other UUID.
406
- def eql?(other)
407
- return self == other
408
- end
404
+ # Returns true if this UUID is exactly equal to the other UUID.
405
+ def eql?(other)
406
+ return self == other
407
+ end
409
408
 
410
- # Returns the MAC address of the current computer's network card.
411
- # Returns nil if a MAC address could not be found.
412
- def self.mac_address #:nodoc:
413
- if !defined?(@@mac_address)
414
- require 'rbconfig'
415
- os_platform = Config::CONFIG['target_os']
416
- if os_platform =~ /win/ && !(os_platform =~ /darwin/)
417
- script_in_path = true
418
- else
419
- script_in_path = Kernel.system("which ifconfig 2>&1 > /dev/null")
420
- end
421
- if os_platform =~ /solaris/
422
- begin
423
- ifconfig_output =
424
- (script_in_path ? `ifconfig -a` : `/sbin/ifconfig -a`)
425
- ip_addresses = ifconfig_output.scan(
426
- /inet\s?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
427
- ip = ip_addresses.find {|addr| addr[0] != '127.0.0.1'}[0]
428
- @@mac_address = `/usr/sbin/arp #{ip}`.split(' ')[3]
429
- rescue Exception
409
+ # Returns the MAC address of the current computer's network card.
410
+ # Returns nil if a MAC address could not be found.
411
+ def self.mac_address #:nodoc:
412
+ if !defined?(@@mac_address)
413
+ require 'rbconfig'
414
+ os_platform = Config::CONFIG['target_os']
415
+ if (os_platform =~ /win/ && !(os_platform =~ /darwin/)) ||
416
+ os_platform =~ /w32/
417
+ script_in_path = true
418
+ else
419
+ script_in_path = Kernel.system("which ifconfig 2>&1 > /dev/null")
430
420
  end
431
- if @@mac_address == "" || @@mac_address == nil
421
+ if os_platform =~ /solaris/
432
422
  begin
433
423
  ifconfig_output =
434
- (script_in_path ?
435
- `ifconfig -a` : `/sbin/ifconfig -a`).split(' ')
436
- index = ifconfig_output.index("inet") + 1
437
- ip = ifconfig_output[index]
438
- @@mac_address = `arp #{ip}`.split(' ')[3]
424
+ (script_in_path ? `ifconfig -a` : `/sbin/ifconfig -a`)
425
+ ip_addresses = ifconfig_output.scan(
426
+ /inet\s?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
427
+ ip = ip_addresses.find {|addr| addr[0] != '127.0.0.1'}[0]
428
+ @@mac_address = `/usr/sbin/arp #{ip}`.split(' ')[3]
439
429
  rescue Exception
440
430
  end
441
- end
442
- elsif os_platform =~ /win/ && !(os_platform =~ /darwin/)
443
- begin
444
- ifconfig_output = `ipconfig /all`
445
- mac_addresses = ifconfig_output.scan(
446
- Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join("-")})"))
447
- if mac_addresses.size > 0
448
- @@mac_address = mac_addresses.first.first.downcase.gsub(/-/, ":")
431
+ if @@mac_address == "" || @@mac_address == nil
432
+ begin
433
+ ifconfig_output =
434
+ (script_in_path ?
435
+ `ifconfig -a` : `/sbin/ifconfig -a`).split(' ')
436
+ index = ifconfig_output.index("inet") + 1
437
+ ip = ifconfig_output[index]
438
+ @@mac_address = `arp #{ip}`.split(' ')[3]
439
+ rescue Exception
440
+ end
449
441
  end
450
- rescue
451
- end
452
- else
453
- begin
454
- mac_addresses = []
455
- if os_platform =~ /netbsd/
456
- ifconfig_output =
457
- (script_in_path ? `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
458
- mac_addresses = ifconfig_output.scan(
459
- Regexp.new("address\: (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
460
- elsif os_platform =~ /openbsd/
461
- ifconfig_output = `/sbin/ifconfig -a 2>&1`
462
- ifconfig_output =
463
- (script_in_path ? `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
464
- mac_addresses = ifconfig_output.scan(
465
- Regexp.new("addr (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
466
- elsif File.exists?('/sbin/ifconfig')
467
- ifconfig_output =
468
- (script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`)
442
+ elsif os_platform =~ /win/ && !(os_platform =~ /darwin/)
443
+ begin
444
+ ifconfig_output = `ipconfig /all`
469
445
  mac_addresses = ifconfig_output.scan(
470
- Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
471
- if mac_addresses.size == 0
446
+ Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join("-")})"))
447
+ if mac_addresses.size > 0
448
+ @@mac_address = mac_addresses.first.first.downcase.gsub(/-/, ":")
449
+ end
450
+ rescue
451
+ end
452
+ else
453
+ begin
454
+ mac_addresses = []
455
+ if os_platform =~ /netbsd/
472
456
  ifconfig_output =
473
- (script_in_path ?
474
- `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
457
+ (script_in_path ? `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
475
458
  mac_addresses = ifconfig_output.scan(
476
- Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
477
- end
478
- if mac_addresses.size == 0
459
+ Regexp.new("address\: (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
460
+ elsif os_platform =~ /openbsd/
461
+ ifconfig_output = `/sbin/ifconfig -a 2>&1`
479
462
  ifconfig_output =
480
- (script_in_path ?
481
- `ifconfig | grep HWaddr | cut -c39- 2>&1` :
482
- `/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`)
463
+ (script_in_path ? `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
483
464
  mac_addresses = ifconfig_output.scan(
484
- Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
485
- end
486
- else
487
- ifconfig_output =
488
- (script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`)
489
- mac_addresses = ifconfig_output.scan(
490
- Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
491
- if mac_addresses.size == 0
465
+ Regexp.new("addr (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
466
+ elsif File.exists?('/sbin/ifconfig')
492
467
  ifconfig_output =
493
- (script_in_path ?
494
- `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
468
+ (script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`)
495
469
  mac_addresses = ifconfig_output.scan(
496
470
  Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
497
- end
498
- if mac_addresses.size == 0
471
+ if mac_addresses.size == 0
472
+ ifconfig_output =
473
+ (script_in_path ?
474
+ `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
475
+ mac_addresses = ifconfig_output.scan(
476
+ Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
477
+ end
478
+ if mac_addresses.size == 0
479
+ ifconfig_output =
480
+ (script_in_path ?
481
+ `ifconfig | grep HWaddr | cut -c39- 2>&1` :
482
+ `/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`)
483
+ mac_addresses = ifconfig_output.scan(
484
+ Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
485
+ end
486
+ else
499
487
  ifconfig_output =
500
- (script_in_path ?
501
- `ifconfig | grep HWaddr | cut -c39- 2>&1` :
502
- `/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`)
488
+ (script_in_path ? `ifconfig 2>&1` : `/sbin/ifconfig 2>&1`)
503
489
  mac_addresses = ifconfig_output.scan(
504
- Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
490
+ Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
491
+ if mac_addresses.size == 0
492
+ ifconfig_output =
493
+ (script_in_path ?
494
+ `ifconfig -a 2>&1` : `/sbin/ifconfig -a 2>&1`)
495
+ mac_addresses = ifconfig_output.scan(
496
+ Regexp.new("ether (#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
497
+ end
498
+ if mac_addresses.size == 0
499
+ ifconfig_output =
500
+ (script_in_path ?
501
+ `ifconfig | grep HWaddr | cut -c39- 2>&1` :
502
+ `/sbin/ifconfig | grep HWaddr | cut -c39- 2>&1`)
503
+ mac_addresses = ifconfig_output.scan(
504
+ Regexp.new("(#{(["[0-9a-fA-F]{2}"] * 6).join(":")})"))
505
+ end
505
506
  end
507
+ if mac_addresses.size > 0
508
+ @@mac_address = mac_addresses.first.first
509
+ end
510
+ rescue
506
511
  end
507
- if mac_addresses.size > 0
508
- @@mac_address = mac_addresses.first.first
512
+ end
513
+ if @@mac_address != nil
514
+ if @@mac_address.respond_to?(:to_str)
515
+ @@mac_address = @@mac_address.to_str
516
+ else
517
+ @@mac_address = @@mac_address.to_s
509
518
  end
510
- rescue
519
+ @@mac_address.downcase!
520
+ @@mac_address.strip!
511
521
  end
512
- end
513
- if @@mac_address != nil
514
- if @@mac_address.respond_to?(:to_str)
515
- @@mac_address = @@mac_address.to_str
516
- else
517
- @@mac_address = @@mac_address.to_s
522
+
523
+ # Verify that the MAC address is in the right format.
524
+ # Nil it out if it isn't.
525
+ unless @@mac_address.respond_to?(:scan) &&
526
+ @@mac_address.scan(/#{(["[0-9a-f]{2}"] * 6).join(":")}/)
527
+ @@mac_address = nil
518
528
  end
519
- @@mac_address.downcase!
520
- @@mac_address.strip!
521
529
  end
530
+ return @@mac_address
531
+ end
522
532
 
523
- # Verify that the MAC address is in the right format.
524
- # Nil it out if it isn't.
525
- unless @@mac_address.respond_to?(:scan) &&
526
- @@mac_address.scan(/#{(["[0-9a-f]{2}"] * 6).join(":")}/)
527
- @@mac_address = nil
528
- end
533
+ # Allows users to set the MAC address manually in cases where the MAC
534
+ # address cannot be obtained programatically.
535
+ def self.mac_address=(new_mac_address)
536
+ @@mac_address = new_mac_address
529
537
  end
530
- return @@mac_address
531
- end
532
538
 
533
- # Allows users to set the MAC address manually in cases where the MAC
534
- # address cannot be obtained programatically.
535
- def self.mac_address=(new_mac_address)
536
- @@mac_address = new_mac_address
537
- end
539
+ # The following methods are not part of the public API,
540
+ # and generally should not be called directly.
538
541
 
539
- # The following methods are not part of the public API,
540
- # and generally should not be called directly.
541
-
542
- # Creates a new UUID from a SHA1 or MD5 hash
543
- def self.create_from_hash(hash_class, namespace, name) #:nodoc:
544
- if hash_class == Digest::MD5
545
- version = 3
546
- elsif hash_class == Digest::SHA1
547
- version = 5
548
- else
549
- raise ArgumentError,
550
- "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
542
+ # Creates a new UUID from a SHA1 or MD5 hash
543
+ def self.create_from_hash(hash_class, namespace, name) #:nodoc:
544
+ if hash_class == Digest::MD5
545
+ version = 3
546
+ elsif hash_class == Digest::SHA1
547
+ version = 5
548
+ else
549
+ raise ArgumentError,
550
+ "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
551
+ end
552
+ hash = hash_class.new
553
+ hash.update(namespace.raw)
554
+ hash.update(name)
555
+ hash_string = hash.to_s[0..31]
556
+ new_uuid = self.parse("#{hash_string[0..7]}-#{hash_string[8..11]}-" +
557
+ "#{hash_string[12..15]}-#{hash_string[16..19]}-#{hash_string[20..31]}")
558
+
559
+ new_uuid.time_hi_and_version &= 0x0FFF
560
+ new_uuid.time_hi_and_version |= (version << 12)
561
+ new_uuid.clock_seq_hi_and_reserved &= 0x3F
562
+ new_uuid.clock_seq_hi_and_reserved |= 0x80
563
+ return new_uuid
551
564
  end
552
- hash = hash_class.new
553
- hash.update(namespace.raw)
554
- hash.update(name)
555
- hash_string = hash.to_s[0..31]
556
- new_uuid = self.parse("#{hash_string[0..7]}-#{hash_string[8..11]}-" +
557
- "#{hash_string[12..15]}-#{hash_string[16..19]}-#{hash_string[20..31]}")
558
-
559
- new_uuid.time_hi_and_version &= 0x0FFF
560
- new_uuid.time_hi_and_version |= (version << 12)
561
- new_uuid.clock_seq_hi_and_reserved &= 0x3F
562
- new_uuid.clock_seq_hi_and_reserved |= 0x80
563
- return new_uuid
564
- end
565
565
 
566
- def self.convert_int_to_byte_string(integer, size) #:nodoc:
567
- byte_string = ""
568
- for i in 0..(size - 1)
569
- byte_string << ((integer >> (((size - 1) - i) * 8)) & 0xFF)
566
+ def self.convert_int_to_byte_string(integer, size) #:nodoc:
567
+ byte_string = ""
568
+ for i in 0..(size - 1)
569
+ byte_string << ((integer >> (((size - 1) - i) * 8)) & 0xFF)
570
+ end
571
+ return byte_string
570
572
  end
571
- return byte_string
572
- end
573
573
 
574
- def self.convert_byte_string_to_int(byte_string) #:nodoc:
575
- integer = 0
576
- size = byte_string.size
577
- for i in 0..(size - 1)
578
- ordinal = (byte_string[i].respond_to?(:ord) ?
579
- byte_string[i].ord : byte_string[i])
580
- integer += (ordinal << (((size - 1) - i) * 8))
574
+ def self.convert_byte_string_to_int(byte_string) #:nodoc:
575
+ integer = 0
576
+ size = byte_string.size
577
+ for i in 0..(size - 1)
578
+ ordinal = (byte_string[i].respond_to?(:ord) ?
579
+ byte_string[i].ord : byte_string[i])
580
+ integer += (ordinal << (((size - 1) - i) * 8))
581
+ end
582
+ return integer
581
583
  end
582
- return integer
583
584
  end
584
- end
585
585
 
586
- UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
587
- UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
588
- UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
589
- UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
586
+ UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
587
+ UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
588
+ UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
589
+ UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
590
+ end