lexical_uuid 0.0.1

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 James Golick
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,26 @@
1
+ = lexical_uuid
2
+
3
+ UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.
4
+
5
+ = Install
6
+
7
+ sudo gem install lexical_uuid
8
+
9
+ = Usage
10
+
11
+ ree-1.8.7-2010.02 > LexicalUUID.new
12
+ => #<LexicalUUID:0x1019400f0 @worker_id=2842420286492008582, @timestamp=1281991807929511>
13
+ r ee-1.8.7-2010.02 > LexicalUUID.new.to_guid
14
+ => "00048df6-faef-2bb5-2772-4e30d6b86086"
15
+ r ee-1.8.7-2010.02 > LexicalUUID.new.to_bytes
16
+ => "\000\004\215\366\373\"\022\352'rN0\326\270206"
17
+ r ee-1.8.7-2010.02 > LexicalUUID.new(LexicalUUID.new.to_guid)
18
+ => #<LexicalUUID:0x101936118 @worker_id=2842420286492008582, @timestamp=1281991837642798>
19
+ r ee-1.8.7-2010.02 > LexicalUUID.new(LexicalUUID.new.to_bytes)
20
+ => #<LexicalUUID:0x101931690 @worker_id=2842420286492008582, @timestamp=1281991842330188>
21
+ r ee-1.8.7-2010.02 > LexicalUUID.new(Time.now)
22
+ => #<LexicalUUID:0x10192df18 @worker_id=2842420286492008582, @timestamp=1281991847641387>
23
+
24
+ == Copyright
25
+
26
+ Copyright (c) 2010 James Golick. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "lexical_uuid"
8
+ gem.summary = %Q{UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.}
9
+ gem.description = %Q{UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.}
10
+ gem.email = "jamesgolick@gmail.com"
11
+ gem.homepage = "http://github.com/jamesgolick/lexical_uuid"
12
+ gem.authors = ["James Golick"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency "RubyInline", "=3.8.4"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "lexical_uuid #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,113 @@
1
+ require "rubygems"
2
+ require "socket"
3
+ require "inline"
4
+
5
+ class String
6
+ inline :C do |builder|
7
+ builder.c <<-__END__
8
+ static long fnv1a() {
9
+ long hash = 0xcbf29ce484222325;
10
+ long i = 0;
11
+
12
+ for(i = 0; i < RSTRING(self)->len; i++) {
13
+ hash ^= RSTRING(self)->ptr[i];
14
+ hash *= 0x100000001b3;
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
33
+
34
+ class LexicalUUID
35
+ class << self
36
+ def worker_id
37
+ @worker_id ||= create_worker_id
38
+ end
39
+
40
+ private
41
+ def create_worker_id
42
+ Socket.gethostbyname(Socket.gethostname).first.fnv1a
43
+ end
44
+ end
45
+
46
+ attr_reader :worker_id, :timestamp
47
+
48
+ def initialize(timestamp = nil, worker_id = nil)
49
+ case timestamp
50
+ when Fixnum, Bignum
51
+ @timestamp = timestamp
52
+ @worker_id = worker_id || self.class.worker_id
53
+ when String
54
+ case timestamp.size
55
+ when 16
56
+ from_bytes(timestamp)
57
+ when 36
58
+ elements = timestamp.split("-")
59
+ from_bytes(elements.join.to_a.pack('H32'))
60
+ else
61
+ raise ArgumentError,
62
+ "#{timestamp} was incorrectly sized. Must be 16 timestamp."
63
+ end
64
+ when Time
65
+ @timestamp = timestamp.stamp
66
+ @worker_id = self.class.worker_id
67
+ when nil
68
+ @worker_id = self.class.worker_id
69
+ @timestamp = Time.stamp
70
+ end
71
+ end
72
+
73
+ def to_bytes
74
+ [timestamp >> 32,
75
+ timestamp & 0xffffffff,
76
+ worker_id >> 32,
77
+ worker_id & 0xffffffff].pack("NNNN")
78
+ end
79
+
80
+ # Also borrowed from simple_uuid
81
+ def to_guid
82
+ elements = to_bytes.unpack("NnnCCa6")
83
+ node = elements[-1].unpack('C*')
84
+ elements[-1] = '%02x%02x%02x%02x%02x%02x' % node
85
+ "%08x-%04x-%04x-%02x%02x-%s" % elements
86
+ end
87
+
88
+ def <=>(other)
89
+ timestamp == other.timestamp ?
90
+ worker_id <=> other.worker_id : timestamp <=> other.timestamp
91
+ end
92
+
93
+ def ==(other)
94
+ other.is_a?(LexicalUUID) &&
95
+ timestamp == other.timestamp &&
96
+ worker_id == other.worker_id
97
+ end
98
+
99
+ def eql?(other)
100
+ self == other
101
+ end
102
+
103
+ def hash
104
+ to_bytes.hash
105
+ end
106
+
107
+ private
108
+ def from_bytes(bytes)
109
+ time_high, time_low, worker_high, worker_low = bytes.unpack("NNNN")
110
+ @timestamp = (time_high << 32) | time_low
111
+ @worker_id = (worker_high << 32) | worker_low
112
+ end
113
+ end
@@ -0,0 +1,173 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "LexicalUUID" do
4
+ describe "creating a UUID with no parameters" do
5
+ before do
6
+ @uuid = LexicalUUID.new
7
+ end
8
+
9
+ it "has a worker id" do
10
+ @uuid.worker_id.should_not be_nil
11
+ end
12
+
13
+ it "has a timestamp in usecs" do
14
+ @uuid.timestamp.should < Time.stamp
15
+ end
16
+
17
+ it "serializes to bytes" do
18
+ expected_bytes = [@uuid.timestamp >> 32,
19
+ @uuid.timestamp & 0xffffffff,
20
+ @uuid.worker_id >> 32,
21
+ @uuid.worker_id & 0xffffffff].pack("NNNN")
22
+ @uuid.to_bytes.should == expected_bytes
23
+ end
24
+ end
25
+
26
+ describe "reinitializing the uuid from bytes" do
27
+ describe "with a correctly sized byte array" do
28
+ before do
29
+ @bytes = [1234567890 >> 32,
30
+ 1234567890 & 0xffffffff,
31
+ 9876543210 >> 32,
32
+ 9876543210 & 0xffffffff].pack("NNNN")
33
+ @uuid = LexicalUUID.new(@bytes)
34
+ end
35
+
36
+ it "correctly extracts the timestamp" do
37
+ @uuid.timestamp.should == 1234567890
38
+ end
39
+
40
+ it "correctly extracts the worker id" do
41
+ @uuid.worker_id.should == 9876543210
42
+ end
43
+ end
44
+
45
+ describe "with a mis-sized byte array" do
46
+ it "raises ArgumentError" do
47
+ lambda {
48
+ LexicalUUID.new("asdf")
49
+ }.should raise_error(ArgumentError)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "initializing a uuid from a timestamp and worker_id" do
55
+ before do
56
+ @timestamp = 15463021018891620831
57
+ @worker_id = 9964740229835689317
58
+ @uuid = LexicalUUID.new(@timestamp, @worker_id)
59
+ end
60
+
61
+ it "sets the timestamp" do
62
+ @uuid.timestamp.should == @timestamp
63
+ end
64
+
65
+ it "sets the worker_id" do
66
+ @uuid.worker_id.should == @worker_id
67
+ end
68
+ end
69
+
70
+ describe "converting a uuid in to a guid" do
71
+ before do
72
+ @uuid = LexicalUUID.new(15463021018891620831, 9964740229835689317)
73
+ end
74
+
75
+ it "matches other uuid->guid implementations" do
76
+ @uuid.to_guid.should == "d697afb0-a96f-11df-8a49-de718e668d65"
77
+ end
78
+ end
79
+
80
+ describe "initializing from a guid" do
81
+ before do
82
+ @uuid = LexicalUUID.new("d697afb0-a96f-11df-8a49-de718e668d65")
83
+ end
84
+
85
+ it "correctly initializes the timestamp" do
86
+ @uuid.timestamp.should == 15463021018891620831
87
+ end
88
+
89
+ it "correctly initializes the worker_id" do
90
+ @uuid.worker_id.should == 9964740229835689317
91
+ end
92
+ end
93
+
94
+ describe "initializing with a timestamp with no worker_id" do
95
+ before do
96
+ @uuid = LexicalUUID.new(12345)
97
+ end
98
+
99
+ it "sets the timestamp" do
100
+ @uuid.timestamp.should == 12345
101
+ end
102
+
103
+ it "uses the default worker_id" do
104
+ @uuid.worker_id.should == LexicalUUID.worker_id
105
+ end
106
+ end
107
+
108
+ describe "comparing uuids" do
109
+ it "compares first by timestamp" do
110
+ (LexicalUUID.new(123) <=> LexicalUUID.new(234)).should == -1
111
+ (LexicalUUID.new(223) <=> LexicalUUID.new(134)).should == 1
112
+ end
113
+
114
+ it "compares by worker_id if the timestamps are equal" do
115
+ (LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 2)).should == -1
116
+ (LexicalUUID.new(123, 2) <=> LexicalUUID.new(123, 1)).should == 1
117
+ (LexicalUUID.new(123, 1) <=> LexicalUUID.new(123, 1)).should == 0
118
+ end
119
+ end
120
+
121
+ describe "==" do
122
+ it "is equal when the timestamps and worker ids are equal" do
123
+ LexicalUUID.new(123, 123).should == LexicalUUID.new(123, 123)
124
+ end
125
+
126
+ it "is not equal when the timestamps are not equal" do
127
+ LexicalUUID.new(223, 123).should_not == LexicalUUID.new(123, 123)
128
+ end
129
+
130
+ it "is not equal when the worker_ids are not equal" do
131
+ LexicalUUID.new(123, 223).should_not == LexicalUUID.new(123, 123)
132
+ end
133
+ end
134
+
135
+ describe "eql?" do
136
+ it "is equal when the timestamps and worker ids are equal" do
137
+ LexicalUUID.new(123, 123).should eql(LexicalUUID.new(123, 123))
138
+ end
139
+
140
+ it "is not equal when the timestamps are not equal" do
141
+ LexicalUUID.new(223, 123).should_not eql(LexicalUUID.new(123, 123))
142
+ end
143
+
144
+ it "is not equal when the worker_ids are not equal" do
145
+ LexicalUUID.new(123, 223).should_not eql(LexicalUUID.new(123, 123))
146
+ end
147
+ end
148
+
149
+ describe "hash" do
150
+ it "has the same hash if the timestamp/worker_id are the same" do
151
+ LexicalUUID.new(123, 123).hash.should == LexicalUUID.new(123, 123).hash
152
+ end
153
+
154
+ it "has a different hash when the timestamps are different" do
155
+ LexicalUUID.new(223, 123).hash.should_not == LexicalUUID.new(123, 123).hash
156
+ end
157
+
158
+ it "has a different hash when the worker_ids are not equalc" do
159
+ LexicalUUID.new(123, 223).hash.should_not == LexicalUUID.new(123, 123).hash
160
+ end
161
+ end
162
+
163
+ describe "initializing with a time object" do
164
+ before do
165
+ @time = Time.now
166
+ @uuid = LexicalUUID.new(@time)
167
+ end
168
+
169
+ it "uses the time's stamp object" do
170
+ @uuid.timestamp.should == @time.stamp
171
+ end
172
+ end
173
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'lexical_uuid'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lexical_uuid
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - James Golick
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-16 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 2
33
+ - 9
34
+ version: 1.2.9
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: RubyInline
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ hash: 47
46
+ segments:
47
+ - 3
48
+ - 8
49
+ - 4
50
+ version: 3.8.4
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.
54
+ email: jamesgolick@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - LICENSE
61
+ - README.rdoc
62
+ files:
63
+ - .document
64
+ - .gitignore
65
+ - LICENSE
66
+ - README.rdoc
67
+ - Rakefile
68
+ - VERSION
69
+ - lib/lexical_uuid.rb
70
+ - spec/lexical_uuid_spec.rb
71
+ - spec/spec.opts
72
+ - spec/spec_helper.rb
73
+ has_rdoc: true
74
+ homepage: http://github.com/jamesgolick/lexical_uuid
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --charset=UTF-8
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 3
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.7
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: UUIDs that are byte-ordered lamport clocks (timestamp, worker_id). Much simpler than type-1 UUID's crappy, weirdo layout.
107
+ test_files:
108
+ - spec/lexical_uuid_spec.rb
109
+ - spec/spec_helper.rb