From efaebcf0a6df669ca4a999c85fd95c20f17122bf Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Fri, 20 Sep 2024 12:33:43 -0400 Subject: [PATCH] Add uuid v7 support --- CHANGELOG.md | 2 + Gemfile.lock | 2 +- README.md | 3 +- lib/lite/uxid.rb | 4 +- lib/lite/uxid/base/irreversible.rb | 78 ++++++++++++++++++++++++++++++ lib/lite/uxid/base/reversible.rb | 36 ++++++++++++++ lib/lite/uxid/configuration.rb | 6 ++- lib/lite/uxid/hashid.rb | 2 +- lib/lite/uxid/irreversible.rb | 71 --------------------------- lib/lite/uxid/nanoid.rb | 2 +- lib/lite/uxid/reversible.rb | 34 ------------- lib/lite/uxid/ulid.rb | 2 +- lib/lite/uxid/uuid.rb | 9 +++- 13 files changed, 136 insertions(+), 115 deletions(-) create mode 100644 lib/lite/uxid/base/irreversible.rb create mode 100644 lib/lite/uxid/base/reversible.rb delete mode 100644 lib/lite/uxid/irreversible.rb delete mode 100644 lib/lite/uxid/reversible.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 472169d..22016fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [1.5.0] - 2024-09-20 +### Added +- Added uuid version option ### Changed - Ruby send perf improvements diff --git a/Gemfile.lock b/Gemfile.lock index c6e7bcc..2151e82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - lite-uxid (1.4.0) + lite-uxid (1.5.0) GEM remote: https://rubygems.org/ diff --git a/README.md b/README.md index 0f1f983..4ef7d52 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Lite::Uxid.configure do |config| config.nanoid_size = 21 config.ulid_charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" config.ulid_size = 26 + config.uuid_version = 4 end ``` @@ -92,7 +93,7 @@ Lite::Uxid::Ulid.encode #=> '01GJAY9KGR539EZF4QWYEJGSN7' ## UUID -Implements v4 of the specification. [More information](https://en.wikipedia.org/wiki/Universally_unique_identifier) +Implements `v4` and `v7` of the specification. [More information](https://en.wikipedia.org/wiki/Universally_unique_identifier) ```ruby Lite::Uxid::Uuid.encode #=> '4376a67e-1189-44b3-a599-7f7566bf105b' diff --git a/lib/lite/uxid.rb b/lib/lite/uxid.rb index 9e92882..37ce396 100644 --- a/lib/lite/uxid.rb +++ b/lib/lite/uxid.rb @@ -4,8 +4,8 @@ require "lite/uxid/version" require "lite/uxid/configuration" -require "lite/uxid/irreversible" -require "lite/uxid/reversible" +require "lite/uxid/base/irreversible" +require "lite/uxid/base/reversible" require "lite/uxid/record/hashid" require "lite/uxid/record/nanoid" require "lite/uxid/record/ulid" diff --git a/lib/lite/uxid/base/irreversible.rb b/lib/lite/uxid/base/irreversible.rb new file mode 100644 index 0000000..4bb8883 --- /dev/null +++ b/lib/lite/uxid/base/irreversible.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "securerandom" unless defined?(SecureRandom) + +module Lite + module Uxid + module Base + class Irreversible + + attr_reader :opts + + def initialize(opts = {}) + @opts = opts + end + + class << self + + def encode(opts = {}) + klass = new(opts) + klass.encode + end + + def decode(opts = {}) + klass = new(opts) + klass.decode + end + + end + + def encode + raise NotImplementedError, "override method in #{coder_class}" + end + + def decode + raise NotImplementedError, "coder does not support decoding" + end + + private + + def coder_value_for(key) + sym_key = :"#{coder_class.downcase}_#{key}" + return unless Lite::Uxid.configuration.respond_to?(sym_key) + + opts.delete(key) || Lite::Uxid.configuration.send(sym_key) + end + + def coder_bytes + @coder_bytes ||= SecureRandom.random_bytes(coder_size).bytes + end + + def coder_charset + @coder_charset ||= coder_value_for(:charset) + end + + def coder_class + @coder_class ||= self.class.name.split("::").last + end + + def coder_length + @coder_length ||= coder_charset.size + end + + def coder_salt + @coder_salt ||= coder_value_for(:salt) + end + + def coder_size + @coder_size ||= coder_value_for(:size) + end + + def coder_version + @coder_version ||= coder_value_for(:version) + end + + end + end + end +end diff --git a/lib/lite/uxid/base/reversible.rb b/lib/lite/uxid/base/reversible.rb new file mode 100644 index 0000000..97ce4de --- /dev/null +++ b/lib/lite/uxid/base/reversible.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Lite + module Uxid + module Base + class Reversible < Irreversible + + attr_reader :id + + def initialize(id, opts = {}) + @id = id + super(opts) + end + + class << self + + def encode(id, opts = {}) + klass = new(id, opts) + klass.encode + end + + def decode(id, opts = {}) + klass = new(id, opts) + klass.decode + end + + end + + def decode + raise NotImplementedError, "override method in #{coder_class}" + end + + end + end + end +end diff --git a/lib/lite/uxid/configuration.rb b/lib/lite/uxid/configuration.rb index 69f7aa8..751e2a7 100644 --- a/lib/lite/uxid/configuration.rb +++ b/lib/lite/uxid/configuration.rb @@ -5,7 +5,10 @@ module Uxid class Configuration - attr_accessor :hashid_charset, :hashid_salt, :hashid_size, :nanoid_charset, :nanoid_size, :ulid_charset, :ulid_size + attr_accessor :hashid_charset, :hashid_size, :hashid_salt, + :nanoid_charset, :nanoid_size, + :ulid_charset, :ulid_size, + :uuid_version def initialize @hashid_charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -15,6 +18,7 @@ def initialize @nanoid_size = 21 @ulid_charset = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" @ulid_size = 26 + @uuid_version = 4 end end diff --git a/lib/lite/uxid/hashid.rb b/lib/lite/uxid/hashid.rb index 1b061f0..400be6d 100644 --- a/lib/lite/uxid/hashid.rb +++ b/lib/lite/uxid/hashid.rb @@ -2,7 +2,7 @@ module Lite module Uxid - class Hashid < Reversible + class Hashid < Base::Reversible def encode encode_chars((id + coder_salt) << coder_size) diff --git a/lib/lite/uxid/irreversible.rb b/lib/lite/uxid/irreversible.rb deleted file mode 100644 index 3fab35f..0000000 --- a/lib/lite/uxid/irreversible.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require "securerandom" unless defined?(SecureRandom) - -module Lite - module Uxid - class Irreversible - - attr_reader :opts - - def initialize(opts = {}) - @opts = opts - end - - class << self - - def encode(opts = {}) - klass = new(opts) - klass.encode - end - - def decode(opts = {}) - klass = new(opts) - klass.decode - end - - end - - def encode - raise NotImplementedError, "override method in #{coder_class}" - end - - def decode - raise NotImplementedError, "coder does not support decoding" - end - - private - - def coder_bytes - @coder_bytes ||= SecureRandom.random_bytes(coder_size).bytes - end - - def coder_charset - @coder_charset ||= - opts.delete(:charset) || - Lite::Uxid.configuration.send(:"#{coder_class.downcase}_charset") - end - - def coder_class - @coder_class ||= self.class.name.split("::").last - end - - def coder_length - @coder_length ||= coder_charset.size - end - - def coder_salt - @coder_salt ||= - opts.delete(:salt) || - Lite::Uxid.configuration.send(:"#{coder_class.downcase}_salt") - end - - def coder_size - @coder_size ||= - opts.delete(:size) || - Lite::Uxid.configuration.send(:"#{coder_class.downcase}_size") - end - - end - end -end diff --git a/lib/lite/uxid/nanoid.rb b/lib/lite/uxid/nanoid.rb index 02d4d39..9c466d5 100644 --- a/lib/lite/uxid/nanoid.rb +++ b/lib/lite/uxid/nanoid.rb @@ -2,7 +2,7 @@ module Lite module Uxid - class Nanoid < Irreversible + class Nanoid < Base::Irreversible def encode (0...coder_size).each_with_object(+"") do |i, str| diff --git a/lib/lite/uxid/reversible.rb b/lib/lite/uxid/reversible.rb deleted file mode 100644 index 6da43ec..0000000 --- a/lib/lite/uxid/reversible.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -module Lite - module Uxid - class Reversible < Irreversible - - attr_reader :id - - def initialize(id, opts = {}) - @id = id - super(opts) - end - - class << self - - def encode(id, opts = {}) - klass = new(id, opts) - klass.encode - end - - def decode(id, opts = {}) - klass = new(id, opts) - klass.decode - end - - end - - def decode - raise NotImplementedError, "override method in #{coder_class}" - end - - end - end -end diff --git a/lib/lite/uxid/ulid.rb b/lib/lite/uxid/ulid.rb index 7aff1ac..1c9b2e3 100644 --- a/lib/lite/uxid/ulid.rb +++ b/lib/lite/uxid/ulid.rb @@ -2,7 +2,7 @@ module Lite module Uxid - class Ulid < Irreversible + class Ulid < Base::Irreversible MASK = 0x1f diff --git a/lib/lite/uxid/uuid.rb b/lib/lite/uxid/uuid.rb index 29cd49e..2b35e16 100644 --- a/lib/lite/uxid/uuid.rb +++ b/lib/lite/uxid/uuid.rb @@ -2,10 +2,15 @@ module Lite module Uxid - class Uuid < Irreversible + class Uuid < Base::Irreversible def encode - SecureRandom.uuid + case coder_version + when 7 + SecureRandom.uuid_v7 + else + SecureRandom.uuid + end end end