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.



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
61
# File 'lib/friendly/uuid.rb', line 20

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



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

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

#==(other) ⇒ Object



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

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

#eql?(other) ⇒ Boolean

Returns:



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

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

#hashObject



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

def hash
  @bytes.hash
end

#inspect(long = false) ⇒ Object



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

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



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

def seconds
  total_usecs / 1_000_000
end

#sql_literal(dataset) ⇒ Object



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

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

#to_guidObject



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

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



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

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

#to_json(*args) ⇒ Object



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

def to_json(*args)
  Rufus::Json.encode(to_guid)
end

#to_sObject



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

def to_s
  @bytes
end

#usecsObject



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

def usecs
  total_usecs % 1_000_000
end

#variantObject



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

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

#versionObject



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

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