-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from matic-insurance/feature/configuration_inte…
…rface Singleton Interface
- Loading branch information
Showing
10 changed files
with
214 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,5 +11,4 @@ deploy: | |
provider: rubygems | ||
api_key: "$RUBY_GEMS_API_KEY" | ||
on: | ||
branch: master | ||
tags: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,22 @@ | ||
require 'securerandom' | ||
|
||
class IdGenerator | ||
VERSION = '0.1.2'.freeze | ||
|
||
COUNTER_PART_SIZE = 8 | ||
CONTEXT_PART_SIZE = 2 | ||
|
||
RANDOM_PART_BYTES = 11 | ||
COUNTER_START = Time.new(2000).to_i | ||
|
||
class Error < StandardError | ||
end | ||
|
||
def initialize(context_id) | ||
raise(IdGenerator::Error, 'Invalid project id') unless context_id_valid?(context_id) | ||
|
||
@context_id = value_to_hex(context_id, CONTEXT_PART_SIZE) | ||
end | ||
|
||
def generate | ||
"#{time}-#{@context_id}-#{random_number}" | ||
end | ||
|
||
private | ||
|
||
def context_id_valid?(context_id) | ||
return false unless context_id.is_a?(Integer) | ||
return false unless context_id.between?(0, 255) | ||
|
||
true | ||
require 'id_generator/version' | ||
require 'id_generator/configuration' | ||
require 'id_generator/errors' | ||
require 'id_generator/generators/timestamped_random' | ||
|
||
module IdGenerator | ||
def self.configure | ||
yield(configuration) | ||
end | ||
|
||
def time | ||
timestamp = Time.now.to_i - COUNTER_START | ||
value_to_hex(timestamp, COUNTER_PART_SIZE) | ||
def self.generate | ||
id_generator.generate | ||
end | ||
|
||
def random_number | ||
SecureRandom.hex(RANDOM_PART_BYTES) | ||
def self.configuration | ||
@configuration ||= Configuration.new | ||
end | ||
|
||
def value_to_hex(value, size) | ||
format("%0#{size}x", value) | ||
def self.id_generator | ||
@id_generator ||= IdGenerator::Generators::TimestampedRandom.new(configuration) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module IdGenerator | ||
class Configuration | ||
attr_reader :context_id | ||
|
||
def initialize(context_id: 0) | ||
self.context_id = context_id | ||
end | ||
|
||
def context_id=(context_id) | ||
raise(IdGenerator::Errors::InvalidContextId, 'Invalid context id') unless context_id_valid?(context_id) | ||
|
||
@context_id = context_id | ||
end | ||
|
||
protected | ||
|
||
def context_id_valid?(context_id) | ||
return false unless context_id.is_a?(Integer) | ||
return false unless context_id.between?(0, 255) | ||
|
||
true | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module IdGenerator | ||
module Errors | ||
class InvalidContextId < StandardError | ||
# Just empty line to trick codacy | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
require 'securerandom' | ||
|
||
module IdGenerator | ||
module Generators | ||
class TimestampedRandom | ||
COUNTER_PART_SIZE = 8 | ||
CONTEXT_PART_SIZE = 2 | ||
|
||
RANDOM_PART_BYTES = 11 | ||
COUNTER_START = Time.new(2000).to_i | ||
|
||
attr_reader :config | ||
|
||
def initialize(config) | ||
@config = config | ||
end | ||
|
||
def generate | ||
"#{time}-#{context_id}-#{random_number}" | ||
end | ||
|
||
private | ||
|
||
def time | ||
timestamp = Time.now.to_i - COUNTER_START | ||
value_to_hex(timestamp, COUNTER_PART_SIZE) | ||
end | ||
|
||
def context_id | ||
value_to_hex(config.context_id, CONTEXT_PART_SIZE) | ||
end | ||
|
||
def random_number | ||
SecureRandom.hex(RANDOM_PART_BYTES) | ||
end | ||
|
||
def value_to_hex(value, size) | ||
format("%0#{size}x", value) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module IdGenerator | ||
VERSION = '0.1.2'.freeze | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
require 'spec_helper' | ||
|
||
RSpec.describe IdGenerator::Configuration do | ||
describe '#context_id' do | ||
let(:configuration) { described_class.new(context_id: context_id) } | ||
let(:context_id) { rand(255) } | ||
|
||
it 'returns initialized value' do | ||
expect(configuration.context_id).to eq(context_id) | ||
end | ||
|
||
describe 'validation' do | ||
let(:error) { IdGenerator::Errors::InvalidContextId } | ||
|
||
it 'allows empty' do | ||
expect { described_class.new }.not_to raise_error | ||
end | ||
|
||
it 'allows 0' do | ||
expect { described_class.new(context_id: 0) }.not_to raise_error | ||
end | ||
|
||
it 'allows 255' do | ||
expect { described_class.new(context_id: 255) }.not_to raise_error | ||
end | ||
|
||
it 'rejects negative values' do | ||
expect { described_class.new(context_id: -1) }.to raise_error(error, 'Invalid context id') | ||
end | ||
|
||
it 'rejects large values' do | ||
expect { described_class.new(context_id: rand(256..1000)) }.to raise_error(error, 'Invalid context id') | ||
end | ||
|
||
it 'rejects empty values' do | ||
expect { described_class.new(context_id: nil) }.to raise_error(error, 'Invalid context id') | ||
end | ||
|
||
it 'rejects invalid values' do | ||
expect { described_class.new(context_id: 'id') }.to raise_error(error, 'Invalid context id') | ||
end | ||
end | ||
end | ||
end |
55 changes: 55 additions & 0 deletions
55
spec/lib/id_generator/generators/timestamped_random_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
RSpec.describe IdGenerator::Generators::TimestampedRandom do | ||
let(:generator) { described_class.new(configuration) } | ||
let(:context_id) { rand(255) } | ||
let(:configuration) { IdGenerator::Configuration.new(context_id: context_id) } | ||
|
||
describe 'id format' do | ||
let(:parts) { uniq_id.split('-') } | ||
|
||
it 'has correct size' do | ||
expect(uniq_id.size).to eq(34) | ||
end | ||
|
||
it 'has correct format' do | ||
expect(uniq_id).to match(/^[a-z0-9\-]+$/) | ||
end | ||
|
||
it 'has 2 separators' do | ||
expect(parts.size).to eq(3) | ||
end | ||
|
||
it 'has correct timestamp size' do | ||
expect(parts[0].size).to eq(8) | ||
end | ||
|
||
it 'has correct project id size' do | ||
expect(parts[1].size).to eq(2) | ||
end | ||
|
||
it 'has correct random part size' do | ||
expect(parts[2].size).to eq(22) | ||
end | ||
|
||
it 'includes timestamp' do | ||
timestamp = Time.now.to_i - Time.new(2000).to_i | ||
id_timestamp = uniq_id.split('-').first.to_i(16) | ||
expect(id_timestamp).to be_between(timestamp, timestamp + 2) | ||
end | ||
|
||
it 'include project id' do | ||
expect(uniq_id).to include(format('-%02x-', context_id)) | ||
end | ||
end | ||
|
||
describe '#generate' do | ||
it 'generates random id every time' do | ||
expect(uniq_id).not_to eq(uniq_id) | ||
end | ||
end | ||
|
||
protected | ||
|
||
def uniq_id | ||
generator.generate | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,43 @@ | ||
RSpec.describe IdGenerator do | ||
let(:generator) { described_class.new(context_id) } | ||
let(:context_id) { rand(255) } | ||
let(:context_error) { IdGenerator::Errors::InvalidContextId } | ||
|
||
describe 'id format' do | ||
let(:parts) { uniq_id.split('-') } | ||
after { described_class.configuration.context_id = 0 } | ||
|
||
it 'has correct size' do | ||
expect(uniq_id.size).to eq(34) | ||
end | ||
|
||
it 'has correct format' do | ||
expect(uniq_id).to match(/^[a-z0-9\-]+$/) | ||
end | ||
|
||
it 'has 2 separators' do | ||
expect(parts.size).to eq(3) | ||
end | ||
|
||
it 'has correct timestamp size' do | ||
expect(parts[0].size).to eq(8) | ||
end | ||
|
||
it 'has correct project id size' do | ||
expect(parts[1].size).to eq(2) | ||
end | ||
|
||
it 'has correct random part size' do | ||
expect(parts[2].size).to eq(22) | ||
end | ||
|
||
it 'includes timestamp' do | ||
timestamp = Time.now.to_i - Time.new(2000).to_i | ||
id_timestamp = uniq_id.split('-').first.to_i(16) | ||
expect(id_timestamp).to be_between(timestamp, timestamp + 2) | ||
describe '#generate' do | ||
it 'generates random id every time' do | ||
expect(uniq_id).not_to eq(uniq_id) | ||
end | ||
|
||
it 'include project id' do | ||
expect(uniq_id).to include(format('-%02x-', context_id)) | ||
it 'using default context id' do | ||
expect(uniq_id).to include('-00-') | ||
end | ||
end | ||
|
||
describe 'context_id' do | ||
it 'allows 0' do | ||
expect { described_class.new(0) }.not_to raise_error | ||
end | ||
|
||
it 'allows 255' do | ||
expect { described_class.new(255) }.not_to raise_error | ||
describe '#configure' do | ||
it 'setting context id' do | ||
described_class.configure { |c| c.context_id = 15 } | ||
expect(uniq_id).to include('-0f-') | ||
end | ||
|
||
it 'rejects negative values' do | ||
expect { described_class.new(-1) }.to raise_error(IdGenerator::Error, 'Invalid project id') | ||
end | ||
|
||
it 'rejects large values' do | ||
expect { described_class.new(rand(256..1000)) }.to raise_error(IdGenerator::Error, 'Invalid project id') | ||
end | ||
|
||
it 'rejects empty values' do | ||
expect { described_class.new(nil) }.to raise_error(IdGenerator::Error, 'Invalid project id') | ||
it 'validating context id' do | ||
expect { described_class.configure { |c| c.context_id = -1 } }.to raise_error(context_error) | ||
end | ||
end | ||
|
||
it 'rejects invalid values' do | ||
expect { described_class.new('id') }.to raise_error(IdGenerator::Error, 'Invalid project id') | ||
describe '#configuration' do | ||
it 'setting context id' do | ||
described_class.configuration.context_id = 15 | ||
expect(uniq_id).to include('-0f-') | ||
end | ||
end | ||
|
||
describe '#generate' do | ||
it 'generates random id every time' do | ||
expect(uniq_id).not_to eq(uniq_id) | ||
it 'validating context id' do | ||
expect { described_class.configuration.context_id = -1 }.to raise_error(context_error) | ||
end | ||
end | ||
|
||
protected | ||
|
||
def uniq_id | ||
generator.generate | ||
described_class.generate | ||
end | ||
end |