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.
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: