Skip to content

Commit

Permalink
Merge pull request #12 from recurly/TPE-1055
Browse files Browse the repository at this point in the history
Add method to return the lowest druuid for a time
  • Loading branch information
drewish authored Jan 13, 2017
2 parents 9a5da12 + 5a07ed5 commit 86faf0f
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
vendor
.bundle
5 changes: 4 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
druuid (1.0.1)
druuid (1.0.2)

GEM
remote: https://rubygems.org/
Expand All @@ -24,3 +24,6 @@ DEPENDENCIES
druuid!
rake
rspec

BUNDLED WITH
1.11.2
4 changes: 3 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ require 'druuid'

uuid = Druuid.gen
# => 11142943683383068069
Druuid.time uuid
time = Druuid.time uuid
# => 2012-02-04 00:00:00 -0800
Druuid.min_for_time time
# => 11142943683379200000
```


Expand Down
2 changes: 1 addition & 1 deletion druuid.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = 'druuid'
s.version = '1.0.1'
s.version = '1.0.2'
s.summary = 'Date-relative UUID generation'
s.description = 'Druuid generates 64-bit, time-sortable UUIDs.'

Expand Down
20 changes: 17 additions & 3 deletions druuid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#
# Date-relative UUID generation.
module Druuid
NUM_RANDOM_BITS = 64 - 41

class << self

Expand All @@ -21,8 +22,8 @@ class << self
def gen time = Time.now, epoch_offset = epoch
ms = ((time.to_f - epoch_offset.to_i) * 1e3).round
rand = (SecureRandom.random_number * 1e16).round
id = ms << (64 - 41)
id | rand % (2 ** (64 - 41))
id = ms << NUM_RANDOM_BITS
id | rand % (2 ** NUM_RANDOM_BITS)
end

# Determines when a given UUID was generated.
Expand All @@ -34,10 +35,23 @@ def gen time = Time.now, epoch_offset = epoch
# Druuid.time 11142943683383068069
# # => 2012-02-04 00:00:00 -0800
def time uuid, epoch_offset = epoch
ms = uuid >> (64 - 41)
ms = uuid >> NUM_RANDOM_BITS
Time.at(ms / 1e3) + epoch_offset.to_i
end

# Determines the minimum UUID that could be generated for the given time.
#
# @param [Time] time of UUID
# @param [Numeric] epoch offset
# @return [Bignum] UUID
# @example
# Druuid.min_for_time
# # => 11142943683379200000
def min_for_time time = Time.now, epoch_offset = epoch
ms = ((time.to_f - epoch_offset.to_i) * 1e3).round
ms << NUM_RANDOM_BITS
end

end

end
39 changes: 29 additions & 10 deletions spec/druuid_spec.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
require_relative '../druuid'

describe Druuid do
describe '.gen' do
it 'generates a UUID' do
uuid = Druuid.gen
uuid.should be_instance_of Bignum
uuid.should_not eq Druuid.gen
end

shared_examples "druuid generator" do |method|
let(:datetime) { Time.utc 2012, 2, 4, 8 }
let(:prefix) { '111429436833' }

it "is a Bugnum" do
Druuid.send(method).should be_instance_of Bignum
end

context 'with a given time' do
it 'generates the UUID against the time' do
Druuid.gen(datetime).to_s[0, 12].should eq prefix
Druuid.send(method, datetime).to_s[0, 12].should eq prefix
end
end

let(:offset) { 60 * 60 * 24 }
context 'with a given epoch' do
it 'generates the UUID against the offset' do
Druuid.gen(datetime + offset, offset).to_s[0, 12].should eq prefix
Druuid.send(method, datetime + offset, offset).to_s[0, 12].should eq prefix
end
end

context 'with a default epoch' do
before { @old_epoch, Druuid.epoch = Druuid.epoch, offset }
it 'generates the UUID against the offset' do
Druuid.gen(datetime + offset).to_s[0, 12].should eq prefix
Druuid.send(method, datetime + offset).to_s[0, 12].should eq prefix
end
after { Druuid.epoch = @old_epoch }
end
end


describe '.gen' do
it_behaves_like 'druuid generator', :gen

it 'generates a UUID' do
uuid = Druuid.gen
uuid.should_not eq Druuid.gen
end
end

describe '.time' do
let(:datetime) { Time.utc 2012, 2, 4, 8 }
let(:uuid) { 11142943683383068069 }
Expand All @@ -54,4 +63,14 @@
after { Druuid.epoch = @old_epoch }
end
end

describe '.min_for_time' do
it_behaves_like 'druuid generator', :min_for_time

let(:datetime) { Time.utc 2012, 2, 4, 8 }
it 'generates druuid without random bits' do
random_bits = Druuid.min_for_time(Time.now) & Integer("0b" + ("1" * Druuid::NUM_RANDOM_BITS))
random_bits.should be_zero
end
end
end

0 comments on commit 86faf0f

Please sign in to comment.