Class: Friendly::UUID

Inherits:
Object
  • Object
show all
Defined in:
lib/friendly/uuid.rb

Overview

UUID format version 1, as specified in RFC 4122, with jitter in place of the mac address and sequence counter.

Defined Under Namespace

Classes: InvalidVersion, TypeError

Constant Summary collapse

GREGORIAN_EPOCH_OFFSET =

Oct 15, 1582

0x01B2_1DD2_1381_4000
VARIANT =
0b1000_0000_0000_0000

Instance Method Summary collapse

Constructor Details

#initialize(bytes = nil) ⇒ UUID

Returns a new instance of UUID.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/friendly/uuid.rb', line 19

def initialize(bytes = nil)
  case bytes
  when self.class # UUID
    @bytes = bytes.to_s
  when String
    case bytes.size
    when 16 # Raw byte array
      @bytes = bytes
    when 36 # Human-readable UUID representation; inverse of #to_guid
      elements = bytes.split("-")
      raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (malformed UUID representation)" if elements.size != 5
      @bytes = Array(elements.join).pack('H32')
    else
      raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (invalid bytecount)"
    end

  when Integer
    raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (integer out of range)" if bytes < 0 or bytes > 2**128
    @bytes = [
      (bytes >> 96) & 0xFFFF_FFFF,
      (bytes >> 64) & 0xFFFF_FFFF,
      (bytes >> 32) & 0xFFFF_FFFF,
      bytes & 0xFFFF_FFFF
    ].pack("NNNN")

  when NilClass, Time
    time = (bytes || Time).stamp * 10 + GREGORIAN_EPOCH_OFFSET
    # See http://github.com/spectra/ruby-uuid/
    @bytes = [
      time & 0xFFFF_FFFF,
      time >> 32,
      ((time >> 48) & 0x0FFF) | 0x1000,
      # Top 3 bytes reserved
      rand(2**13) | VARIANT,
      rand(2**16),
      rand(2**32)
    ].pack("NnnnnN")

  else
    raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (unknown source class)"
  end
end

Instance Method Details

#<=>(other) ⇒ Object



99
100
101
# File 'lib/friendly/uuid.rb', line 99

def <=>(other)
  total_usecs <=> other.send(:total_usecs)
end

#==(other) ⇒ Object



125
126
127
# File 'lib/friendly/uuid.rb', line 125

def ==(other)
  self.to_s == other.to_s
end

#eql?(other) ⇒ Boolean

Returns:



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

def eql?(other)
  other.is_a?(Comparable) and @bytes == other.to_s
end

#hashObject



117
118
119
# File 'lib/friendly/uuid.rb', line 117

def hash
  @bytes.hash
end

#inspect(long = false) ⇒ Object



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

def inspect(long = false)
  "<Friendly::UUID##{object_id} time: #{
    Time.at(seconds).inspect
  }, usecs: #{
    usecs
  } jitter: #{
    @bytes.unpack('QQ')[1]
  }" + (long ? ", version: #{version}, variant: #{variant}, guid: #{to_guid}>" :  ">")
end

#secondsObject



91
92
93
# File 'lib/friendly/uuid.rb', line 91

def seconds
  total_usecs / 1_000_000
end

#sql_literal(dataset) ⇒ Object



133
134
135
# File 'lib/friendly/uuid.rb', line 133

def sql_literal(dataset)
  dataset.literal(to_s.to_sequel_blob)
end

#to_guidObject



80
81
82
83
84
85
# File 'lib/friendly/uuid.rb', line 80

def to_guid
  elements = @bytes.unpack("NnnCCa6")
  node = elements[-1].unpack('C*')
  elements[-1] = '%02x%02x%02x%02x%02x%02x' % node
  "%08x-%04x-%04x-%02x%02x-%s" % elements
end

#to_iObject



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

def to_i
  ints = @bytes.unpack("NNNN")
  (ints[0] << 96) +
  (ints[1] << 64) +
  (ints[2] << 32) +
  ints[3]
end

#to_json(*args) ⇒ Object



87
88
89
# File 'lib/friendly/uuid.rb', line 87

def to_json(*args)
  to_guid.to_json(*args)
end

#to_sObject



129
130
131
# File 'lib/friendly/uuid.rb', line 129

def to_s
  @bytes
end

#usecsObject



95
96
97
# File 'lib/friendly/uuid.rb', line 95

def usecs
  total_usecs % 1_000_000
end

#variantObject



76
77
78
# File 'lib/friendly/uuid.rb', line 76

def variant
  @bytes.unpack('QnnN')[1] >> 13
end

#versionObject



70
71
72
73
74
# File 'lib/friendly/uuid.rb', line 70

def version
  time_high = @bytes.unpack("NnnQ")[2]
  version = (time_high & 0xF000).to_s(16)[0].chr.to_i
  version > 0 and version < 6 ? version : -1
end