diff --git a/lib/ulid.rb b/lib/ulid.rb index eea7464..6bce566 100644 --- a/lib/ulid.rb +++ b/lib/ulid.rb @@ -1,13 +1,14 @@ +# frozen_string_literal: true -require 'time' -require 'securerandom' +require "time" +require "securerandom" -require 'ulid/version' -require 'ulid/constants' -require 'ulid/identifier' -require 'ulid/generate' -require 'ulid/parse' -require 'ulid/compare' +require "ulid/version" +require "ulid/constants" +require "ulid/identifier" +require "ulid/generate" +require "ulid/parse" +require "ulid/compare" module ULID include Constants @@ -81,6 +82,4 @@ def self.min_ulid_at(at_time) def self.max_ulid_at(at_time) Identifier.new(at_time, MAX_ENTROPY).ulid end - end - diff --git a/lib/ulid/compare.rb b/lib/ulid/compare.rb index 33acb5b..0ac969b 100644 --- a/lib/ulid/compare.rb +++ b/lib/ulid/compare.rb @@ -1,35 +1,37 @@ +# frozen_string_literal: true + module ULID module Compare def >(other) case other when self.class - self.ulid > other.ulid + ulid > other.ulid when Time - self.time > other + time > other when String - self.ulid > other + ulid > other end end def <(other) case other when self.class - self.ulid < other.ulid + ulid < other.ulid when Time - self.time < other + time < other when String - self.ulid < other + ulid < other end end def <=>(other) case other when self.class - self.ulid <=> other.ulid + ulid <=> other.ulid when Time - self.time <=> other + time <=> other when String - self.ulid <=> other + ulid <=> other end end end diff --git a/lib/ulid/constants.rb b/lib/ulid/constants.rb index 79d8d25..9d05589 100644 --- a/lib/ulid/constants.rb +++ b/lib/ulid/constants.rb @@ -3,14 +3,14 @@ module ULID module Constants # smallest representable time - MIN_TIME = ([0] * 6).pack('C' * 6) + MIN_TIME = ([0] * 6).pack("C" * 6) # largest representable time - MAX_TIME = ([255] * 6).pack('C' * 6) + MAX_TIME = ([255] * 6).pack("C" * 6) # smallest possible seed value - MIN_ENTROPY = ([0] * 10).pack('C' * 10) + MIN_ENTROPY = ([0] * 10).pack("C" * 10) # largest possible seed value - MAX_ENTROPY = ([255] * 10).pack('C' * 10) + MAX_ENTROPY = ([255] * 10).pack("C" * 10) # Crockford's Base32 (https://www.crockford.com/base32.html) Differs from Base32 in the following ways: # * Excludes I, L, O and U diff --git a/lib/ulid/generate.rb b/lib/ulid/generate.rb index 5f6c979..338f320 100644 --- a/lib/ulid/generate.rb +++ b/lib/ulid/generate.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'securerandom' -require 'ulid/constants' +require "securerandom" +require "ulid/constants" module ULID module Generate @@ -24,11 +24,11 @@ def encode32 # returns the binary uint128 in base16 UUID format def encode16 - self.bytes.unpack("H8H4H4H4H*").join("-") + bytes.unpack("H8H4H4H4H*").join("-") end def encode10 - (hi, lo) = self.bytes.unpack('Q>Q>') + (hi, lo) = bytes.unpack("Q>Q>") (hi << 64) | lo end diff --git a/lib/ulid/identifier.rb b/lib/ulid/identifier.rb index 7180812..7bc6520 100644 --- a/lib/ulid/identifier.rb +++ b/lib/ulid/identifier.rb @@ -1,6 +1,8 @@ -require 'ulid/parse' -require 'ulid/generate' -require 'ulid/compare' +# frozen_string_literal: true + +require "ulid/parse" +require "ulid/generate" +require "ulid/compare" module ULID class Identifier @@ -25,13 +27,14 @@ def initialize(start = nil, seed = nil) @time = start.time @seed = start.seed when NilClass, Time - @time = (start || Time.now).utc - if seed == nil + @time = start || Time.now + if seed.nil? @seed = random_bytes else if seed.size != 10 || seed.encoding != Encoding::ASCII_8BIT - raise ArgumentError.new("seed error, seed value must be 10 bytes encoded as Encoding::ASCII_8BIT") + raise ArgumentError, "seed error, seed value must be 10 bytes encoded as Encoding::ASCII_8BIT" end + @seed = seed end when String @@ -47,24 +50,24 @@ def initialize(start = nil, seed = nil) # parse UUID string into bytes @bytes = decode16(start) else - raise ArgumentError.new("invalid ULID or UUID string - must be 16, 26, or 36 characters") + raise ArgumentError, "invalid ULID or UUID string - must be 16, 26, or 36 characters" end - raise ArgumentError.new("invalid ULID or UUID") if @bytes.size != 16 + raise ArgumentError, "invalid ULID or UUID" if @bytes.size != 16 @time, @seed = unpack_decoded_bytes(@bytes) when Integer # parse integer (BigNum) into bytes @bytes = decode10(start) - raise ArgumentError.new("invalid ULID or UUID") if @bytes.size != 16 + raise ArgumentError, "invalid ULID or UUID" if @bytes.size != 16 @time, @seed = unpack_decoded_bytes(@bytes) when Array # parse Array(16) into bytes @bytes = start.pack("C*") - raise ArgumentError.new("invalid Byte Array") if @bytes.size != 16 + raise ArgumentError, "invalid Byte Array" if @bytes.size != 16 @time, @seed = unpack_ulid_bytes(@bytes) else diff --git a/spec/ulid_spec.rb b/spec/ulid_spec.rb index 45eb7ea..8ddc4e8 100644 --- a/spec/ulid_spec.rb +++ b/spec/ulid_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" # time seed @@ -12,265 +14,261 @@ describe ULID do it "has a version number" do - expect(ULID::VERSION).not_to be nil + expect(ULID::VERSION).not_to(be(nil)) end - describe '.generate' do + describe ".generate" do it "produces ULID strings" do - expect(ULID.generate).to be_a_valid_ulid + expect(ULID.generate).to(be_a_valid_ulid) end end - describe '.at' do - - it 'produces randomized ULID strings for a given time' do - expect(ULID.at(KNOWN_TIME)).to be_a_valid_ulid + describe ".at" do + it "produces randomized ULID strings for a given time" do + expect(ULID.at(KNOWN_TIME)).to(be_a_valid_ulid) end - it 'handles timestamp as the milliseconds precision' do - expect(ULID.at(Time.parse('2016-07-30 22:36:16.001000000 UTC'))).to start_with('01ARYZ6RR1') - expect(ULID.at(Time.parse('2016-07-30 22:36:16.002000001 UTC'))).to(start_with('01ARYZ6RR2')) # leap nanosecond - expect(ULID.at(Time.parse('2016-07-30 22:36:16.003000000 UTC'))).to start_with('01ARYZ6RR3') + it "handles timestamp as the milliseconds precision" do + expect(ULID.at(Time.parse("2016-07-30 22:36:16.001000000 UTC"))).to(start_with("01ARYZ6RR1")) + expect(ULID.at(Time.parse("2016-07-30 22:36:16.002000001 UTC"))).to(start_with("01ARYZ6RR2")) # leap nanosecond + expect(ULID.at(Time.parse("2016-07-30 22:36:16.003000000 UTC"))).to(start_with("01ARYZ6RR3")) end - end - describe '.time' do + describe ".time" do let(:ulid_time) { ULID.time(KNOWN_STRING) } - it 'returns Time object' do - expect(ulid_time).to be_instance_of(Time) + it "returns Time object" do + expect(ulid_time).to(be_instance_of(Time)) end - it 'returns same time that was used to generate it' do - expect(ulid_time).to eq(KNOWN_TIME) + it "returns same time that was used to generate it" do + expect(ulid_time).to(eq(KNOWN_TIME)) end - it 'handles timestamp as the milliseconds precision' do - time = ULID.time('0A000000000000000000000000') - expect(time.to_i).to eq(10995116277) + it "handles timestamp as the milliseconds precision" do + time = ULID.time("0A000000000000000000000000") + expect(time.to_i).to(eq(10995116277)) # ULID precision is only to the millisecond value. Some parses will infer leap nanoseconds - expect(time.nsec).to be_within(1000).of(760000000) + expect(time.nsec).to(be_within(1000).of(760000000)) end end - describe '.min_ulid_at' do + describe ".min_ulid_at" do let(:ulid_string) { ULID.min_ulid_at(KNOWN_TIME) } - it 'generates a valid ULID string' do - expect(ulid_string).to be_a_valid_ulid - expect(ulid_string).to be_instance_of(String) + it "generates a valid ULID string" do + expect(ulid_string).to(be_a_valid_ulid) + expect(ulid_string).to(be_instance_of(String)) end - it 'generates the lowest lexicographical ULID' do - expect(ulid_string).to match(/0000000000000000$/) + it "generates the lowest lexicographical ULID" do + expect(ulid_string).to(match(/0000000000000000$/)) end end - describe '.max_ulid_at' do + describe ".max_ulid_at" do let(:ulid_string) { ULID.max_ulid_at(KNOWN_TIME) } - it 'generates a valid ULID string' do - expect(ulid_string).to be_a_valid_ulid - expect(ulid_string).to be_instance_of(String) + it "generates a valid ULID string" do + expect(ulid_string).to(be_a_valid_ulid) + expect(ulid_string).to(be_instance_of(String)) end - it 'generates the highest lexicographical ULID' do - expect(ulid_string).to match(/ZZZZZZZZZZZZZZZZ$/) + it "generates the highest lexicographical ULID" do + expect(ulid_string).to(match(/ZZZZZZZZZZZZZZZZ$/)) end end - describe '.uuid' do - it 'generates a valid UUID' do - ulid = ULID.new KNOWN_STRING - expect(ulid.uuid).to eq(KNOWN_UUID) + describe ".uuid" do + it "generates a valid UUID" do + ulid = ULID.new(KNOWN_STRING) + expect(ulid.uuid).to(eq(KNOWN_UUID)) end end - describe '.bytes' do - it 'from a valid UUID' do - ulid = ULID.new KNOWN_UUID - expect(ulid.bytes).to eq(KNOWN_BYTES) + describe ".bytes" do + it "from a valid UUID" do + ulid = ULID.new(KNOWN_UUID) + expect(ulid.bytes).to(eq(KNOWN_BYTES)) end end - describe ULID::Identifier do - context 'with no initialization value' do - it 'generates a random value for the current time' do + context "with no initialization value" do + it "generates a random value for the current time" do right_now = Time.now ulid = ULID.new - expect(ulid.ulid).to be_instance_of(String) - expect(ulid.ulid).to be_a_valid_ulid - expect(ulid.time).to be_within(0.001).of(right_now) + expect(ulid.ulid).to(be_instance_of(String)) + expect(ulid.ulid).to(be_a_valid_ulid) + expect(ulid.time).to(be_within(0.001).of(right_now)) end end - context 'with Time' do - it 'generates a ULID for that time' do + context "with Time" do + it "generates a ULID for that time" do right_now = Time.now ulid = ULID.new(right_now) - expect(ulid.ulid).to be_instance_of(String) - expect(ulid.ulid).to be_a_valid_ulid - expect(ulid.time).to be_within(0.001).of(right_now) + expect(ulid.ulid).to(be_instance_of(String)) + expect(ulid.ulid).to(be_a_valid_ulid) + expect(ulid.time).to(be_within(0.001).of(right_now)) end end - context 'with ULID::Instance' do - it 'generates the same ULID' do + context "with ULID::Instance" do + it "generates the same ULID" do first = ULID.new other = ULID.new(first) - expect(other.ulid).to eq(first.ulid) - expect(other.time).to eq(first.time) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) + expect(other.ulid).to(eq(first.ulid)) + expect(other.time).to(eq(first.time)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) end end - context 'with ULID string arg' do - it 'generates to same ULID' do + context "with ULID string arg" do + it "generates to same ULID" do first = ULID.new other = ULID.new(first.ulid) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) # same caveat as "returns the same time" note above - expect(other.time).to be_within(0.001).of(first.time) + expect(other.time).to(be_within(0.001).of(first.time)) end - it 'generates with lowercase alphabet' do - first = ULID.new KNOWN_STRING - other = ULID.new KNOWN_STRING.downcase + it "generates with lowercase alphabet" do + first = ULID.new(KNOWN_STRING) + other = ULID.new(KNOWN_STRING.downcase) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to eq(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(eq(first.time)) end - it 'raises an error for invalid ULID string' do - expect { ULID.new("not a valid ULID!") }.to raise_error(ArgumentError) - expect { ULID.new("") }.to raise_error(ArgumentError) - expect { ULID.new(KNOWN_STRING + KNOWN_STRING) }.to raise_error(ArgumentError) + it "raises an error for invalid ULID string" do + expect { ULID.new("not a valid ULID!") }.to(raise_error(ArgumentError)) + expect { ULID.new("") }.to(raise_error(ArgumentError)) + expect { ULID.new(KNOWN_STRING + KNOWN_STRING) }.to(raise_error(ArgumentError)) end end - context 'with Bytes string arg' do - it 'supports byteform' do + context "with Bytes string arg" do + it "supports byteform" do first = ULID.new - other = ULID.new first.bytes + other = ULID.new(first.bytes) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to be_within(0.001).of(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(be_within(0.001).of(first.time)) end end - context 'with UUID string arg' do - it 'supports UUID' do - first = ULID.new KNOWN_UUID - other = ULID.new KNOWN_STRING + context "with UUID string arg" do + it "supports UUID" do + first = ULID.new(KNOWN_UUID) + other = ULID.new(KNOWN_STRING) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to eq(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(eq(first.time)) end - it 'supports UUID case insensitive' do - first = ULID.new KNOWN_UUID.downcase - other = ULID.new KNOWN_UUID.upcase + it "supports UUID case insensitive" do + first = ULID.new(KNOWN_UUID.downcase) + other = ULID.new(KNOWN_UUID.upcase) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to eq(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(eq(first.time)) end - it 'supports UUID self generated' do + it "supports UUID self generated" do first = ULID.new - other = ULID.new first.uuid + other = ULID.new(first.uuid) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to be_within(0.001).of(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(be_within(0.001).of(first.time)) end end - context 'with uInt128 arg' do - it 'supports BigNum' do + context "with uInt128 arg" do + it "supports BigNum" do first = ULID.new - other = ULID.new first.int128 + other = ULID.new(first.int128) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to be_within(0.001).of(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(be_within(0.001).of(first.time)) end - it 'supports BigNum self generated' do - first = ULID.new KNOWN_UINT128 - other = ULID.new KNOWN_STRING + it "supports BigNum self generated" do + first = ULID.new(KNOWN_UINT128) + other = ULID.new(KNOWN_STRING) - expect(other.ulid).to eq(first.ulid) - expect(other.seed).to eq(first.seed) - expect(other.bytes).to eq(first.bytes) - expect(other.time).to eq(first.time) + expect(other.ulid).to(eq(first.ulid)) + expect(other.seed).to(eq(first.seed)) + expect(other.bytes).to(eq(first.bytes)) + expect(other.time).to(eq(first.time)) end end - describe 'compared to other ULIDs' do + describe "compared to other ULIDs" do let(:at_time) { Time.now } let(:first) { ULID.new(at_time - 5) } let(:last) { ULID.new(at_time) } - it 'is sortable with <' do - expect(first).to be < last - expect(first).to be < last.ulid - expect(first).to be < last.time + it "is sortable with <" do + expect(first).to(be < last) + expect(first).to(be < last.ulid) + expect(first).to(be < last.time) end - it 'is sortable with >' do - expect(last).to be > first - expect(last).to be > first.ulid - expect(last).to be > first.time + it "is sortable with >" do + expect(last).to(be > first) + expect(last).to(be > first.ulid) + expect(last).to(be > first.time) end - it 'is sortable in a list' do + it "is sortable in a list" do reverse = [last, first] - expect(reverse[0]).not_to be(first) - expect(reverse.sort[0]).to be(first) + expect(reverse[0]).not_to(be(first)) + expect(reverse.sort[0]).to(be(first)) end - it 'sorts the same as strings' do + it "sorts the same as strings" do # get reverse list of ULID instances reverse = [last, first] # ... and reversed list of ULID strings ulids = [last.ulid, first.ulid] - ulids.each {|u| - expect(u).to be_instance_of(String) - expect(u).to be_a_valid_ulid - } + ulids.each do |u| + expect(u).to(be_instance_of(String)) + expect(u).to(be_a_valid_ulid) + end # compare both when sorted ulids_sorted = reverse.sort.map(&:ulid) strings_sorted = ulids.sort ulids_sorted.zip(strings_sorted).each do |(a, b)| - expect(a).to eq(b) + expect(a).to(eq(b)) end end end end - end