gabe-uuid 0.3.1 → 0.3.2
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/Rakefile +2 -2
- data/lib/uuid.rb +45 -38
- data/spec/uuid_spec.rb +45 -11
- metadata +2 -2
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
spec = Gem::Specification.new do |s|
|
13
13
|
s.name = 'uuid'
|
14
|
-
s.version = '0.3.
|
14
|
+
s.version = '0.3.2'
|
15
15
|
s.platform = Gem::Platform::RUBY
|
16
16
|
s.author = 'Gabriel Boyer'
|
17
17
|
s.email = 'gboyer@gmail.com'
|
@@ -22,7 +22,7 @@ spec = Gem::Specification.new do |s|
|
|
22
22
|
s.files = %w[ LICENSE README.markdown Rakefile
|
23
23
|
spec/spec_helper.rb spec/uuid_spec.rb
|
24
24
|
lib/uuid.rb lib/compat/securerandom.rb ]
|
25
|
-
s.required_ruby_version = "
|
25
|
+
s.required_ruby_version = "~> 1.8.6"
|
26
26
|
end
|
27
27
|
|
28
28
|
Rake::GemPackageTask.new(spec) do |package|
|
data/lib/uuid.rb
CHANGED
@@ -5,6 +5,8 @@ rescue LoadError
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class UUID
|
8
|
+
VERSION = '0.3.2'
|
9
|
+
|
8
10
|
def initialize(value)
|
9
11
|
@value = Integer(value)
|
10
12
|
unless (@value >= 0) && (@value < (1 << 128))
|
@@ -16,11 +18,17 @@ class UUID
|
|
16
18
|
eql?(other)
|
17
19
|
end
|
18
20
|
|
21
|
+
def bytes
|
22
|
+
bs = ''
|
23
|
+
(0..120).step(8) { |shift| bs << ((@value >> (120 - shift)) & 0xff) }
|
24
|
+
bs
|
25
|
+
end
|
26
|
+
|
19
27
|
def clock_seq
|
20
|
-
((
|
28
|
+
((clock_seq_and_reserved & 0x3f) << 8) | clock_seq_low
|
21
29
|
end
|
22
30
|
|
23
|
-
def
|
31
|
+
def clock_seq_and_reserved
|
24
32
|
(to_i >> 56) & 0xff
|
25
33
|
end
|
26
34
|
|
@@ -44,15 +52,19 @@ class UUID
|
|
44
52
|
to_s
|
45
53
|
end
|
46
54
|
|
55
|
+
def nil_uuid?
|
56
|
+
to_i == 0
|
57
|
+
end
|
58
|
+
|
47
59
|
def node
|
48
60
|
to_i & 0xffffffffffff
|
49
61
|
end
|
50
62
|
|
51
63
|
def time
|
52
|
-
((
|
64
|
+
((time_hi_and_version & 0x0fff) << 48) | (time_mid << 32) | time_low
|
53
65
|
end
|
54
66
|
|
55
|
-
def
|
67
|
+
def time_hi_and_version
|
56
68
|
(to_i >> 64) & 0xffff
|
57
69
|
end
|
58
70
|
|
@@ -77,51 +89,46 @@ class UUID
|
|
77
89
|
"urn:uuid:#{self}"
|
78
90
|
end
|
79
91
|
|
80
|
-
RESERVED_NCS
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
'reserved for future definition'
|
85
|
-
]
|
92
|
+
RESERVED_NCS = 0b000 # Reserved for NCS compatibility
|
93
|
+
RFC_4122 = 0b100 # Specified in RFC 4122
|
94
|
+
RESERVED_MICROSOFT = 0b110 # Reserved for Microsoft compatibility
|
95
|
+
RESERVED_FUTURE = 0b111 # Reserved for future definition
|
86
96
|
|
87
97
|
def variant
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
when to_i & (0x2000 << 48)
|
94
|
-
RESERVED_MICROSOFT
|
98
|
+
raw_variant = (clock_seq_and_reserved >> 5)
|
99
|
+
if (raw_variant >> 2) == 0
|
100
|
+
0x000
|
101
|
+
elsif (raw_variant >> 1) == 2
|
102
|
+
0x100
|
95
103
|
else
|
96
|
-
|
97
|
-
end
|
104
|
+
raw_variant
|
105
|
+
end >> 6
|
98
106
|
end
|
99
107
|
|
100
108
|
def version
|
101
109
|
(variant == RFC_4122) ? ((to_i >> 76) & 0xf) : nil
|
102
110
|
end
|
103
111
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
unless str =~ /^(urn:uuid:)?[0-9a-fA-F]{8}((-)?[0-9a-fA-F]{4}){3}(-)?[0-9a-fA-F]{12}$/
|
108
|
-
raise ArgumentError, "#{str} is not a recognized UUID representation"
|
109
|
-
end
|
110
|
-
new bytes_to_i(str.gsub(/(^urn:uuid:|-)/, '').downcase.unpack('a2' * 16).collect { |x| x.to_i(16) }.pack('C*'))
|
112
|
+
def self.new_from_bytes(bytes)
|
113
|
+
unless bytes.length == 16
|
114
|
+
raise ArgumentError, "#{bytes} must have length of 16"
|
111
115
|
end
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def bytes_to_i(bytes)
|
123
|
-
bytes.unpack('C*').inject { |value, i| value * 256 | i }
|
116
|
+
new bytes.unpack('C*').inject { |value, i| value * 256 | i }
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.parse(uuid)
|
120
|
+
str = uuid.to_s
|
121
|
+
unless str =~ /^(urn:uuid:)?[0-9a-fA-F]{8}((-)?[0-9a-fA-F]{4}){3}(-)?[0-9a-fA-F]{12}$/
|
122
|
+
raise ArgumentError, "#{str} is not a recognized UUID representation"
|
124
123
|
end
|
124
|
+
new_from_bytes (str.gsub(/(^urn:uuid:|-)/, '').downcase.unpack('a2' * 16).collect { |x| x.to_i(16) }.pack('C*'))
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.uuid4
|
128
|
+
bytes = SecureRandom.random_bytes(16)
|
129
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40
|
130
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80
|
131
|
+
new_from_bytes bytes
|
125
132
|
end
|
126
133
|
end
|
127
134
|
|
data/spec/uuid_spec.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
describe UUID, '.
|
4
|
-
it '
|
5
|
-
UUID.
|
6
|
-
UUID.uuid4.should_not == UUID.uuid4
|
3
|
+
describe UUID, '.new_from_bytes' do
|
4
|
+
it 'creates a UUID from a 16-byte string' do
|
5
|
+
lambda { UUID.new_from_bytes('x' * 16) }.should_not raise_error
|
7
6
|
end
|
8
7
|
|
9
|
-
it '
|
10
|
-
UUID.
|
11
|
-
UUID.
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'generates UUIDs of the RFC 4122 variant' do
|
15
|
-
UUID.uuid4.variant.should == UUID::RFC_4122
|
8
|
+
it 'raises an ArgumentError when not passed 16 bytes' do
|
9
|
+
lambda { UUID.new_from_bytes('x' * 15) }.should raise_error(ArgumentError)
|
10
|
+
lambda { UUID.new_from_bytes('x' * 17) }.should raise_error(ArgumentError)
|
16
11
|
end
|
17
12
|
end
|
18
13
|
|
@@ -30,6 +25,22 @@ describe UUID, '.parse' do
|
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
28
|
+
describe UUID, '.uuid4' do
|
29
|
+
it 'generates a new UUID' do
|
30
|
+
UUID.uuid4.should be_a_kind_of(UUID)
|
31
|
+
UUID.uuid4.should_not == UUID.uuid4
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'generates version 4 UUIDs' do
|
35
|
+
UUID.uuid4.to_s.should =~ /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
|
36
|
+
UUID.uuid4.version.should == 4
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'generates UUIDs of the RFC 4122 variant' do
|
40
|
+
UUID.uuid4.variant.should == UUID::RFC_4122
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
33
44
|
describe UUID, '#initialize' do
|
34
45
|
it 'creates a UUID from an Integer when passed one that is within range for a UUID' do
|
35
46
|
id = UUID.uuid4
|
@@ -47,6 +58,29 @@ describe UUID, '#initialize' do
|
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
61
|
+
describe UUID, '#bytes' do
|
62
|
+
it 'returns a 16-byte representation of the UUID' do
|
63
|
+
UUID.uuid4.bytes.length.should == 16
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can be used to reconstruct a UUID, in conjunction with UUID.new_from_bytes' do
|
67
|
+
id = UUID.uuid4
|
68
|
+
UUID.new_from_bytes(id.bytes).should == id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe UUID, '#nil_uuid?' do
|
73
|
+
it 'returns true for the nil (0, UUID::Nil) UUID' do
|
74
|
+
UUID.new(0).should be_nil_uuid
|
75
|
+
UUID::Nil.should be_nil_uuid
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns false for non-nil UUIDs' do
|
79
|
+
UUID.parse('2f2b66f0-90ca-11dd-a935-000ea6f788fa').should_not be_nil_uuid
|
80
|
+
UUID.uuid4.should_not be_nil_uuid
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
50
84
|
describe UUID, '#to_i' do
|
51
85
|
it 'returns an unsigned integer representation of the UUID' do
|
52
86
|
i = UUID.uuid4.to_i
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gabe-uuid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriel Boyer
|
@@ -38,7 +38,7 @@ require_paths:
|
|
38
38
|
- lib
|
39
39
|
required_ruby_version: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 1.8.6
|
44
44
|
version:
|