lexical_uuid 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lexical_uuid.gemspec +29 -22
- data/lib/lexical_uuid.rb +55 -16
- data/spec/lexical_uuid_spec.rb +41 -14
- metadata +3 -3
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/jamesgolick/lexical_uuid"
|
12
12
|
gem.authors = ["James Golick"]
|
13
13
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
-
gem.add_dependency "
|
14
|
+
gem.add_dependency "RubyInline", ">3.8.4"
|
15
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
16
|
end
|
17
17
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
data/lexical_uuid.gemspec
CHANGED
@@ -1,51 +1,58 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.1.
|
7
|
+
s.name = %q{lexical_uuid}
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["James Golick"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
12
|
+
s.date = %q{2010-11-22}
|
13
|
+
s.description = %q{UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.}
|
14
|
+
s.email = %q{jamesgolick@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lexical_uuid.gemspec",
|
27
|
+
"lib/lexical_uuid.rb",
|
28
|
+
"spec/lexical_uuid_spec.rb",
|
29
|
+
"spec/spec.opts",
|
30
|
+
"spec/spec_helper.rb"
|
30
31
|
]
|
31
|
-
s.homepage =
|
32
|
+
s.homepage = %q{http://github.com/jamesgolick/lexical_uuid}
|
33
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
32
34
|
s.require_paths = ["lib"]
|
33
|
-
s.rubygems_version =
|
34
|
-
s.summary =
|
35
|
+
s.rubygems_version = %q{1.3.7}
|
36
|
+
s.summary = %q{UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.}
|
37
|
+
s.test_files = [
|
38
|
+
"spec/lexical_uuid_spec.rb",
|
39
|
+
"spec/spec_helper.rb"
|
40
|
+
]
|
35
41
|
|
36
42
|
if s.respond_to? :specification_version then
|
43
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
37
44
|
s.specification_version = 3
|
38
45
|
|
39
46
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
40
47
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
41
|
-
s.add_runtime_dependency(%q<RubyInline>, ["
|
48
|
+
s.add_runtime_dependency(%q<RubyInline>, ["= 3.8.4"])
|
42
49
|
else
|
43
50
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
44
|
-
s.add_dependency(%q<RubyInline>, ["
|
51
|
+
s.add_dependency(%q<RubyInline>, ["= 3.8.4"])
|
45
52
|
end
|
46
53
|
else
|
47
54
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
48
|
-
s.add_dependency(%q<RubyInline>, ["
|
55
|
+
s.add_dependency(%q<RubyInline>, ["= 3.8.4"])
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
data/lib/lexical_uuid.rb
CHANGED
@@ -1,8 +1,35 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "socket"
|
3
|
-
require "
|
4
|
-
|
5
|
-
|
3
|
+
require "inline"
|
4
|
+
|
5
|
+
class String
|
6
|
+
inline :C do |builder|
|
7
|
+
builder.c <<-__END__
|
8
|
+
static long fnv1a() {
|
9
|
+
int hash = 2166136261;
|
10
|
+
int i = 0;
|
11
|
+
|
12
|
+
for(i = 0; i < RSTRING_LEN(self); i++) {
|
13
|
+
hash ^= RSTRING_PTR(self)[i];
|
14
|
+
hash *= 16777619;
|
15
|
+
}
|
16
|
+
|
17
|
+
return hash;
|
18
|
+
}
|
19
|
+
__END__
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Borrowed from the SimpleUUID gem
|
24
|
+
class Time
|
25
|
+
def self.stamp
|
26
|
+
Time.now.stamp
|
27
|
+
end
|
28
|
+
|
29
|
+
def stamp
|
30
|
+
to_i * 1_000_000 + usec
|
31
|
+
end
|
32
|
+
end
|
6
33
|
|
7
34
|
class LexicalUUID
|
8
35
|
class << self
|
@@ -14,16 +41,17 @@ class LexicalUUID
|
|
14
41
|
def create_worker_id
|
15
42
|
fqdn = Socket.gethostbyname(Socket.gethostname).first
|
16
43
|
pid = Process.pid
|
17
|
-
|
44
|
+
"#{fqdn}-#{pid}".fnv1a
|
18
45
|
end
|
19
46
|
end
|
20
47
|
|
21
|
-
attr_reader :worker_id, :timestamp
|
48
|
+
attr_reader :worker_id, :jitter, :timestamp
|
22
49
|
|
23
|
-
def initialize(timestamp = nil,
|
50
|
+
def initialize(timestamp = nil, jitter = nil, worker_id = nil)
|
24
51
|
case timestamp
|
25
52
|
when Fixnum, Bignum
|
26
53
|
@timestamp = timestamp
|
54
|
+
@jitter = jitter || create_jitter
|
27
55
|
@worker_id = worker_id || self.class.worker_id
|
28
56
|
when String
|
29
57
|
case timestamp.size
|
@@ -31,25 +59,27 @@ class LexicalUUID
|
|
31
59
|
from_bytes(timestamp)
|
32
60
|
when 36
|
33
61
|
elements = timestamp.split("-")
|
34
|
-
from_bytes(elements.join.
|
62
|
+
from_bytes([elements.join].pack('H32'))
|
35
63
|
else
|
36
64
|
raise ArgumentError,
|
37
65
|
"#{timestamp} was incorrectly sized. Must be 16 timestamp."
|
38
66
|
end
|
39
67
|
when Time
|
40
68
|
@timestamp = timestamp.stamp
|
69
|
+
@jitter = create_jitter
|
41
70
|
@worker_id = self.class.worker_id
|
42
71
|
when nil
|
43
72
|
@worker_id = self.class.worker_id
|
44
|
-
@
|
73
|
+
@jitter = create_jitter
|
74
|
+
@timestamp = Time.stamp
|
45
75
|
end
|
46
76
|
end
|
47
77
|
|
48
78
|
def to_bytes
|
49
79
|
[timestamp >> 32,
|
50
|
-
|
51
|
-
|
52
|
-
|
80
|
+
timestamp & 0xffffffff,
|
81
|
+
jitter,
|
82
|
+
worker_id].pack("iIii")
|
53
83
|
end
|
54
84
|
|
55
85
|
# Also borrowed from simple_uuid
|
@@ -61,14 +91,20 @@ class LexicalUUID
|
|
61
91
|
end
|
62
92
|
|
63
93
|
def <=>(other)
|
64
|
-
timestamp == other.timestamp
|
65
|
-
worker_id <=> other.worker_id
|
94
|
+
if timestamp == other.timestamp && jitter == other.jitter
|
95
|
+
worker_id <=> other.worker_id
|
96
|
+
elsif timestamp == other.timestamp
|
97
|
+
jitter <=> other.jitter
|
98
|
+
else
|
99
|
+
timestamp <=> other.timestamp
|
100
|
+
end
|
66
101
|
end
|
67
102
|
|
68
103
|
def ==(other)
|
69
104
|
other.is_a?(LexicalUUID) &&
|
70
105
|
timestamp == other.timestamp &&
|
71
|
-
|
106
|
+
jitter == other.jitter &&
|
107
|
+
worker_id == other.worker_id
|
72
108
|
end
|
73
109
|
|
74
110
|
def eql?(other)
|
@@ -81,8 +117,11 @@ class LexicalUUID
|
|
81
117
|
|
82
118
|
private
|
83
119
|
def from_bytes(bytes)
|
84
|
-
time_high, time_low,
|
120
|
+
time_high, time_low, @jitter, @worker_id = bytes.unpack("iIii")
|
85
121
|
@timestamp = (time_high << 32) | time_low
|
86
|
-
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_jitter
|
125
|
+
rand(2**32)
|
87
126
|
end
|
88
127
|
end
|
data/spec/lexical_uuid_spec.rb
CHANGED
@@ -14,11 +14,15 @@ describe "LexicalUUID" do
|
|
14
14
|
@uuid.timestamp.should < Time.stamp
|
15
15
|
end
|
16
16
|
|
17
|
+
it "has jitter" do
|
18
|
+
@uuid.jitter.should_not be_nil
|
19
|
+
end
|
20
|
+
|
17
21
|
it "serializes to bytes" do
|
18
22
|
expected_bytes = [@uuid.timestamp >> 32,
|
19
23
|
@uuid.timestamp & 0xffffffff,
|
20
|
-
@uuid.
|
21
|
-
@uuid.worker_id
|
24
|
+
@uuid.jitter,
|
25
|
+
@uuid.worker_id].pack("iIii")
|
22
26
|
@uuid.to_bytes.should == expected_bytes
|
23
27
|
end
|
24
28
|
end
|
@@ -28,8 +32,8 @@ describe "LexicalUUID" do
|
|
28
32
|
before do
|
29
33
|
@bytes = [1234567890 >> 32,
|
30
34
|
1234567890 & 0xffffffff,
|
31
|
-
|
32
|
-
|
35
|
+
54321,
|
36
|
+
12345].pack("iIii")
|
33
37
|
@uuid = LexicalUUID.new(@bytes)
|
34
38
|
end
|
35
39
|
|
@@ -37,8 +41,12 @@ describe "LexicalUUID" do
|
|
37
41
|
@uuid.timestamp.should == 1234567890
|
38
42
|
end
|
39
43
|
|
44
|
+
it "correctly extracts the jitter" do
|
45
|
+
@uuid.jitter.should == 54321
|
46
|
+
end
|
47
|
+
|
40
48
|
it "correctly extracts the worker id" do
|
41
|
-
@uuid.worker_id.should ==
|
49
|
+
@uuid.worker_id.should == 12345
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
@@ -54,8 +62,9 @@ describe "LexicalUUID" do
|
|
54
62
|
describe "initializing a uuid from a timestamp and worker_id" do
|
55
63
|
before do
|
56
64
|
@timestamp = 15463021018891620831
|
57
|
-
@
|
58
|
-
@
|
65
|
+
@jitter = 1234125
|
66
|
+
@worker_id = 51341
|
67
|
+
@uuid = LexicalUUID.new(@timestamp, @jitter, @worker_id)
|
59
68
|
end
|
60
69
|
|
61
70
|
it "sets the timestamp" do
|
@@ -65,29 +74,37 @@ describe "LexicalUUID" do
|
|
65
74
|
it "sets the worker_id" do
|
66
75
|
@uuid.worker_id.should == @worker_id
|
67
76
|
end
|
77
|
+
|
78
|
+
it "sets the jitter" do
|
79
|
+
@uuid.jitter.should == @jitter
|
80
|
+
end
|
68
81
|
end
|
69
82
|
|
70
83
|
describe "converting a uuid in to a guid" do
|
71
84
|
before do
|
72
|
-
@uuid = LexicalUUID.new(15463021018891620831,
|
85
|
+
@uuid = LexicalUUID.new(15463021018891620831, 2320096881, 2389085541)
|
73
86
|
end
|
74
87
|
|
75
88
|
it "matches other uuid->guid implementations" do
|
76
|
-
@uuid.to_guid.should == "
|
89
|
+
@uuid.to_guid.should == "b0af97d6-df11-6fa9-71de-498a658d668e"
|
77
90
|
end
|
78
91
|
end
|
79
92
|
|
80
93
|
describe "initializing from a guid" do
|
81
94
|
before do
|
82
|
-
@uuid = LexicalUUID.new("
|
95
|
+
@uuid = LexicalUUID.new("d3910400-a04d-1c02-69bd-2d82f733af24")
|
83
96
|
end
|
84
97
|
|
85
98
|
it "correctly initializes the timestamp" do
|
86
|
-
@uuid.timestamp.should ==
|
99
|
+
@uuid.timestamp.should == 1286235366378912
|
100
|
+
end
|
101
|
+
|
102
|
+
it "correctly initializes the jitter" do
|
103
|
+
@uuid.jitter.should == -2110931607
|
87
104
|
end
|
88
105
|
|
89
106
|
it "correctly initializes the worker_id" do
|
90
|
-
@uuid.worker_id.should ==
|
107
|
+
@uuid.worker_id.should == 615461879
|
91
108
|
end
|
92
109
|
end
|
93
110
|
|
@@ -103,6 +120,10 @@ describe "LexicalUUID" do
|
|
103
120
|
it "uses the default worker_id" do
|
104
121
|
@uuid.worker_id.should == LexicalUUID.worker_id
|
105
122
|
end
|
123
|
+
|
124
|
+
it "initializes the jitter" do
|
125
|
+
@uuid.jitter.should_not be_nil
|
126
|
+
end
|
106
127
|
end
|
107
128
|
|
108
129
|
describe "comparing uuids" do
|
@@ -111,11 +132,17 @@ describe "LexicalUUID" do
|
|
111
132
|
(LexicalUUID.new(223) <=> LexicalUUID.new(134)).should == 1
|
112
133
|
end
|
113
134
|
|
114
|
-
it "compares by
|
135
|
+
it "compares by jitter if the timestamps are equal" do
|
115
136
|
(LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 2)).should == -1
|
116
137
|
(LexicalUUID.new(123, 2) <=> LexicalUUID.new(123, 1)).should == 1
|
117
138
|
(LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 1)).should == 0
|
118
139
|
end
|
140
|
+
|
141
|
+
it "compares by worker_id if the timestamps and jitter are equal" do
|
142
|
+
(LexicalUUID.new(123, 1, 0) <=> LexicalUUID.new(123, 1, 1)).should == -1
|
143
|
+
(LexicalUUID.new(123, 1, 1) <=> LexicalUUID.new(123, 1, 0)).should == 1
|
144
|
+
(LexicalUUID.new(123, 1, 1) <=> LexicalUUID.new(123, 1, 1)).should == 0
|
145
|
+
end
|
119
146
|
end
|
120
147
|
|
121
148
|
describe "==" do
|
@@ -128,7 +155,7 @@ describe "LexicalUUID" do
|
|
128
155
|
end
|
129
156
|
|
130
157
|
it "is not equal when the worker_ids are not equal" do
|
131
|
-
LexicalUUID.new(123, 223).should_not == LexicalUUID.new(123, 123)
|
158
|
+
LexicalUUID.new(123, 223, 432).should_not == LexicalUUID.new(123, 123, 234)
|
132
159
|
end
|
133
160
|
end
|
134
161
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lexical_uuid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 7
|
10
|
+
version: 0.1.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- James Golick
|