encoded_id 0.4.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5cc2ba3de20b77f871eacb0820fb0ab151281bf6ff6281c992f9e47dc8657138
4
- data.tar.gz: 22e9cc3a0dcaecaf34aea73b25681651efe8a4528b4cb70d01ea0aa5fdb73b57
3
+ metadata.gz: a860b12577a70042f6d17a1788cb8557f3ab5ab477441a44c3be037b70165ded
4
+ data.tar.gz: bd9d57c92ada9e47a1080ea5b4d04cb3069a055a213305b698f1a2c7c424297f
5
5
  SHA512:
6
- metadata.gz: 04f9083352c9559df93ef8418397f43b9360b070025ba75e1ad4ba116fced9635f479939ca9cc55f9b9e594d380e8c4fa503834c85e1ef1994c187de0f5ce3a0
7
- data.tar.gz: b2527e2301ad455b22d8ce1a5c652a6814485a703b032af635834ba145b904050ea3b15f3cb9d189b0e3a3a1361e5dce4c4fdbf662f819c56bbbcd212c8f7008
6
+ metadata.gz: e78405858e31da61d3361c3e42f999591e68f2053f1b58944c1f07616f5a57a599a174708eda301d52743d9dabaae8e76bf50442936401a9e943699589e0ad5c
7
+ data.tar.gz: a4e9ee6327f0d0e0d68eab43af5f21126e5ccef888b7478e07e14ade2a1532f618ac95ddb80e3406956ed7e505fda76c577e63368d376955024ab65df5084aa0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.0] - 2023-08-06
4
+
5
+ - Improved RBS definitions
6
+ - Improved test coverage
7
+
8
+ ## [0.4.0] - 2022-12-04
9
+
10
+ - Support custom split character which must not be in the alphabet
11
+ - Ability to provide a custom character equivalences mapping
12
+
13
+ ## [0.3.0] - 2022-10-12
14
+
15
+ - Fix splitting of encoded ID string
16
+ - Checks that integer values to be encoded are positive
17
+ - Experimental support for encoding hex strings
18
+
3
19
  ## [0.1.0] - 2022-10-11
4
20
 
5
21
  - Initial release
data/Gemfile CHANGED
@@ -9,6 +9,6 @@ gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
11
 
12
- gem "standard", "~> 1.3"
12
+ gem "standard", "~> 1.25"
13
13
 
14
- gem "steep", "~> 1.2"
14
+ gem "steep", "~> 1.5"
data/README.md CHANGED
@@ -33,8 +33,7 @@ coder.decode("z2j7-Odmw") # (note the capital 'o' instead of zero)
33
33
 
34
34
  ## Features
35
35
 
36
- * encoded IDs are reversible (uses with https://hashids.org)
37
- * supports slugged IDs (eg `beef-tenderloins-prime--p5w9-z27j`)
36
+ * encoded IDs are reversible (uses with https://hashids.org))
38
37
  * supports multiple IDs encoded in one encoded string (eg `7aq6-0zqw` decodes to `[78, 45]`)
39
38
  * supports encoding of hex strings (eg UUIDs), including multiple IDs encoded in one string **(experimental)**
40
39
  * supports custom alphabets for the encoded string (at least 16 characters needed)
@@ -276,6 +275,21 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
276
275
  number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git
277
276
  commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
278
277
 
278
+ ### Type check
279
+
280
+ First install dependencies:
281
+
282
+ ```bash
283
+ rbs collection install
284
+ ```
285
+
286
+ Then run:
287
+
288
+ ```bash
289
+ steep check
290
+ ```
291
+
292
+
279
293
  ## See also
280
294
 
281
295
  - https://hashids.org
@@ -2,29 +2,10 @@
2
2
 
3
3
  module EncodedId
4
4
  class Alphabet
5
- def initialize(characters, equivalences = nil)
6
- unless (characters.is_a?(Array) || characters.is_a?(String)) && characters.size > 0
7
- raise InvalidAlphabetError, "Alphabet must be a string or array"
8
- end
9
- unique_alphabet = (characters.is_a?(Array) ? characters : characters.chars).uniq
10
- raise InvalidAlphabetError, "Alphabet must be at least 16 unique characters" if unique_alphabet.size < 16
11
- @characters = unique_alphabet.join
12
-
13
- # Equivalences is a hash of characters to their equivalent character.
14
- # Characters to be mapped must not be in the alphabet, and must map to a character that is in the alphabet.
15
- raise InvalidConfigurationError, "Character equivalences must be a hash or nil" unless equivalences.nil? || equivalences.is_a?(Hash)
16
- valid_equivalences = equivalences.nil? || (unique_alphabet & equivalences.keys).empty? && (equivalences.values - unique_alphabet).empty?
17
- raise InvalidConfigurationError unless valid_equivalences
18
- @equivalences = equivalences
19
- end
20
-
21
- attr_reader :characters, :equivalences
5
+ MIN_UNIQUE_CHARACTERS = 16
22
6
 
23
7
  class << self
24
8
  def modified_crockford
25
- # Note we downcase first, so mappings are only for lower case. Also Crockford suggests i==1,
26
- # but here i==j is used.
27
-
28
9
  new(
29
10
  "0123456789abcdefghjkmnpqrstuvwxyz",
30
11
  {
@@ -35,5 +16,50 @@ module EncodedId
35
16
  )
36
17
  end
37
18
  end
19
+
20
+ def initialize(characters, equivalences = nil)
21
+ raise_invalid_alphabet! unless valid_input_characters?(characters)
22
+ unique_characters = unique_character_alphabet(characters)
23
+ raise_character_set_too_small! unless sufficient_characters?(unique_characters.size)
24
+ raise_invalid_equivalences! unless valid_equivalences?(equivalences, unique_characters)
25
+
26
+ @characters = unique_characters.join
27
+ @equivalences = equivalences
28
+ end
29
+
30
+ attr_reader :characters, :equivalences
31
+
32
+ private
33
+
34
+ def valid_input_characters?(characters)
35
+ (characters.is_a?(Array) || characters.is_a?(String)) && characters.size > 0
36
+ end
37
+
38
+ def unique_character_alphabet(characters)
39
+ (characters.is_a?(Array) ? characters : characters.chars).uniq
40
+ end
41
+
42
+ def sufficient_characters?(size)
43
+ size >= MIN_UNIQUE_CHARACTERS
44
+ end
45
+
46
+ def valid_equivalences?(equivalences, unique_characters)
47
+ return true if equivalences.nil?
48
+ return false unless equivalences.is_a?(Hash)
49
+
50
+ (unique_characters & equivalences.keys).empty? && (equivalences.values - unique_characters).empty?
51
+ end
52
+
53
+ def raise_invalid_alphabet!
54
+ raise InvalidAlphabetError, "Alphabet must be a string or array."
55
+ end
56
+
57
+ def raise_character_set_too_small!
58
+ raise InvalidAlphabetError, "Alphabet must contain at least #{MIN_UNIQUE_CHARACTERS} unique characters."
59
+ end
60
+
61
+ def raise_invalid_equivalences!
62
+ raise InvalidConfigurationError, "Character equivalences must be a hash or nil."
63
+ end
38
64
  end
39
65
  end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EncodedId
4
+ class HexRepresentation
5
+ def initialize(hex_digit_encoding_group_size)
6
+ @hex_digit_encoding_group_size = validate_hex_digit_encoding_group_size(hex_digit_encoding_group_size)
7
+ end
8
+
9
+ def hex_as_integers(hexs)
10
+ integer_representation(hexs)
11
+ end
12
+
13
+ def integers_as_hex(integers)
14
+ integers_to_hex_strings(integers)
15
+ end
16
+
17
+ private
18
+
19
+ # Number of hex digits to encode in each group, larger values will result in shorter hashes for longer inputs.
20
+ # Vice versa for smaller values, ie a smaller value will result in smaller hashes for small inputs.
21
+ def validate_hex_digit_encoding_group_size(hex_digit_encoding_group_size)
22
+ if !hex_digit_encoding_group_size.is_a?(Integer) || hex_digit_encoding_group_size < 1 || hex_digit_encoding_group_size > 32
23
+ raise InvalidConfigurationError, "hex_digit_encoding_group_size must be > 0 and <= 32"
24
+ end
25
+ hex_digit_encoding_group_size
26
+ end
27
+
28
+ # Convert hex strings to integer representations
29
+ def integer_representation(hexs)
30
+ inputs = Array(hexs).map(&:to_s)
31
+ digits_to_encode = []
32
+
33
+ inputs.map { |hex_string| hex_string_as_integer_representation(hex_string) }.each do |integer_groups|
34
+ digits_to_encode.concat(integer_groups)
35
+ digits_to_encode << hex_string_separator
36
+ end
37
+
38
+ # Remove the last marker
39
+ digits_to_encode.pop unless digits_to_encode.empty?
40
+ digits_to_encode
41
+ end
42
+
43
+ # Convert integer representations to hex strings
44
+ def integers_to_hex_strings(integers)
45
+ hex_strings = []
46
+ hex_string = []
47
+ add_leading = false
48
+
49
+ integers.reverse_each do |integer|
50
+ if integer == hex_string_separator # Marker to separate hex strings, so start a new one
51
+ hex_strings << hex_string.join
52
+ hex_string = []
53
+ add_leading = false
54
+ else
55
+ hex_string << (add_leading ? "%.#{@hex_digit_encoding_group_size}x" % integer : integer.to_s(16))
56
+ add_leading = true
57
+ end
58
+ end
59
+
60
+ # Add the last hex string
61
+ hex_strings << hex_string.join unless hex_string.empty?
62
+ hex_strings.reverse
63
+ end
64
+
65
+ def hex_string_as_integer_representation(hex_string)
66
+ cleaned = remove_non_hex_characters(hex_string)
67
+ convert_to_integer_groups(cleaned)
68
+ end
69
+
70
+ # Marker to separate hex strings, must be greater than largest value encoded
71
+ def hex_string_separator
72
+ @hex_string_separator ||= 2.pow(@hex_digit_encoding_group_size * 4)
73
+ end
74
+
75
+ def remove_non_hex_characters(hex_string)
76
+ hex_string.gsub(/[^0-9a-f]/i, "")
77
+ end
78
+
79
+ def convert_to_integer_groups(hex_string_cleaned)
80
+ groups = []
81
+ hex_string_cleaned.chars.reverse.each_with_index do |char, i|
82
+ group_id = i / @hex_digit_encoding_group_size
83
+ groups[group_id] ||= []
84
+ groups[group_id].unshift(char)
85
+ end
86
+ groups.map { |c| c.join.to_i(16) }
87
+ end
88
+ end
89
+ end
@@ -9,29 +9,12 @@ require "hashids"
9
9
  module EncodedId
10
10
  class ReversibleId
11
11
  def initialize(salt:, length: 8, split_at: 4, split_with: "-", alphabet: Alphabet.modified_crockford, hex_digit_encoding_group_size: 4)
12
- raise InvalidAlphabetError, "alphabet must be an instance of Alphabet" unless alphabet.is_a?(Alphabet)
13
- @alphabet = alphabet
14
-
15
- raise InvalidConfigurationError, "Salt must be a string and longer that 3 characters" unless salt.is_a?(String) && salt.size > 3
16
- @salt = salt
17
- # Target length of the encoded string (the minimum but not maximum length)
18
- raise InvalidConfigurationError, "Length must be an integer greater than 0" unless length.is_a?(Integer) && length > 0
19
- @length = length
20
- # Split the encoded string into groups of this size
21
- unless (split_at.is_a?(Integer) && split_at > 0) || split_at.nil?
22
- raise InvalidConfigurationError, "Split at must be an integer greater than 0 or nil"
23
- end
24
- @split_at = split_at
25
- unless split_with.is_a?(String) && !alphabet.characters.include?(split_with)
26
- raise InvalidConfigurationError, "Split with must be a string and not part of the alphabet"
27
- end
28
- @split_with = split_with
29
- # Number of hex digits to encode in each group, larger values will result in shorter hashes for longer inputs.
30
- # Vice versa for smaller values, ie a smaller value will result in smaller hashes for small inputs.
31
- if hex_digit_encoding_group_size < 1 || hex_digit_encoding_group_size > 32
32
- raise InvalidConfigurationError, "hex_digit_encoding_group_size must be > 0 and <= 32"
33
- end
34
- @hex_digit_encoding_group_size = hex_digit_encoding_group_size
12
+ @alphabet = validate_alphabet(alphabet)
13
+ @salt = validate_salt(salt)
14
+ @length = validate_length(length)
15
+ @split_at = validate_split_at(split_at)
16
+ @split_with = validate_split_with(split_with, alphabet)
17
+ @hex_represention_encoder = HexRepresentation.new(hex_digit_encoding_group_size)
35
18
  end
36
19
 
37
20
  # Encode the input values into a hash
@@ -44,7 +27,7 @@ module EncodedId
44
27
 
45
28
  # Encode hex strings into a hash
46
29
  def encode_hex(hexs)
47
- encode(integer_representation(hexs))
30
+ encode(hex_represention_encoder.hex_as_integers(hexs))
48
31
  end
49
32
 
50
33
  # Decode the hash to original array
@@ -57,7 +40,7 @@ module EncodedId
57
40
  # Decode hex strings from a hash
58
41
  def decode_hex(str)
59
42
  integers = encoded_id_generator.decode(convert_to_hash(str))
60
- integers_to_hex_strings(integers)
43
+ hex_represention_encoder.integers_as_hex(integers)
61
44
  end
62
45
 
63
46
  private
@@ -67,7 +50,38 @@ module EncodedId
67
50
  :alphabet,
68
51
  :split_at,
69
52
  :split_with,
70
- :hex_digit_encoding_group_size
53
+ :hex_represention_encoder
54
+
55
+ def validate_alphabet(alphabet)
56
+ raise InvalidAlphabetError, "alphabet must be an instance of Alphabet" unless alphabet.is_a?(Alphabet)
57
+ alphabet
58
+ end
59
+
60
+ def validate_salt(salt)
61
+ raise InvalidConfigurationError, "Salt must be a string and longer than 3 characters" unless salt.is_a?(String) && salt.size > 3
62
+ salt
63
+ end
64
+
65
+ # Target length of the encoded string (the minimum but not maximum length)
66
+ def validate_length(length)
67
+ raise InvalidConfigurationError, "Length must be an integer greater than 0" unless length.is_a?(Integer) && length > 0
68
+ length
69
+ end
70
+
71
+ # Split the encoded string into groups of this size
72
+ def validate_split_at(split_at)
73
+ unless (split_at.is_a?(Integer) && split_at > 0) || split_at.nil?
74
+ raise InvalidConfigurationError, "Split at must be an integer greater than 0 or nil"
75
+ end
76
+ split_at
77
+ end
78
+
79
+ def validate_split_with(split_with, alphabet)
80
+ unless split_with.is_a?(String) && !alphabet.characters.include?(split_with)
81
+ raise InvalidConfigurationError, "Split with must be a string and not part of the alphabet"
82
+ end
83
+ split_with
84
+ end
71
85
 
72
86
  def prepare_input(value)
73
87
  inputs = value.is_a?(Array) ? value.map(&:to_i) : [value.to_i]
@@ -99,53 +113,5 @@ module EncodedId
99
113
  cleaned.tr(from, to)
100
114
  end
101
115
  end
102
-
103
- # TODO: optimize this
104
- def integer_representation(hexs)
105
- inputs = hexs.is_a?(Array) ? hexs.map(&:to_s) : [hexs.to_s]
106
- inputs.map! do |hex_string|
107
- cleaned = hex_string.gsub(/[^0-9a-f]/i, "")
108
- # Convert to groups of integers. Process least significant hex digits first
109
- groups = []
110
- cleaned.chars.reverse.each_with_index do |char, i|
111
- group_id = i / hex_digit_encoding_group_size.to_i
112
- groups[group_id] ||= []
113
- groups[group_id].unshift(char)
114
- end
115
- groups.map { |c| c.join.to_i(16) }
116
- end
117
- digits_to_encode = []
118
- inputs.each_with_object(digits_to_encode) do |hex_digits, digits|
119
- digits.concat(hex_digits)
120
- digits << hex_string_separator
121
- end
122
- digits_to_encode.pop unless digits_to_encode.empty? # Remove the last marker
123
- digits_to_encode
124
- end
125
-
126
- # Marker to separate hex strings, must be greater than largest value encoded
127
- def hex_string_separator
128
- @hex_string_separator ||= 2.pow(hex_digit_encoding_group_size * 4)
129
- end
130
-
131
- # TODO: optimize this
132
- def integers_to_hex_strings(integers)
133
- hex_strings = []
134
- hex_string = []
135
- add_leading = false
136
- # Digits are encoded in least significant digit first order, but string is most significant first, so reverse
137
- integers.reverse_each do |integer|
138
- if integer == hex_string_separator # Marker to separate hex strings, so start a new one
139
- hex_strings << hex_string.join
140
- hex_string = []
141
- add_leading = false
142
- else
143
- hex_string << (add_leading ? "%.#{hex_digit_encoding_group_size}x" % integer : integer.to_s(16))
144
- add_leading = true
145
- end
146
- end
147
- hex_strings << hex_string.join unless hex_string.empty? # Add the last hex string
148
- hex_strings.reverse # Reverse final values to get the original order (the encoding process also reverses the encoded value order)
149
- end
150
116
  end
151
117
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EncodedId
4
- VERSION = "0.4.0"
4
+ VERSION = "1.0.0.rc1"
5
5
  end
data/lib/encoded_id.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "encoded_id/version"
4
4
  require_relative "encoded_id/alphabet"
5
+ require_relative "encoded_id/hex_representation"
5
6
  require_relative "encoded_id/reversible_id"
6
7
 
7
8
  module EncodedId
data/rbs_collection.yaml CHANGED
@@ -9,8 +9,6 @@ sources:
9
9
  path: .gem_rbs_collection
10
10
 
11
11
  gems:
12
- - name: encoded_id
13
- ignore: true
14
12
  # Skip loading rbs gem's RBS.
15
13
  # It's unnecessary if you don't use rbs as a library.
16
14
  - name: rbs
data/sig/encoded_id.rbs CHANGED
@@ -1,25 +1,65 @@
1
1
  module EncodedId
2
+ VERSION: ::String
3
+
4
+ InvalidConfigurationError: ::StandardError
2
5
  EncodedIdFormatError: ::ArgumentError
3
6
  InvalidAlphabetError: ::ArgumentError
4
7
  InvalidInputError: ::ArgumentError
5
8
 
6
9
  class Alphabet
10
+ MIN_UNIQUE_CHARACTERS: ::Integer
11
+
7
12
  def initialize: (String, ?::Hash[::String, ::String]) -> void
8
13
 
9
- attr_reader alphabet: String
14
+ attr_reader characters: String
10
15
  attr_reader equivalences: ::Hash[::String, ::String]
11
16
 
12
17
  def self.modified_crockford: () -> Alphabet
18
+
19
+ private
20
+
21
+ def valid_input_characters?: ((::Array[::String] | ::String) characters) -> bool
22
+
23
+ def sufficient_characters?: (::Integer size) -> bool
24
+
25
+ def unique_character_alphabet: ((::Array[::String] | ::String) characters) -> ::Array[::String]
26
+
27
+ def valid_equivalences?: (::Hash[::String, ::String] equivalences, ::Array[::String] unique_characters) -> bool
28
+
29
+ def raise_character_set_too_small!: -> untyped
30
+
31
+ def raise_invalid_alphabet!: -> void
32
+
33
+ def raise_invalid_equivalences!: -> void
34
+ end
35
+
36
+ type encodeableValue = ::Array[::String | ::Integer] | ::String | ::Integer
37
+ type encodeableHexValue = ::Array[::String] | ::String
38
+
39
+ class HexRepresentation
40
+ def initialize: (::Integer) -> void
41
+ def hex_as_integers: (encodeableHexValue) -> ::Array[::Integer]
42
+ def integers_as_hex: (::Array[::Integer]) -> ::Array[::String]
43
+
44
+ private
45
+
46
+ def validate_hex_digit_encoding_group_size: (::Integer) -> ::Integer
47
+ def integer_representation: (encodeableHexValue) -> ::Array[::Integer]
48
+ def integers_to_hex_strings: (::Array[::Integer]) -> ::Array[::String]
49
+ def hex_string_as_integer_representation: (::String) -> ::Array[::Integer]
50
+ def hex_string_separator: -> ::Integer
51
+ def remove_non_hex_characters: (::String) -> ::String
52
+ def convert_to_integer_groups: (::String) -> ::Array[::Integer]
13
53
  end
14
54
 
15
55
  class ReversibleId
16
56
  def initialize: (salt: ::String, ?length: ::Integer, ?split_at: ::Integer, ?split_with: ::String, ?alphabet: Alphabet, ?hex_digit_encoding_group_size: ::Integer) -> void
17
57
 
18
58
  # Encode the input values into a hash
19
- def encode: (untyped values) -> ::String
59
+ def encode: (encodeableValue values) -> ::String
20
60
 
21
61
  # Encode hex strings into a hash
22
- def encode_hex: (untyped hexs) -> ::String
62
+ def encode_hex: (encodeableHexValue hexs) -> ::String
23
63
 
24
64
  # Decode the hash to original array
25
65
  def decode: (::String str) -> ::Array[::Integer]
@@ -42,7 +82,14 @@ module EncodedId
42
82
  attr_reader split_at: ::Integer | nil
43
83
  attr_reader split_with: ::String
44
84
 
45
- attr_reader hex_digit_encoding_group_size: ::Integer
85
+ attr_reader hex_represention_encoder: HexRepresentation
86
+
87
+ def validate_alphabet: (Alphabet) -> Alphabet
88
+ def validate_salt: (::String) -> ::String
89
+ def validate_length: (::Integer) -> ::Integer
90
+ def validate_split_at: (::Integer | nil) -> (::Integer | nil)
91
+ def validate_split_with: (::String, Alphabet) -> ::String
92
+ def validate_hex_digit_encoding_group_size: (::Integer) -> ::Integer
46
93
 
47
94
  def prepare_input: (untyped value) -> ::Array[::Integer]
48
95
 
@@ -55,11 +102,5 @@ module EncodedId
55
102
  def convert_to_hash: (::String str) -> ::String
56
103
 
57
104
  def map_equivalent_characters: (::String str) -> ::String
58
-
59
- def integer_representation: (untyped hexs) -> ::Array[::Integer]
60
-
61
- def integers_to_hex_strings: (::Array[::Integer] integers) -> ::Array[::String]
62
-
63
- def hex_string_separator: () -> ::Integer
64
105
  end
65
106
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: encoded_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-04 00:00:00.000000000 Z
11
+ date: 2023-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashids
@@ -43,6 +43,7 @@ files:
43
43
  - Steepfile
44
44
  - lib/encoded_id.rb
45
45
  - lib/encoded_id/alphabet.rb
46
+ - lib/encoded_id/hex_representation.rb
46
47
  - lib/encoded_id/reversible_id.rb
47
48
  - lib/encoded_id/version.rb
48
49
  - rbs_collection.yaml
@@ -66,11 +67,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
67
  version: 2.7.0
67
68
  required_rubygems_version: !ruby/object:Gem::Requirement
68
69
  requirements:
69
- - - ">="
70
+ - - ">"
70
71
  - !ruby/object:Gem::Version
71
- version: '0'
72
+ version: 1.3.1
72
73
  requirements: []
73
- rubygems_version: 3.3.7
74
+ rubygems_version: 3.4.10
74
75
  signing_key:
75
76
  specification_version: 4
76
77
  summary: EncodedId is a gem for creating reversible obfuscated IDs from numerical