uuidtools 1.0.4 → 1.0.5
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 +6 -0
- data/Rakefile +6 -1
- data/lib/compat/securerandom.rb +197 -0
- data/lib/uuidtools.rb +38 -50
- data/lib/uuidtools/version.rb +9 -6
- data/spec/uuidtools/utility_spec.rb +17 -0
- data/spec/uuidtools/uuid_creation_spec.rb +85 -2
- data/spec/uuidtools/uuid_parsing_spec.rb +70 -0
- data/tasks/gem.rake +8 -2
- data/tasks/rubyforge.rake +14 -3
- data/tasks/spec.rake +28 -53
- metadata +20 -7
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== UUIDTools 1.0.5
|
2
|
+
* improved specs
|
3
|
+
* fixed minor bugs
|
4
|
+
* better JRuby compatibility
|
5
|
+
* uses securerandom library
|
6
|
+
* updated rake tasks
|
1
7
|
== UUIDTools 1.0.4
|
2
8
|
* calculates random node id with multicast bit if there is no MAC address
|
3
9
|
* uses RSpec instead of Test::Unit
|
data/Rakefile
CHANGED
@@ -36,7 +36,12 @@ PKG_FILES = FileList[
|
|
36
36
|
"[A-Z]*", "Rakefile"
|
37
37
|
].exclude(/database\.yml/).exclude(/[_\.]git$/)
|
38
38
|
|
39
|
-
|
39
|
+
RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/)
|
40
|
+
if RCOV_ENABLED
|
41
|
+
task :default => "spec:verify"
|
42
|
+
else
|
43
|
+
task :default => "spec"
|
44
|
+
end
|
40
45
|
|
41
46
|
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
42
47
|
SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# = Secure random number generator interface.
|
2
|
+
#
|
3
|
+
# This library is an interface for secure random number generator which is
|
4
|
+
# suitable for generating session key in HTTP cookies, etc.
|
5
|
+
#
|
6
|
+
# It supports following secure random number generators.
|
7
|
+
#
|
8
|
+
# * openssl
|
9
|
+
# * /dev/urandom
|
10
|
+
# * Win32
|
11
|
+
#
|
12
|
+
# == Example
|
13
|
+
#
|
14
|
+
# # random hexadecimal string.
|
15
|
+
# p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
|
16
|
+
# p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
|
17
|
+
# p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
|
18
|
+
# p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
|
19
|
+
# p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
|
20
|
+
# ...
|
21
|
+
#
|
22
|
+
# # random base64 string.
|
23
|
+
# p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
|
24
|
+
# p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
|
25
|
+
# p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
|
26
|
+
# p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
|
27
|
+
# p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
|
28
|
+
# p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
|
29
|
+
# ...
|
30
|
+
#
|
31
|
+
# # random binary string.
|
32
|
+
# p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
|
33
|
+
# p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
|
34
|
+
# ...
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'openssl'
|
38
|
+
rescue LoadError
|
39
|
+
end
|
40
|
+
|
41
|
+
module SecureRandom
|
42
|
+
# SecureRandom.random_bytes generates a random binary string.
|
43
|
+
#
|
44
|
+
# The argument n specifies the length of the result string.
|
45
|
+
#
|
46
|
+
# If n is not specified, 16 is assumed.
|
47
|
+
# It may be larger in future.
|
48
|
+
#
|
49
|
+
# If secure random number generator is not available,
|
50
|
+
# NotImplementedError is raised.
|
51
|
+
def self.random_bytes(n=nil)
|
52
|
+
n ||= 16
|
53
|
+
|
54
|
+
if defined? OpenSSL::Random
|
55
|
+
return OpenSSL::Random.random_bytes(n)
|
56
|
+
end
|
57
|
+
|
58
|
+
if !defined?(@has_urandom) || @has_urandom
|
59
|
+
flags = File::RDONLY
|
60
|
+
flags |= File::NONBLOCK if defined? File::NONBLOCK
|
61
|
+
flags |= File::NOCTTY if defined? File::NOCTTY
|
62
|
+
flags |= File::NOFOLLOW if defined? File::NOFOLLOW
|
63
|
+
begin
|
64
|
+
File.open("/dev/urandom", flags) {|f|
|
65
|
+
unless f.stat.chardev?
|
66
|
+
raise Errno::ENOENT
|
67
|
+
end
|
68
|
+
@has_urandom = true
|
69
|
+
ret = f.readpartial(n)
|
70
|
+
if ret.length != n
|
71
|
+
raise NotImplementedError,
|
72
|
+
"Unexpected partial read from random device"
|
73
|
+
end
|
74
|
+
return ret
|
75
|
+
}
|
76
|
+
rescue Errno::ENOENT
|
77
|
+
@has_urandom = false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if !defined?(@has_win32)
|
82
|
+
begin
|
83
|
+
require 'Win32API'
|
84
|
+
|
85
|
+
crypt_acquire_context = Win32API.new(
|
86
|
+
"advapi32", "CryptAcquireContext", 'PPPII', 'L'
|
87
|
+
)
|
88
|
+
@crypt_gen_random = Win32API.new(
|
89
|
+
"advapi32", "CryptGenRandom", 'LIP', 'L'
|
90
|
+
)
|
91
|
+
|
92
|
+
hProvStr = " " * 4
|
93
|
+
prov_rsa_full = 1
|
94
|
+
crypt_verifycontext = 0xF0000000
|
95
|
+
|
96
|
+
if crypt_acquire_context.call(
|
97
|
+
hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
|
98
|
+
raise SystemCallError,
|
99
|
+
"CryptAcquireContext failed: #{lastWin32ErrorMessage}"
|
100
|
+
end
|
101
|
+
@hProv, = hProvStr.unpack('L')
|
102
|
+
|
103
|
+
@has_win32 = true
|
104
|
+
rescue LoadError
|
105
|
+
@has_win32 = false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
if @has_win32
|
109
|
+
bytes = " " * n
|
110
|
+
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
|
111
|
+
raise SystemCallError,
|
112
|
+
"CryptGenRandom failed: #{lastWin32ErrorMessage}"
|
113
|
+
end
|
114
|
+
return bytes
|
115
|
+
end
|
116
|
+
|
117
|
+
raise NotImplementedError, "No random device"
|
118
|
+
end
|
119
|
+
|
120
|
+
# SecureRandom.hex generates a random hex string.
|
121
|
+
#
|
122
|
+
# The argument n specifies the length of the random length.
|
123
|
+
# The length of the result string is twice of n.
|
124
|
+
#
|
125
|
+
# If n is not specified, 16 is assumed.
|
126
|
+
# It may be larger in future.
|
127
|
+
#
|
128
|
+
# If secure random number generator is not available,
|
129
|
+
# NotImplementedError is raised.
|
130
|
+
def self.hex(n=nil)
|
131
|
+
random_bytes(n).unpack("H*")[0]
|
132
|
+
end
|
133
|
+
|
134
|
+
# SecureRandom.base64 generates a random base64 string.
|
135
|
+
#
|
136
|
+
# The argument n specifies the length of the random length.
|
137
|
+
# The length of the result string is about 4/3 of n.
|
138
|
+
#
|
139
|
+
# If n is not specified, 16 is assumed.
|
140
|
+
# It may be larger in future.
|
141
|
+
#
|
142
|
+
# If secure random number generator is not available,
|
143
|
+
# NotImplementedError is raised.
|
144
|
+
def self.base64(n=nil)
|
145
|
+
[random_bytes(n)].pack("m*").delete("\n")
|
146
|
+
end
|
147
|
+
|
148
|
+
# SecureRandom.random_number generates a random number.
|
149
|
+
#
|
150
|
+
# If an positive integer is given as n,
|
151
|
+
# SecureRandom.random_number returns an integer:
|
152
|
+
# 0 <= SecureRandom.random_number(n) < n.
|
153
|
+
#
|
154
|
+
# If 0 is given or an argument is not given,
|
155
|
+
# SecureRandom.random_number returns an float:
|
156
|
+
# 0.0 <= SecureRandom.random_number() < 1.0.
|
157
|
+
def self.random_number(n=0)
|
158
|
+
if 0 < n
|
159
|
+
hex = n.to_s(16)
|
160
|
+
hex = '0' + hex if (hex.length & 1) == 1
|
161
|
+
bin = [hex].pack("H*")
|
162
|
+
mask = bin[0].ord
|
163
|
+
mask |= mask >> 1
|
164
|
+
mask |= mask >> 2
|
165
|
+
mask |= mask >> 4
|
166
|
+
begin
|
167
|
+
rnd = SecureRandom.random_bytes(bin.length)
|
168
|
+
rnd[0] = (rnd[0].ord & mask).chr
|
169
|
+
end until rnd < bin
|
170
|
+
rnd.unpack("H*")[0].hex
|
171
|
+
else
|
172
|
+
# assumption: Float::MANT_DIG <= 64
|
173
|
+
i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
|
174
|
+
Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Following code is based on David Garamond's GUID library for Ruby.
|
179
|
+
def self.lastWin32ErrorMessage # :nodoc:
|
180
|
+
get_last_error = Win32API.new(
|
181
|
+
"kernel32", "GetLastError", '', 'L'
|
182
|
+
)
|
183
|
+
format_message = Win32API.new(
|
184
|
+
"kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L'
|
185
|
+
)
|
186
|
+
format_message_ignore_inserts = 0x00000200
|
187
|
+
format_message_from_system = 0x00001000
|
188
|
+
|
189
|
+
code = get_last_error.call
|
190
|
+
msg = "\0" * 1024
|
191
|
+
len = format_message.call(
|
192
|
+
format_message_ignore_inserts + format_message_from_system,
|
193
|
+
0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil
|
194
|
+
)
|
195
|
+
msg[0, len].tr("\r", '').chomp
|
196
|
+
end
|
197
|
+
end
|
data/lib/uuidtools.rb
CHANGED
@@ -31,6 +31,12 @@ require 'digest/md5'
|
|
31
31
|
|
32
32
|
require 'uuidtools/version'
|
33
33
|
|
34
|
+
begin
|
35
|
+
require 'securerandom'
|
36
|
+
rescue LoadError
|
37
|
+
require File.join(File.dirname(__FILE__), 'compat', 'securerandom')
|
38
|
+
end
|
39
|
+
|
34
40
|
#= uuidtools.rb
|
35
41
|
#
|
36
42
|
# UUIDTools was designed to be a simple library for generating any
|
@@ -47,6 +53,8 @@ require 'uuidtools/version'
|
|
47
53
|
# UUID.random_create
|
48
54
|
# => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>
|
49
55
|
class UUID
|
56
|
+
include Comparable
|
57
|
+
|
50
58
|
@@last_timestamp = nil
|
51
59
|
@@last_node_id = nil
|
52
60
|
@@last_clock_sequence = nil
|
@@ -78,9 +86,9 @@ class UUID
|
|
78
86
|
"Expected unsigned 8-bit number for clock_seq_low, " +
|
79
87
|
"got #{clock_seq_low}."
|
80
88
|
end
|
81
|
-
unless nodes.
|
82
|
-
raise
|
83
|
-
"Expected
|
89
|
+
unless nodes.kind_of?(Enumerable)
|
90
|
+
raise TypeError,
|
91
|
+
"Expected Enumerable, got #{nodes.class.name}."
|
84
92
|
end
|
85
93
|
unless nodes.size == 6
|
86
94
|
raise ArgumentError,
|
@@ -111,7 +119,7 @@ class UUID
|
|
111
119
|
# Parses a UUID from a string.
|
112
120
|
def self.parse(uuid_string)
|
113
121
|
unless uuid_string.kind_of? String
|
114
|
-
raise
|
122
|
+
raise TypeError,
|
115
123
|
"Expected String, got #{uuid_string.class.name} instead."
|
116
124
|
end
|
117
125
|
uuid_components = uuid_string.downcase.scan(
|
@@ -134,7 +142,7 @@ class UUID
|
|
134
142
|
# Parses a UUID from a raw byte string.
|
135
143
|
def self.parse_raw(raw_string)
|
136
144
|
unless raw_string.kind_of? String
|
137
|
-
raise
|
145
|
+
raise TypeError,
|
138
146
|
"Expected String, got #{raw_string.class.name} instead."
|
139
147
|
end
|
140
148
|
integer = self.convert_byte_string_to_int(raw_string)
|
@@ -154,7 +162,7 @@ class UUID
|
|
154
162
|
|
155
163
|
# Creates a UUID from a random value.
|
156
164
|
def self.random_create()
|
157
|
-
new_uuid = self.parse_raw(
|
165
|
+
new_uuid = self.parse_raw(SecureRandom.random_bytes(16))
|
158
166
|
new_uuid.time_hi_and_version &= 0x0FFF
|
159
167
|
new_uuid.time_hi_and_version |= (4 << 12)
|
160
168
|
new_uuid.clock_seq_hi_and_reserved &= 0x3F
|
@@ -183,14 +191,9 @@ class UUID
|
|
183
191
|
octet.to_i(16)
|
184
192
|
end
|
185
193
|
else
|
186
|
-
nodes =
|
187
|
-
|
188
|
-
|
189
|
-
chr.ord
|
190
|
-
else
|
191
|
-
# Ruby 1.8
|
192
|
-
chr.sum(8)
|
193
|
-
end
|
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)
|
194
197
|
end
|
195
198
|
nodes[0] |= 0b00000001
|
196
199
|
end
|
@@ -199,11 +202,15 @@ class UUID
|
|
199
202
|
end
|
200
203
|
clock_sequence = @@last_clock_sequence
|
201
204
|
if clock_sequence.nil?
|
202
|
-
clock_sequence = self.convert_byte_string_to_int(
|
205
|
+
clock_sequence = self.convert_byte_string_to_int(
|
206
|
+
SecureRandom.random_bytes(16)
|
207
|
+
)
|
203
208
|
end
|
204
209
|
if @@last_node_id != nil && @@last_node_id != node_id
|
205
210
|
# The node id has changed. Change the clock id.
|
206
|
-
clock_sequence = self.convert_byte_string_to_int(
|
211
|
+
clock_sequence = self.convert_byte_string_to_int(
|
212
|
+
SecureRandom.random_bytes(16)
|
213
|
+
)
|
207
214
|
elsif @@last_timestamp != nil &&
|
208
215
|
gmt_timestamp_100_nanoseconds <= @@last_timestamp
|
209
216
|
clock_sequence = clock_sequence + 1
|
@@ -353,7 +360,7 @@ class UUID
|
|
353
360
|
|
354
361
|
# Returns the hex digest of the UUID object.
|
355
362
|
def hexdigest
|
356
|
-
return self.to_i.to_s(16)
|
363
|
+
return self.to_i.to_s(16).rjust(32, "0")
|
357
364
|
end
|
358
365
|
|
359
366
|
# Returns the raw bytes that represent this UUID.
|
@@ -394,7 +401,7 @@ class UUID
|
|
394
401
|
|
395
402
|
# Returns true if this UUID is exactly equal to the other UUID.
|
396
403
|
def eql?(other)
|
397
|
-
return
|
404
|
+
return self == other
|
398
405
|
end
|
399
406
|
|
400
407
|
# Returns the MAC address of the current computer's network card.
|
@@ -406,7 +413,7 @@ class UUID
|
|
406
413
|
if os_platform =~ /win/ && !(os_platform =~ /darwin/)
|
407
414
|
script_in_path = true
|
408
415
|
else
|
409
|
-
script_in_path =
|
416
|
+
script_in_path = Kernel.system("which ifconfig 2>&1 > /dev/null")
|
410
417
|
end
|
411
418
|
if os_platform =~ /solaris/
|
412
419
|
begin
|
@@ -526,7 +533,9 @@ class UUID
|
|
526
533
|
@@mac_address = new_mac_address
|
527
534
|
end
|
528
535
|
|
529
|
-
|
536
|
+
# The following methods are not part of the public API,
|
537
|
+
# and generally should not be called directly.
|
538
|
+
|
530
539
|
# Creates a new UUID from a SHA1 or MD5 hash
|
531
540
|
def self.create_from_hash(hash_class, namespace, name) #:nodoc:
|
532
541
|
if hash_class == Digest::MD5
|
@@ -551,29 +560,6 @@ protected
|
|
551
560
|
return new_uuid
|
552
561
|
end
|
553
562
|
|
554
|
-
# N bits of unpredictable data.
|
555
|
-
def self.random_bits(size=128) #:nodoc:
|
556
|
-
if 128 % 16 != 0
|
557
|
-
raise ArgumentError, "Value must be divisible by 16."
|
558
|
-
end
|
559
|
-
if !defined?(@random_device) || @random_device == nil
|
560
|
-
begin
|
561
|
-
@random_device = nil
|
562
|
-
if File.exists? "/dev/urandom"
|
563
|
-
@random_device = File.open "/dev/urandom", "r"
|
564
|
-
elsif File.exists? "/dev/random"
|
565
|
-
@random_device = File.open "/dev/random", "r"
|
566
|
-
end
|
567
|
-
rescue Exception
|
568
|
-
end
|
569
|
-
end
|
570
|
-
begin
|
571
|
-
return @random_device.read(size / 8) if @random_device != nil
|
572
|
-
rescue Exception
|
573
|
-
end
|
574
|
-
return (1..(size / 16)).to_a.map { rand(0x10000) }.pack("n#{size / 16}")
|
575
|
-
end
|
576
|
-
|
577
563
|
def self.convert_int_to_byte_string(integer, size) #:nodoc:
|
578
564
|
byte_string = ""
|
579
565
|
for i in 0..(size - 1)
|
@@ -586,13 +572,9 @@ protected
|
|
586
572
|
integer = 0
|
587
573
|
size = byte_string.size
|
588
574
|
for i in 0..(size - 1)
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
else
|
593
|
-
# Ruby 1.8
|
594
|
-
integer += (byte_string[i] << (((size - 1) - i) * 8))
|
595
|
-
end
|
575
|
+
ordinal = (byte_string[i].respond_to?(:ord) ?
|
576
|
+
byte_string[i].ord : byte_string[i])
|
577
|
+
integer += (ordinal << (((size - 1) - i) * 8))
|
596
578
|
end
|
597
579
|
return integer
|
598
580
|
end
|
@@ -602,3 +584,9 @@ UUID_DNS_NAMESPACE = UUID.parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
|
602
584
|
UUID_URL_NAMESPACE = UUID.parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
603
585
|
UUID_OID_NAMESPACE = UUID.parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
604
586
|
UUID_X500_NAMESPACE = UUID.parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
587
|
+
|
588
|
+
at_exit do
|
589
|
+
if UUID.instance_variable_get("@random_device") != nil
|
590
|
+
UUID.instance_variable_get("@random_device").close rescue nil
|
591
|
+
end
|
592
|
+
end
|
data/lib/uuidtools/version.rb
CHANGED
@@ -21,12 +21,15 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
-
class
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
# Used to prevent the class/module from being loaded more than once
|
25
|
+
unless defined? UUID::VERSION
|
26
|
+
class UUID
|
27
|
+
module VERSION #:nodoc:
|
28
|
+
MAJOR = 1
|
29
|
+
MINOR = 0
|
30
|
+
TINY = 5
|
29
31
|
|
30
|
-
|
32
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
33
|
+
end
|
31
34
|
end
|
32
35
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
2
|
+
|
3
|
+
describe UUID, "when using utility methods" do
|
4
|
+
it "should correctly obtain random bits" do
|
5
|
+
bits = []
|
6
|
+
1000.times do
|
7
|
+
bits << SecureRandom.random_bytes(16)
|
8
|
+
end
|
9
|
+
# Check to make sure that none of the 10,000 strings were duplicates
|
10
|
+
(bits.map {|x| x.to_s}).uniq.size.should == bits.size
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the correct number of random bits" do
|
14
|
+
SecureRandom.random_bytes(16).size.should == 16
|
15
|
+
SecureRandom.random_bytes(6).size.should == 6
|
16
|
+
end
|
17
|
+
end
|
@@ -14,6 +14,7 @@ describe UUID, "when generating" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should correctly generate timestamp variant UUIDs" do
|
17
|
+
UUID.timestamp_create.should_not be_random_node_id
|
17
18
|
UUID.timestamp_create.to_s.should_not == UUID.timestamp_create.to_s
|
18
19
|
current_time = Time.now
|
19
20
|
UUID.timestamp_create(current_time).to_s.should_not ==
|
@@ -22,16 +23,98 @@ describe UUID, "when generating" do
|
|
22
23
|
1000.times do
|
23
24
|
uuids << UUID.timestamp_create
|
24
25
|
end
|
25
|
-
# Check to make sure that none of the
|
26
|
+
# Check to make sure that none of the 1,000 UUIDs were duplicates
|
26
27
|
(uuids.map {|x| x.to_s}).uniq.size.should == uuids.size
|
27
28
|
end
|
28
29
|
|
30
|
+
it "should correctly generate UUIDs without a MAC address" do
|
31
|
+
mac_address = UUID.mac_address
|
32
|
+
UUID.mac_address = nil
|
33
|
+
UUID.timestamp_create.should be_random_node_id
|
34
|
+
UUID.mac_address = mac_address
|
35
|
+
end
|
36
|
+
|
29
37
|
it "should correctly generate random number variant UUIDs" do
|
30
38
|
uuids = []
|
31
39
|
1000.times do
|
32
40
|
uuids << UUID.random_create
|
33
41
|
end
|
34
|
-
# Check to make sure that none of the
|
42
|
+
# Check to make sure that none of the 1,000 UUIDs were duplicates
|
35
43
|
(uuids.map {|x| x.to_s}).uniq.size.should == uuids.size
|
36
44
|
end
|
45
|
+
|
46
|
+
it "should throw an exception if a segment has an invalid value" do
|
47
|
+
(lambda do
|
48
|
+
UUID.new(-1, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
49
|
+
end).should raise_error(ArgumentError)
|
50
|
+
(lambda do
|
51
|
+
UUID.new(4294967296, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
52
|
+
end).should raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should throw an exception if a segment has an invalid value" do
|
56
|
+
(lambda do
|
57
|
+
UUID.new(0, -1, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
58
|
+
end).should raise_error(ArgumentError)
|
59
|
+
(lambda do
|
60
|
+
UUID.new(0, 65536, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
61
|
+
end).should raise_error(ArgumentError)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should throw an exception if a segment has an invalid value" do
|
65
|
+
(lambda do
|
66
|
+
UUID.new(0, 0, -1, 0, 0, [0, 0, 0, 0, 0, 0])
|
67
|
+
end).should raise_error(ArgumentError)
|
68
|
+
(lambda do
|
69
|
+
UUID.new(0, 0, 65536, 0, 0, [0, 0, 0, 0, 0, 0])
|
70
|
+
end).should raise_error(ArgumentError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should throw an exception if a segment has an invalid value" do
|
74
|
+
(lambda do
|
75
|
+
UUID.new(0, 0, 0, -1, 0, [0, 0, 0, 0, 0, 0])
|
76
|
+
end).should raise_error(ArgumentError)
|
77
|
+
(lambda do
|
78
|
+
UUID.new(0, 0, 0, 256, 0, [0, 0, 0, 0, 0, 0])
|
79
|
+
end).should raise_error(ArgumentError)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should throw an exception if a segment has an invalid value" do
|
83
|
+
(lambda do
|
84
|
+
UUID.new(0, 0, 0, 0, -1, [0, 0, 0, 0, 0, 0])
|
85
|
+
end).should raise_error(ArgumentError)
|
86
|
+
(lambda do
|
87
|
+
UUID.new(0, 0, 0, 0, 256, [0, 0, 0, 0, 0, 0])
|
88
|
+
end).should raise_error(ArgumentError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should throw an exception if nodes are not a collection" do
|
92
|
+
(lambda do
|
93
|
+
UUID.new(0, 0, 0, 0, 0, :bogus)
|
94
|
+
end).should raise_error(TypeError)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should throw an exception if nodes are the wrong size" do
|
98
|
+
(lambda do
|
99
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0])
|
100
|
+
end).should raise_error(ArgumentError)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should throw an exception if any nodes have invalid values" do
|
104
|
+
(lambda do
|
105
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 256])
|
106
|
+
end).should raise_error(ArgumentError)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should throw an exception if parsing anything but a String" do
|
110
|
+
(lambda do
|
111
|
+
UUID.parse(:bogus)
|
112
|
+
end).should raise_error(TypeError)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should throw an exception if raw parsing anything but a String" do
|
116
|
+
(lambda do
|
117
|
+
UUID.parse_raw(:bogus)
|
118
|
+
end).should raise_error(TypeError)
|
119
|
+
end
|
37
120
|
end
|
@@ -33,4 +33,74 @@ describe UUID, "when parsing" do
|
|
33
33
|
UUID.timestamp_create.should be_random_node_id
|
34
34
|
UUID.mac_address = old_mac_address
|
35
35
|
end
|
36
|
+
|
37
|
+
it "should correctly identify the nil UUID" do
|
38
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should be_nil_uuid
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should correctly identify timestamp version UUIDs as valid" do
|
42
|
+
UUID.timestamp_create.should be_valid
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should correctly identify random number version UUIDs as valid" do
|
46
|
+
UUID.random_create.should be_valid
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should correctly identify SHA1 hash version UUIDs as valid" do
|
50
|
+
UUID.sha1_create(
|
51
|
+
UUID_URL_NAMESPACE, 'http://sporkmonger.com'
|
52
|
+
).should be_valid
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should correctly identify MD5 hash version UUIDs as valid" do
|
56
|
+
UUID.md5_create(
|
57
|
+
UUID_URL_NAMESPACE, 'http://sporkmonger.com'
|
58
|
+
).should be_valid
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not identify the nil UUID as valid" do
|
62
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should_not be_valid
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should allow for sorting of UUID arrays" do
|
66
|
+
uuids = []
|
67
|
+
1000.times do
|
68
|
+
uuids << UUID.timestamp_create
|
69
|
+
end
|
70
|
+
uuids.sort!
|
71
|
+
uuids.first.should < uuids.last
|
72
|
+
uuids.last.should > uuids.first
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should allow for comparison of UUIDs" do
|
76
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should <
|
77
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 1])
|
78
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 1]).should >
|
79
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
80
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should ==
|
81
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should produce the correct hexdigest for a UUID" do
|
85
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).hexdigest.should ==
|
86
|
+
"00000000000000000000000000000000"
|
87
|
+
UUID.new(1, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).hexdigest.should ==
|
88
|
+
"00000001000000000000000000000000"
|
89
|
+
UUID.timestamp_create.hexdigest.size.should == 32
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should produce a sane hash value for a UUID" do
|
93
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).hash.should == 0
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should produce the correct URI for a UUID" do
|
97
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).to_uri.should ==
|
98
|
+
"urn:uuid:00000000-0000-0000-0000-000000000000"
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should correctly test UUID equality" do
|
102
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0]).should be_eql(
|
103
|
+
UUID.new(0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0])
|
104
|
+
)
|
105
|
+
end
|
36
106
|
end
|
data/tasks/gem.rake
CHANGED
@@ -2,6 +2,11 @@ require "rake/gempackagetask"
|
|
2
2
|
|
3
3
|
namespace :gem do
|
4
4
|
GEM_SPEC = Gem::Specification.new do |s|
|
5
|
+
unless s.respond_to?(:add_development_dependency)
|
6
|
+
puts "The gem spec requires a newer version of RubyGems."
|
7
|
+
exit(1)
|
8
|
+
end
|
9
|
+
|
5
10
|
s.name = PKG_NAME
|
6
11
|
s.version = PKG_VERSION
|
7
12
|
s.summary = PKG_SUMMARY
|
@@ -13,8 +18,9 @@ namespace :gem do
|
|
13
18
|
s.extra_rdoc_files = %w( README )
|
14
19
|
s.rdoc_options.concat ["--main", "README"]
|
15
20
|
|
16
|
-
s.
|
17
|
-
s.
|
21
|
+
s.add_development_dependency("rake", ">= 0.8.3")
|
22
|
+
s.add_development_dependency("rspec", ">= 1.1.11")
|
23
|
+
s.add_development_dependency("launchy", ">= 0.3.2")
|
18
24
|
|
19
25
|
s.require_path = "lib"
|
20
26
|
|
data/tasks/rubyforge.rake
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require 'rubyforge'
|
2
|
-
require 'rake/contrib/sshpublisher'
|
3
|
-
|
4
1
|
namespace :gem do
|
5
2
|
desc 'Package and upload to RubyForge'
|
6
3
|
task :release => ["gem:package"] do |t|
|
4
|
+
require 'rubyforge'
|
5
|
+
|
7
6
|
v = ENV['VERSION'] or abort 'Must supply VERSION=x.y.z'
|
8
7
|
abort "Versions don't match #{v} vs #{PROJ.version}" if v != PKG_VERSION
|
9
8
|
pkg = "pkg/#{GEM_SPEC.full_name}"
|
@@ -28,6 +27,9 @@ end
|
|
28
27
|
namespace :doc do
|
29
28
|
desc "Publish RDoc to RubyForge"
|
30
29
|
task :release => ["doc:rdoc"] do
|
30
|
+
require "rake/contrib/sshpublisher"
|
31
|
+
require "yaml"
|
32
|
+
|
31
33
|
config = YAML.load(
|
32
34
|
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
33
35
|
)
|
@@ -41,6 +43,9 @@ end
|
|
41
43
|
namespace :spec do
|
42
44
|
desc "Publish specdoc to RubyForge"
|
43
45
|
task :release => ["spec:specdoc"] do
|
46
|
+
require "rake/contrib/sshpublisher"
|
47
|
+
require "yaml"
|
48
|
+
|
44
49
|
config = YAML.load(
|
45
50
|
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
46
51
|
)
|
@@ -53,6 +58,9 @@ namespace :spec do
|
|
53
58
|
namespace :rcov do
|
54
59
|
desc "Publish coverage report to RubyForge"
|
55
60
|
task :release => ["spec:rcov"] do
|
61
|
+
require "rake/contrib/sshpublisher"
|
62
|
+
require "yaml"
|
63
|
+
|
56
64
|
config = YAML.load(
|
57
65
|
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
58
66
|
)
|
@@ -67,6 +75,9 @@ end
|
|
67
75
|
namespace :website do
|
68
76
|
desc "Publish website to RubyForge"
|
69
77
|
task :release => ["doc:release", "spec:release", "spec:rcov:release"] do
|
78
|
+
require "rake/contrib/sshpublisher"
|
79
|
+
require "yaml"
|
80
|
+
|
70
81
|
config = YAML.load(
|
71
82
|
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
72
83
|
)
|
data/tasks/spec.rake
CHANGED
@@ -4,20 +4,33 @@ namespace :spec do
|
|
4
4
|
Spec::Rake::SpecTask.new(:rcov) do |t|
|
5
5
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
6
6
|
t.spec_opts = ['--color', '--format', 'specdoc']
|
7
|
-
|
7
|
+
if RCOV_ENABLED
|
8
|
+
t.rcov = true
|
9
|
+
else
|
10
|
+
t.rcov = false
|
11
|
+
end
|
8
12
|
t.rcov_opts = [
|
9
13
|
'--exclude', 'spec',
|
10
14
|
'--exclude', '1\\.8\\/gems',
|
11
|
-
'--exclude', '1\\.9\\/gems'
|
15
|
+
'--exclude', '1\\.9\\/gems',
|
16
|
+
'--exclude', 'addressable\\/idna\\.rb', # unicode tables too big
|
12
17
|
]
|
13
18
|
end
|
14
19
|
|
15
|
-
|
16
|
-
t.
|
17
|
-
t.
|
20
|
+
Spec::Rake::SpecTask.new(:normal) do |t|
|
21
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
22
|
+
t.spec_opts = ['--color', '--format', 'specdoc']
|
23
|
+
t.rcov = false
|
18
24
|
end
|
19
25
|
|
20
|
-
|
26
|
+
if RCOV_ENABLED
|
27
|
+
RCov::VerifyTask.new(:verify) do |t|
|
28
|
+
t.threshold = 100.0
|
29
|
+
t.index_html = 'coverage/index.html'
|
30
|
+
end
|
31
|
+
|
32
|
+
task :verify => :rcov
|
33
|
+
end
|
21
34
|
|
22
35
|
desc "Generate HTML Specdocs for all specs"
|
23
36
|
Spec::Rake::SpecTask.new(:specdoc) do |t|
|
@@ -34,56 +47,18 @@ namespace :spec do
|
|
34
47
|
namespace :rcov do
|
35
48
|
desc "Browse the code coverage report."
|
36
49
|
task :browse => "spec:rcov" do
|
37
|
-
|
50
|
+
require "launchy"
|
51
|
+
Launchy::Browser.run("coverage/index.html")
|
38
52
|
end
|
39
53
|
end
|
40
54
|
end
|
41
55
|
|
42
|
-
|
43
|
-
|
56
|
+
if RCOV_ENABLED
|
57
|
+
desc "Alias to spec:verify"
|
58
|
+
task "spec" => "spec:verify"
|
59
|
+
else
|
60
|
+
desc "Alias to spec:normal"
|
61
|
+
task "spec" => "spec:normal"
|
62
|
+
end
|
44
63
|
|
45
64
|
task "clobber" => ["spec:clobber_rcov"]
|
46
|
-
|
47
|
-
module Rake
|
48
|
-
def self.browse(filepath)
|
49
|
-
if RUBY_PLATFORM =~ /mswin/
|
50
|
-
system(filepath)
|
51
|
-
else
|
52
|
-
try_browsers = lambda do
|
53
|
-
result = true
|
54
|
-
if !(`which firefox 2>&1` =~ /no firefox/)
|
55
|
-
system("firefox #{filepath}")
|
56
|
-
elsif !(`which mozilla 2>&1` =~ /no mozilla/)
|
57
|
-
system("mozilla #{filepath}")
|
58
|
-
elsif !(`which netscape 2>&1` =~ /no netscape/)
|
59
|
-
system("netscape #{filepath}")
|
60
|
-
elsif !(`which links 2>&1` =~ /no links/)
|
61
|
-
system("links #{filepath}")
|
62
|
-
elsif !(`which lynx 2>&1` =~ /no lynx/)
|
63
|
-
system("lynx #{filepath}")
|
64
|
-
else
|
65
|
-
result = false
|
66
|
-
end
|
67
|
-
result
|
68
|
-
end
|
69
|
-
opened = false
|
70
|
-
if RUBY_PLATFORM =~ /darwin/
|
71
|
-
opened = true
|
72
|
-
system("open #{filepath}")
|
73
|
-
elsif !(`which gnome-open 2>&1` =~ /no gnome-open/)
|
74
|
-
success =
|
75
|
-
!(`gnome-open #{filepath} 2>&1` =~ /There is no default action/)
|
76
|
-
if !success
|
77
|
-
opened = try_browsers.call()
|
78
|
-
else
|
79
|
-
opened = true
|
80
|
-
end
|
81
|
-
else
|
82
|
-
opened = try_browsers.call()
|
83
|
-
end
|
84
|
-
if !opened
|
85
|
-
puts "Don't know how to browse to location."
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uuidtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Aman
|
@@ -9,28 +9,38 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-01 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
17
|
-
type: :
|
17
|
+
type: :development
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 0.8.3
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
type: :
|
27
|
+
type: :development
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: 1.1.11
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: launchy
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.3.2
|
34
44
|
version:
|
35
45
|
description: A simple universally unique ID generation library.
|
36
46
|
email: bob@sporkmonger.com
|
@@ -41,6 +51,8 @@ extensions: []
|
|
41
51
|
extra_rdoc_files:
|
42
52
|
- README
|
43
53
|
files:
|
54
|
+
- lib/compat
|
55
|
+
- lib/compat/securerandom.rb
|
44
56
|
- lib/uuidtools
|
45
57
|
- lib/uuidtools/version.rb
|
46
58
|
- lib/uuidtools.rb
|
@@ -48,6 +60,7 @@ files:
|
|
48
60
|
- spec/spec_helper.rb
|
49
61
|
- spec/uuidtools
|
50
62
|
- spec/uuidtools/mac_address_spec.rb
|
63
|
+
- spec/uuidtools/utility_spec.rb
|
51
64
|
- spec/uuidtools/uuid_creation_spec.rb
|
52
65
|
- spec/uuidtools/uuid_parsing_spec.rb
|
53
66
|
- tasks/benchmark.rake
|
@@ -86,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
99
|
requirements: []
|
87
100
|
|
88
101
|
rubyforge_project: uuidtools
|
89
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.3.1
|
90
103
|
signing_key:
|
91
104
|
specification_version: 2
|
92
105
|
summary: UUID generator
|