gabe-uuid 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/Rakefile +2 -2
  2. data/lib/uuid.rb +45 -38
  3. data/spec/uuid_spec.rb +45 -11
  4. 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.1'
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 = ">= 1.8.6"
25
+ s.required_ruby_version = "~> 1.8.6"
26
26
  end
27
27
 
28
28
  Rake::GemPackageTask.new(spec) do |package|
@@ -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
- ((clock_seq_hi_variant & 0x3f) << 8) | clock_seq_low
28
+ ((clock_seq_and_reserved & 0x3f) << 8) | clock_seq_low
21
29
  end
22
30
 
23
- def clock_seq_hi_variant
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
- ((time_hi_version & 0x0fff) << 48) | (time_mid << 32) | time_low
64
+ ((time_hi_and_version & 0x0fff) << 48) | (time_mid << 32) | time_low
53
65
  end
54
66
 
55
- def time_hi_version
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, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
81
- 'reserved for NCS compatibility',
82
- 'specified in RFC 4122',
83
- 'reserved for Microsoft compatibility',
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
- case 0
89
- when to_i & (0x8000 << 48)
90
- RESERVED_NCS
91
- when to_i & (0x4000 << 48)
92
- RFC_4122
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
- RESERVED_FUTURE
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
- class << self
105
- def parse(uuid)
106
- str = uuid.to_s
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
- def uuid4
114
- bytes = SecureRandom.random_bytes(16)
115
- bytes[6] = (bytes[6] & 0x0f) | 0x40
116
- bytes[8] = (bytes[8] & 0x3f) | 0x80
117
- new bytes_to_i(bytes)
118
- end
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
 
@@ -1,18 +1,13 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- describe UUID, '.uuid4' do
4
- it 'generates a new UUID' do
5
- UUID.uuid4.should be_a_kind_of(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 'generates version 4 UUIDs' do
10
- 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}/
11
- UUID.uuid4.version.should == 4
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.1
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: