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/json-schema/util/uuid.rb, line 139 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
UUID generation using MD5 (for backward compat.)
# File lib/json-schema/util/uuid.rb, line 89 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
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/json-schema/util/uuid.rb, line 104 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
UUID generation using SHA1. Recommended over create_md5. Namespace object is another UUID, some of them are pre-defined below.
# File lib/json-schema/util/uuid.rb, line 76 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
The 'primitive constructor' of this class Note ::pack == uuid
# File lib/json-schema/util/uuid.rb, line 213 def pack tl, tm, th, ch, cl, n raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6" ret = new raw ret.freeze ret end
A simple GUID parser: just ignores unknown characters and convert hexadecimal dump into 16-octet object.
# File lib/json-schema/util/uuid.rb, line 202 def parse obj str = obj.to_s.sub /\Aurn:uuid:/, '' str.gsub! /[^0-9A-Fa-f]/, '' raw = str[0..31].lines.to_a.pack 'H*' ret = new raw ret.freeze ret end
# File lib/json-schema/util/uuid.rb, line 65 def mask v, str if RUBY_VERSION >= "1.9.0" return mask19 v, str else return mask18 v, str end end
# File lib/json-schema/util/uuid.rb, line 54 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
# File lib/json-schema/util/uuid.rb, line 40 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
UUIDs are comparable (don't know what benefits are there, though).
# File lib/json-schema/util/uuid.rb, line 269 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/json-schema/util/uuid.rb, line 263 def == other to_i == other.to_i end
Convert into 128-bit unsigned integer
# File lib/json-schema/util/uuid.rb, line 243 def to_int tmp = self.raw_bytes.unpack "C*" tmp.inject do |r, i| r * 256 | i end end
Generate the string representation (a.k.a GUID) of this UUID
# File lib/json-schema/util/uuid.rb, line 228 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
Convert into a RFC4122-comforming URN representation
# File lib/json-schema/util/uuid.rb, line 237 def to_uri "urn:uuid:" + self.to_s end
The 'primitive deconstructor', or the dual to pack. Note ::pack == uuid
# File lib/json-schema/util/uuid.rb, line 223 def unpack raw_bytes.unpack "NnnCCa6" end
Gets the version of this UUID returns nil if bad version
# File lib/json-schema/util/uuid.rb, line 253 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