uuidtools 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|