class UUID

Pure ruby UUID generator, which is compatible with RFC4122

Constants

NameSpace_DNS

Pre-defined UUID Namespaces described in RFC4122 Appendix C.

NameSpace_OID
NameSpace_URL
NameSpace_X500
Nil

The Nil UUID in RFC4122 Section 4.1.7

STATE_FILE
UNIXEpoch

UUID epoch is 15th Oct. 1582

Public Class Methods

create(clock=nil, time=Time.now, mac_addr=nil) click to toggle source

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
create_md5(str, namespace) click to toggle source

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
create_random() click to toggle source

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
create_sha1(str, namespace) click to toggle source

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
new(str) click to toggle source
# 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
pack(tl, tm, th, ch, cl, n) click to toggle source

The 'primitive constructor' of this class Note ::pack == 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
parse(obj) click to toggle source

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 /\Aurn:uuid:/, ''
        str.gsub! /[^0-9A-Fa-f]/, ''
        raw = [str[0..31]].pack 'H*'
        new raw
end

Public Instance Methods

<=>(other) click to toggle source

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
==(other) click to toggle source

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
Also aliased as: eql?
clock() click to toggle source

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
eql?(other)
Alias for: ==
guid()
Alias for: to_s
hash() click to toggle source

Two identical UUIDs should have same hash

# File lib/uuid.rb, line 282
def hash
        to_i
end
ieee802()
Alias for: node
inspect()
Alias for: to_uri
mac_address()
Alias for: node
node() click to toggle source

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
Also aliased as: mac_address, ieee802
raw_bytes() click to toggle source
# 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
time() click to toggle source

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
to_i()
Alias for: to_int
to_int() click to toggle source

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
Also aliased as: to_i
to_s() click to toggle source

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
Also aliased as: guid
to_uri() click to toggle source

Convert into a RFC4122-comforming URN representation

# File lib/uuid.rb, line 260
def to_uri
        "urn:uuid:" + self.to_s
end
Also aliased as: urn, inspect
unpack() click to toggle source

The 'primitive deconstructor', or the dual to pack. Note ::pack == uuid

# File lib/uuid.rb, line 206
def unpack
        raw_bytes.unpack "NnnCCa6"
end
urn()
Alias for: to_uri
version() click to toggle source

The version of this UUID

# File lib/uuid.rb, line 228
def version
        v = unpack[2] & 0b1111_0000_0000_0000
        v >> 12
end