class UUID
Pure ruby UUID
generator, which is compatible with RFC4122
Constants
Public Class Methods
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 :)
# File lib/uuid.rb, line 131 def create clock=nil, time=Time.now, 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 = [prand].pack "N" sha1.update r end ary = sha1.digest.bytes.to_a node = ary.last 6 node[0] |= 0x01 # multicast bit node = node.pack "C*" 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 += 1 # important; increment here write_state fp, c, m end end c = clock & 0b11_1111_1111_1111 if clock m = mac_addr if mac_addr time = Time.at time if time.is_a? Float case time when Time t = time.to_i * 10_000_000 + time.tv_usec * 10 + UNIXEpoch when Integer t = time + UNIXEpoch else raise TypeError, "cannot convert ``#{time}'' into Time." end tl = t & 0xFFFF_FFFF tm = t >> 32 tm = tm & 0xFFFF th = t >> 48 th = th & 0b0000_1111_1111_1111 th = th | 0b0001_0000_0000_0000 cl = c & 0b0000_0000_1111_1111 ch = c & 0b0011_1111_0000_0000 ch = ch >> 8 ch = ch | 0b1000_0000 pack tl, tm, th, ch, cl, m end
UUID
generation using MD5 (for backward compat.)
# File lib/uuid.rb, line 92 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] new raw end
UUID
generation using random-number generator. From it's random nature, there's no warranty that the created ID is really universaly unique.
# File lib/uuid.rb, line 104 def create_random rnd = [prand, prand, prand, prand].pack "N4" raw = mask 4, rnd new raw end
UUID
generation using SHA1. Recommended over create_md5. Namespace object is another UUID
, some of them are pre-defined below.
# File lib/uuid.rb, line 82 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] new raw end
# File lib/uuid.rb, line 37 def initialize str tmp = str.unpack "C*" @num = tmp.inject do |r, i| r * 256 | i end @num.freeze self.freeze end
The 'primitive constructor' of this class Note UUID.pack(uuid.unpack)
== uuid
# File lib/uuid.rb, line 198 def pack tl, tm, th, ch, cl, n raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6" new raw end
A simple GUID parser: just ignores unknown characters and convert hexadecimal dump into 16-octet object.
# File lib/uuid.rb, line 189 def parse obj str = obj.to_s.sub %r/\Aurn:uuid:/, '' str.gsub! %r/[^0-9A-Fa-f]/, '' raw = [str[0..31]].pack 'H*' new raw end
Public Instance Methods
UUIDs are comparable (don't know what benefits are there, though).
# File lib/uuid.rb, line 288 def <=> other to_s <=> other.to_s end
Two UUIDs are said to be equal if and only if their (byte-order canonicalized) integer representations are equivallent. Refer RFC4122 for details.
# File lib/uuid.rb, line 276 def == other to_i == other.to_i end
The clock sequence of this UUID
# File lib/uuid.rb, line 234 def clock a = unpack ch = a[3] & 0b0001_1111 cl = a[4] c = cl c += ch << 8 c end
Two identical UUIDs should have same hash
# File lib/uuid.rb, line 282 def hash to_i end
The IEEE 802 address in a hexadecimal format
# File lib/uuid.rb, line 244 def node m = unpack[5].unpack 'C*' '%02x%02x%02x%02x%02x%02x' % m end
# File lib/uuid.rb, line 48 def raw_bytes ret = String.new tmp = @num 16.times do |i| x, y = tmp.divmod 256 ret << y tmp = x end ret.reverse! ret end
The timestamp of this UUID
. Throws RageError if that time exceeds UNIX time range
# File lib/uuid.rb, line 212 def time a = unpack tl = a[0] tm = a[1] th = a[2] & 0x0FFF t = tl t += tm << 32 t += th << 48 t -= UNIXEpoch tv_sec = t / 10_000_000 t -= tv_sec * 10_000_000 tv_usec = t / 10 Time.at tv_sec, tv_usec end
Convert into 128-bit unsigned integer Typically a Bignum instance, but can be a Fixnum.
# File lib/uuid.rb, line 268 def to_int @num end
Generate the string representation (a.k.a GUID) of this UUID
# File lib/uuid.rb, line 252 def to_s a = unpack a[-1] = mac_address "%08x-%04x-%04x-%02x%02x-%s" % a end
Convert into a RFC4122-comforming URN representation
# File lib/uuid.rb, line 260 def to_uri "urn:uuid:" + self.to_s end
The 'primitive deconstructor', or the dual to pack. Note UUID.pack(uuid.unpack)
== uuid
# File lib/uuid.rb, line 206 def unpack raw_bytes.unpack "NnnCCa6" end
The version of this UUID
# File lib/uuid.rb, line 228 def version v = unpack[2] & 0b1111_0000_0000_0000 v >> 12 end