Class: UUID
Overview
Pure ruby UUID generator, which is compatible with RFC4122
Constant Summary collapse
- UNIXEpoch =
UUID epoch is 15th Oct. 1582
0x01B21DD213814000
- 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"
Class Method Summary collapse
-
.create(clock = nil, time = Time.now, mac_addr = nil) ⇒ Object
create the “version 1” UUID with current system clock, current UTC timestamp, and the IEEE 802 address (so-called MAC address).
-
.create_md5(str, namespace) ⇒ Object
UUID generation using MD5 (for backward compat.).
-
.create_random ⇒ Object
UUID generation using random-number generator.
-
.create_sha1(str, namespace) ⇒ Object
UUID generation using SHA1.
-
.mask(ver, str) ⇒ Object
:nodoc:.
-
.pack(tl, tm, th, ch, cl, n) ⇒ Object
The ‘primitive constructor’ of this class Note UUID.pack(uuid.unpack) == uuid.
-
.parse(obj) ⇒ Object
A simple GUID parser: just ignores unknown characters and convert hexadecimal dump into 16-octet object.
-
.prand ⇒ Object
:nodoc:.
-
.read_state(fp) ⇒ Object
:nodoc:.
-
.write_state(fp, c, m) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
UUIDs are comparable (don’t know what benefits are there, though).
-
#==(other) ⇒ Object
(also: #eql?)
Two UUIDs are said to be equal if and only if their (byte-order canonicalized) integer representations are equivallent.
-
#clock ⇒ Object
The clock sequence of this UUID.
-
#hash ⇒ Object
Two identical UUIDs should have same hash.
-
#node ⇒ Object
(also: #mac_address, #ieee802)
The IEEE 802 address in a hexadecimal format.
- #raw_bytes ⇒ Object
-
#time ⇒ Object
The timestamp of this UUID.
-
#to_int ⇒ Object
(also: #to_i)
Convert into 128-bit unsigned integer Typically a Bignum instance, but can be a Fixnum.
-
#to_s ⇒ Object
(also: #guid)
Generate the string representation (a.k.a GUID) of this UUID.
-
#to_uri ⇒ Object
(also: #urn, #inspect)
Convert into a RFC4122-comforming URN representation.
-
#unpack ⇒ Object
The ‘primitive deconstructor’, or the dual to pack.
-
#version ⇒ Object
The version of this UUID.
Class Method Details
.create(clock = nil, time = Time.now, mac_addr = nil) ⇒ Object
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 :)
131 132 133 134 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 |
# 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) ⇒ Object
UUID generation using MD5 (for backward compat.)
92 93 94 95 96 97 98 99 |
# 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 ⇒ Object
UUID generation using random-number generator. From it’s random nature, there’s no warranty that the created ID is really universaly unique.
104 105 106 107 108 |
# 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) ⇒ Object
UUID generation using SHA1. Recommended over create_md5. Namespace object is another UUID, some of them are pre-defined below.
82 83 84 85 86 87 88 89 |
# 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 |
.mask(ver, str) ⇒ Object
:nodoc:
61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/uuid.rb', line 61 def mask ver, str # :nodoc: ver = ver & 15 v = str[6].ord v &= 0b0000_1111 v |= ver << 4 str[6] = v.chr r = str[8].ord r &= 0b0011_1111 r |= 0b1000_0000 str[8] = r.chr str end |
.pack(tl, tm, th, ch, cl, n) ⇒ Object
The ‘primitive constructor’ of this class Note UUID.pack(uuid.unpack) == uuid
198 199 200 201 |
# 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) ⇒ Object
A simple GUID parser: just ignores unknown characters and convert hexadecimal dump into 16-octet object.
189 190 191 192 193 194 |
# 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 |
.prand ⇒ Object
:nodoc:
74 75 76 |
# File 'lib/uuid.rb', line 74 def prand # :nodoc: rand 0x100000000 end |
.read_state(fp) ⇒ Object
:nodoc:
110 111 112 113 |
# File 'lib/uuid.rb', line 110 def read_state fp # :nodoc: fp.rewind Marshal.load fp.read end |
.write_state(fp, c, m) ⇒ Object
:nodoc:
115 116 117 118 119 |
# File 'lib/uuid.rb', line 115 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).
288 289 290 |
# File 'lib/uuid.rb', line 288 def <=> other to_s <=> other.to_s end |
#==(other) ⇒ Object Also known as: eql?
Two UUIDs are said to be equal if and only if their (byte-order canonicalized) integer representations are equivallent. Refer RFC4122 for details.
276 277 278 |
# File 'lib/uuid.rb', line 276 def == other to_i == other.to_i end |
#clock ⇒ Object
The clock sequence of this UUID
234 235 236 237 238 239 240 241 |
# 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 |
#hash ⇒ Object
Two identical UUIDs should have same hash
282 283 284 |
# File 'lib/uuid.rb', line 282 def hash to_i end |
#node ⇒ Object Also known as: mac_address, ieee802
The IEEE 802 address in a hexadecimal format
244 245 246 247 |
# File 'lib/uuid.rb', line 244 def node m = unpack[5].unpack 'C*' '%02x%02x%02x%02x%02x%02x' % m end |
#raw_bytes ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 |
# 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 ⇒ Object
The timestamp of this UUID. Throws RageError if that time exceeds UNIX time range
212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# 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_int ⇒ Object Also known as: to_i
Convert into 128-bit unsigned integer Typically a Bignum instance, but can be a Fixnum.
268 269 270 |
# File 'lib/uuid.rb', line 268 def to_int @num end |
#to_s ⇒ Object Also known as: guid
Generate the string representation (a.k.a GUID) of this UUID
252 253 254 255 256 |
# File 'lib/uuid.rb', line 252 def to_s a = unpack a[-1] = mac_address "%08x-%04x-%04x-%02x%02x-%s" % a end |
#to_uri ⇒ Object Also known as: urn, inspect
Convert into a RFC4122-comforming URN representation
260 261 262 |
# File 'lib/uuid.rb', line 260 def to_uri "urn:uuid:" + self.to_s end |
#unpack ⇒ Object
The ‘primitive deconstructor’, or the dual to pack. Note UUID.pack(uuid.unpack) == uuid
206 207 208 |
# File 'lib/uuid.rb', line 206 def unpack raw_bytes.unpack "NnnCCa6" end |
#version ⇒ Object
The version of this UUID
228 229 230 231 |
# File 'lib/uuid.rb', line 228 def version v = unpack[2] & 0b1111_0000_0000_0000 v >> 12 end |