Class: UUID

Inherits:
Struct
  • Object
show all
Includes:
Comparable
Defined in:
lib/uuid.rb,
lib/uuid.rb

Overview

Pure ruby UUID generator, which is compatible with RFC4122

Constant Summary collapse

STATE_FILE =
'ruby-uuid'
NameSpace_DNS =

Pre-defined UUID Namespaces described in RFC4122 Appendix C.

parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
NameSpace_URL =
parse "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
NameSpace_OID =
parse "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
NameSpace_X500 =
parse "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
Nil =

The Nil UUID in RFC4122 Section 4.1.7

parse "00000000-0000-0000-0000-000000000000"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#raw_bytesObject

Returns the value of attribute raw_bytes

Returns:

  • (Object)

    the current value of raw_bytes



30
31
32
# File 'lib/uuid.rb', line 30

def raw_bytes
  @raw_bytes
end

Class Method Details

.create(clock = nil, time = nil, mac_addr = nil) ⇒ Object Also known as: create_v1

create the “version 1” UUID with current system clock, current UTC timestamp, and the IEEE 802 address (so-called MAC address).

Speed notice: it’s slow. It writes some data into hard drive on every invokation. If you want to speed this up, try remounting tmpdir with a memory based filesystem (such as tmpfs). STILL slow? then no way but rewrite it with c :)



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/uuid.rb', line 135

def create clock=nil, time=nil, mac_addr=nil
	c = t = m = nil
	Dir.chdir Dir.tmpdir do
		unless FileTest.exist? STATE_FILE then
			# Generate a pseudo MAC address because we have no pure-ruby way
			# to know  the MAC  address of the  NIC this system  uses.  Note
			# that cheating  with pseudo arresses here  is completely legal:
			# see Section 4.5 of RFC4122 for details.
			sha1 = Digest::SHA1.new
			256.times do
				r = [rand(0x100000000)].pack "N"
				sha1.update r
			end
			str = sha1.digest
			r = rand 14 # 20-6
			node = str[r, 6] || str
			if RUBY_VERSION >= "1.9.0"
				nnode = node.bytes.to_a
				nnode[0] |= 0x01
				node = ''
				nnode.each { |s| node << s.chr }
			else
				node[0] |= 0x01 # multicast bit
			end
			k = rand 0x40000
			open STATE_FILE, 'w' do |fp|
				fp.flock IO::LOCK_EX
				write_state fp, k, node
				fp.chmod 0o777 # must be world writable
			end
		end
		open STATE_FILE, 'r+' do |fp|
			fp.flock IO::LOCK_EX
			c, m = read_state fp
			c = clock % 0x4000 if clock
			m = mac_addr if mac_addr
			t = time
			if t.nil? then
				# UUID epoch is 1582/Oct/15
				tt = Time.now
				t = tt.to_i*10000000 + tt.tv_usec*10 + 0x01B21DD213814000
			end
			c = c.succ # important; increment here
			write_state fp, c, m
		end
	end

	tl = t & 0xFFFF_FFFF
	tm = t >> 32
	tm = tm & 0xFFFF
	th = t >> 48
	th = th & 0x0FFF
	th = th | 0x1000
	cl = c & 0xFF
	ch = c & 0x3F00
	ch = ch >> 8
	ch = ch | 0x80
	pack tl, tm, th, cl, ch, m
end

.create_md5(str, namespace) ⇒ Object Also known as: create_v3

UUID generation using MD5 (for backward compat.)



85
86
87
88
89
90
91
92
93
94
# File 'lib/uuid.rb', line 85

def create_md5 str, namespace
	md5 = Digest::MD5.new
	md5.update namespace.raw_bytes
	md5.update str
	sum = md5.digest
	raw = mask 3, sum[0..16]
	ret = new raw
	ret.freeze
	ret
end

.create_randomObject Also known as: create_v4

UUID generation using random-number generator. From it’s random nature, there’s no warranty that the created ID is really universaly unique.



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/uuid.rb', line 100

def create_random
	rnd = [
		rand(0x100000000),
		rand(0x100000000),
		rand(0x100000000),
		rand(0x100000000),
	].pack "N4"
	raw = mask 4, rnd
	ret = new raw
	ret.freeze
	ret
end

.create_sha1(str, namespace) ⇒ Object Also known as: create_v5

UUID generation using SHA1. Recommended over create_md5. Namespace object is another UUID, some of them are pre-defined below.



72
73
74
75
76
77
78
79
80
81
# File 'lib/uuid.rb', line 72

def create_sha1 str, namespace
	sha1 = Digest::SHA1.new
	sha1.update namespace.raw_bytes
	sha1.update str
	sum = sha1.digest
	raw = mask 5, sum[0..15]
	ret = new raw
	ret.freeze
	ret
end

.mask(v, str) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/uuid.rb', line 61

def mask v, str
	if RUBY_VERSION >= "1.9.0"
		return mask19 v, str
	else
		return mask18 v, str
	end
end

.mask18(v, str) ⇒ Object

:nodoc



50
51
52
53
54
55
56
57
58
59
# File 'lib/uuid.rb', line 50

def mask18 v, str # :nodoc
	version = [0, 16, 32, 48, 64, 80][v]
	str[6] &= 0b00001111
	str[6] |= version
#			str[7] &= 0b00001111
#			str[7] |= 0b01010000
	str[8] &= 0b00111111
	str[8] |= 0b10000000
	str
end

.mask19(v, str) ⇒ Object

:nodoc



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/uuid.rb', line 36

def mask19 v, str # :nodoc
	nstr = str.bytes.to_a
	version = [0, 16, 32, 48, 64, 80][v]
	nstr[6] &= 0b00001111
	nstr[6] |= version
#			nstr[7] &= 0b00001111
#			nstr[7] |= 0b01010000
	nstr[8] &= 0b00111111
	nstr[8] |= 0b10000000
	str = ''
	nstr.each { |s| str << s.chr }
	str
end

.pack(tl, tm, th, ch, cl, n) ⇒ Object

The ‘primitive constructor’ of this class Note UUID.pack(uuid.unpack) == uuid



209
210
211
212
213
214
# File 'lib/uuid.rb', line 209

def pack tl, tm, th, ch, cl, n
	raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6"
	ret = new raw
	ret.freeze
	ret
end

.parse(obj) ⇒ Object

A simple GUID parser: just ignores unknown characters and convert hexadecimal dump into 16-octet object.



198
199
200
201
202
203
204
205
# File 'lib/uuid.rb', line 198

def parse obj
	str = obj.to_s.sub %r/\Aurn:uuid:/, ''
	str.gsub! %r/[^0-9A-Fa-f]/, ''
	raw = str[0..31].lines.to_a.pack 'H*'
	ret = new raw
	ret.freeze
	ret
end

.read_state(fp) ⇒ Object

:nodoc:



114
115
116
117
# File 'lib/uuid.rb', line 114

def read_state fp			  # :nodoc:
	fp.rewind
	Marshal.load fp.read
end

.write_state(fp, c, m) ⇒ Object

:nodoc:



119
120
121
122
123
# File 'lib/uuid.rb', line 119

def write_state fp, c, m  # :nodoc:
	fp.rewind
	str = Marshal.dump [c, m]
	fp.write str
end

Instance Method Details

#<=>(other) ⇒ Object

UUIDs are comparable (don’t know what benefits are there, though).



266
267
268
# File 'lib/uuid.rb', line 266

def <=> other
	to_s <=> other.to_s
end

#==(other) ⇒ Object

Two UUIDs are said to be equal if and only if their (byte-order canonicalized) integer representations are equivallent. Refer RFC4122 for details.



260
261
262
# File 'lib/uuid.rb', line 260

def == other
	to_i == other.to_i
end

#to_intObject Also known as: to_i

Convert into 128-bit unsigned integer Typically a Bignum instance, but can be a Fixnum.



240
241
242
243
244
245
# File 'lib/uuid.rb', line 240

def to_int
	tmp = self.raw_bytes.unpack "C*"
	tmp.inject do |r, i|
		r * 256 | i
	end
end

#to_sObject Also known as: guid

Generate the string representation (a.k.a GUID) of this UUID



224
225
226
227
228
229
# File 'lib/uuid.rb', line 224

def to_s
	a = unpack
	tmp = a[-1].unpack 'C*'
	a[-1] = sprintf '%02x%02x%02x%02x%02x%02x', *tmp
	"%08x-%04x-%04x-%02x%02x-%s" % a
end

#to_uriObject Also known as: urn

Convert into a RFC4122-comforming URN representation



233
234
235
# File 'lib/uuid.rb', line 233

def to_uri
	"urn:uuid:" + self.to_s
end

#unpackObject

The ‘primitive deconstructor’, or the dual to pack. Note UUID.pack(uuid.unpack) == uuid



219
220
221
# File 'lib/uuid.rb', line 219

def unpack
	raw_bytes.unpack "NnnCCa6"
end

#versionObject

Gets the version of this UUID returns nil if bad version



250
251
252
253
254
255
# File 'lib/uuid.rb', line 250

def version
	a = unpack
	v = (a[2] & 0xF000).to_s(16)[0].chr.to_i
	return v if (1..5).include? v
	return nil
end