encoded_id 0.4.0 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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