encoded_id 1.0.0.rc3 → 1.0.0.rc5

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.
@@ -0,0 +1,139 @@
1
+ // https://github.com/tzvetkoff/hashids.c
2
+ /*
3
+ Copyright (C) 2014 Latchezar Tzvetkoff
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+ */
11
+
12
+
13
+ #ifndef HASHIDS_H
14
+ #define HASHIDS_H 1
15
+
16
+ #include <stdlib.h>
17
+
18
+ /* version constants */
19
+ #define HASHIDS_VERSION "1.2.1"
20
+ #define HASHIDS_VERSION_MAJOR 1
21
+ #define HASHIDS_VERSION_MINOR 2
22
+ #define HASHIDS_VERSION_PATCH 1
23
+
24
+ /* minimal alphabet length */
25
+ #define HASHIDS_MIN_ALPHABET_LENGTH 16u
26
+
27
+ /* separator divisor */
28
+ #define HASHIDS_SEPARATOR_DIVISOR 3.5f
29
+
30
+ /* guard divisor */
31
+ #define HASHIDS_GUARD_DIVISOR 12u
32
+
33
+ /* default salt */
34
+ #define HASHIDS_DEFAULT_SALT ""
35
+
36
+ /* default minimal hash length */
37
+ #define HASHIDS_DEFAULT_MIN_HASH_LENGTH 0u
38
+
39
+ /* default alphabet */
40
+ #define HASHIDS_DEFAULT_ALPHABET "abcdefghijklmnopqrstuvwxyz" \
41
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
42
+ "1234567890"
43
+
44
+ /* default separators */
45
+ #define HASHIDS_DEFAULT_SEPARATORS "cfhistuCFHISTU"
46
+
47
+ /* error codes */
48
+ #define HASHIDS_ERROR_OK 0
49
+ #define HASHIDS_ERROR_ALLOC -1
50
+ #define HASHIDS_ERROR_ALPHABET_LENGTH -2
51
+ #define HASHIDS_ERROR_ALPHABET_SPACE -3
52
+ #define HASHIDS_ERROR_INVALID_HASH -4
53
+ #define HASHIDS_ERROR_INVALID_NUMBER -5
54
+
55
+ /* thread-safe hashids_errno indirection */
56
+ extern int *__hashids_errno_addr(void);
57
+ #define hashids_errno (*__hashids_errno_addr())
58
+
59
+ /* alloc & free */
60
+ extern void *(*_hashids_alloc)(size_t size);
61
+ extern void (*_hashids_free)(void *ptr);
62
+
63
+ /* the hashids "object" */
64
+ struct hashids_s {
65
+ char *alphabet;
66
+ char *alphabet_copy_1;
67
+ char *alphabet_copy_2;
68
+ size_t alphabet_length;
69
+
70
+ char *salt;
71
+ size_t salt_length;
72
+
73
+ char *separators;
74
+ size_t separators_count;
75
+
76
+ char *guards;
77
+ size_t guards_count;
78
+
79
+ size_t min_hash_length;
80
+ };
81
+ typedef struct hashids_s hashids_t;
82
+
83
+ /* exported function definitions */
84
+ void
85
+ hashids_shuffle(char *str, size_t str_length, char *salt, size_t salt_length);
86
+
87
+ void
88
+ hashids_free(hashids_t *hashids);
89
+
90
+ hashids_t *
91
+ hashids_init3(const char *salt, size_t min_hash_length,
92
+ const char *alphabet);
93
+
94
+ hashids_t *
95
+ hashids_init2(const char *salt, size_t min_hash_length);
96
+
97
+ hashids_t *
98
+ hashids_init(const char *salt);
99
+
100
+ size_t
101
+ hashids_estimate_encoded_size(hashids_t *hashids, size_t numbers_count,
102
+ unsigned long long *numbers);
103
+
104
+ size_t
105
+ hashids_estimate_encoded_size_v(hashids_t *hashids, size_t numbers_count, ...);
106
+
107
+ size_t
108
+ hashids_encode(hashids_t *hashids, char *buffer, size_t numbers_count,
109
+ unsigned long long *numbers);
110
+
111
+ size_t
112
+ hashids_encode_v(hashids_t *hashids, char *buffer, size_t numbers_count, ...);
113
+
114
+ size_t
115
+ hashids_encode_one(hashids_t *hashids, char *buffer,
116
+ unsigned long long number);
117
+
118
+ size_t
119
+ hashids_numbers_count(hashids_t *hashids, const char *str);
120
+
121
+ size_t
122
+ hashids_decode(hashids_t *hashids, const char *str,
123
+ unsigned long long *numbers, size_t numbers_max);
124
+
125
+ size_t
126
+ hashids_decode_unsafe(hashids_t *hashids, const char *str,
127
+ unsigned long long *numbers);
128
+
129
+ size_t
130
+ hashids_decode_safe(hashids_t *hashids, const char *str,
131
+ unsigned long long *numbers, size_t numbers_max);
132
+
133
+ size_t
134
+ hashids_encode_hex(hashids_t *hashids, char *buffer, const char *hex_str);
135
+
136
+ size_t
137
+ hashids_decode_hex(hashids_t *hashids, char *str, char *output);
138
+
139
+ #endif
@@ -15,6 +15,10 @@ module EncodedId
15
15
  }
16
16
  )
17
17
  end
18
+
19
+ def alphanum
20
+ new("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
21
+ end
18
22
  end
19
23
 
20
24
  def initialize(characters, equivalences = nil)
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This implementation based on https://github.com/peterhellberg/hashids.rb
4
+ #
5
+ # Original Hashids implementation is MIT licensed:
6
+ #
7
+ # Copyright (c) 2013-2017 Peter Hellberg
8
+ #
9
+ # MIT License
10
+ #
11
+ # Permission is hereby granted, free of charge, to any person obtaining
12
+ # a copy of this software and associated documentation files (the
13
+ # "Software"), to deal in the Software without restriction, including
14
+ # without limitation the rights to use, copy, modify, merge, publish,
15
+ # distribute, sublicense, and/or sell copies of the Software, and to
16
+ # permit persons to whom the Software is furnished to do so, subject to
17
+ # the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be
20
+ # included in all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+ #
30
+ # This version also MIT licensed (Stephen Ierodiaconou): see LICENSE.txt file
31
+ module EncodedId
32
+ class HashId
33
+ def initialize(salt, min_hash_length = 0, alphabet = Alphabet.alphanum)
34
+ unless min_hash_length.is_a?(Integer) && min_hash_length >= 0
35
+ raise ArgumentError, "The min length must be a Integer and greater than or equal to 0"
36
+ end
37
+ @min_hash_length = min_hash_length
38
+
39
+ # TODO: move this class creation out of the constructor?
40
+ @separators_and_guards = OrdinalAlphabetSeparatorGuards.new(alphabet, salt)
41
+ @alphabet_ordinals = @separators_and_guards.alphabet
42
+ @separator_ordinals = @separators_and_guards.seps
43
+ @guard_ordinals = @separators_and_guards.guards
44
+ @salt_ordinals = @separators_and_guards.salt
45
+
46
+ @escaped_separator_selector = @separators_and_guards.seps_tr_selector
47
+ @escaped_guards_selector = @separators_and_guards.guards_tr_selector
48
+ end
49
+
50
+ attr_reader :alphabet_ordinals, :separator_ordinals, :guard_ordinals, :salt_ordinals
51
+
52
+ # We could get rid of calling with multiple arguments and just use an array as the argument always
53
+ def encode(numbers)
54
+ numbers.all? { |n| Integer(n) } # raises if conversion fails
55
+
56
+ return "" if numbers.empty? || numbers.any? { |n| n < 0 }
57
+
58
+ internal_encode(numbers)
59
+ end
60
+
61
+ def encode_hex(str)
62
+ return "" unless hex_string?(str)
63
+
64
+ numbers = str.scan(/[\w\W]{1,12}/).map do |num|
65
+ "1#{num}".to_i(16)
66
+ end
67
+
68
+ encode(numbers)
69
+ end
70
+
71
+ def decode(hash)
72
+ return [] if hash.nil? || hash.empty?
73
+
74
+ internal_decode(hash)
75
+ end
76
+
77
+ def decode_hex(hash)
78
+ numbers = decode(hash)
79
+
80
+ ret = numbers.map do |n|
81
+ n.to_s(16)[1..]
82
+ end
83
+
84
+ ret.join.upcase
85
+ end
86
+
87
+ protected
88
+
89
+ def internal_encode(numbers)
90
+ current_alphabet = @alphabet_ordinals.dup
91
+ separator_ordinals = @separator_ordinals
92
+ guard_ordinals = @guard_ordinals
93
+
94
+ alphabet_length = current_alphabet.length
95
+ length = numbers.length
96
+
97
+ hash_int = 0
98
+ # We dont use the iterator#sum to avoid the extra array allocation
99
+ i = 0
100
+ while i < length
101
+ hash_int += numbers[i] % (i + 100)
102
+ i += 1
103
+ end
104
+
105
+ lottery = current_alphabet[hash_int % alphabet_length]
106
+
107
+ # This is the final string form of the hash, as an array of ordinals
108
+ hashid_code = []
109
+ hashid_code << lottery
110
+ seasoning = [lottery].concat(@salt_ordinals)
111
+
112
+ i = 0
113
+ while i < length
114
+ num = numbers[i]
115
+ consistent_shuffle!(current_alphabet, seasoning, current_alphabet.dup, alphabet_length)
116
+ last_char_ord = hash_one_number(hashid_code, num, current_alphabet, alphabet_length)
117
+
118
+ if (i + 1) < length
119
+ num %= (last_char_ord + i)
120
+ hashid_code << separator_ordinals[num % separator_ordinals.length]
121
+ end
122
+
123
+ i += 1
124
+ end
125
+
126
+ if hashid_code.length < @min_hash_length
127
+ hashid_code.prepend(guard_ordinals[(hash_int + hashid_code[0]) % guard_ordinals.length])
128
+
129
+ if hashid_code.length < @min_hash_length
130
+ hashid_code << guard_ordinals[(hash_int + hashid_code[2]) % guard_ordinals.length]
131
+ end
132
+ end
133
+
134
+ half_length = current_alphabet.length.div(2)
135
+
136
+ while hashid_code.length < @min_hash_length
137
+ consistent_shuffle!(current_alphabet, current_alphabet.dup, nil, current_alphabet.length)
138
+ hashid_code.prepend(*current_alphabet[half_length..])
139
+ hashid_code.concat(current_alphabet[0, half_length])
140
+
141
+ excess = hashid_code.length - @min_hash_length
142
+ hashid_code = hashid_code[excess / 2, @min_hash_length] if excess > 0
143
+ end
144
+
145
+ # Convert the array of ordinals to a string
146
+ hashid_code.pack("U*")
147
+ end
148
+
149
+ def internal_decode(hash)
150
+ ret = []
151
+ current_alphabet = @alphabet_ordinals.dup
152
+ salt_ordinals = @salt_ordinals
153
+
154
+ breakdown = hash.tr(@escaped_guards_selector, " ")
155
+ array = breakdown.split(" ")
156
+
157
+ i = [3, 2].include?(array.length) ? 1 : 0
158
+
159
+ if (breakdown = array[i])
160
+ lottery, breakdown = breakdown[0], breakdown[1..]
161
+ breakdown.tr!(@escaped_separator_selector, " ")
162
+ sub_hashes = breakdown.split(" ")
163
+
164
+ seasoning = [lottery.ord].concat(salt_ordinals)
165
+
166
+ len = sub_hashes.length
167
+ time = 0
168
+ while time < len
169
+ sub_hash = sub_hashes[time]
170
+ consistent_shuffle!(current_alphabet, seasoning, current_alphabet.dup, current_alphabet.length)
171
+
172
+ ret.push unhash(sub_hash, current_alphabet)
173
+ time += 1
174
+ end
175
+
176
+ # Check if the result is consistent with the hash, this is important for safety since otherwise
177
+ # a random string could feasibly decode to a set of numbers
178
+ if encode(ret) != hash
179
+ ret = []
180
+ end
181
+ end
182
+
183
+ ret
184
+ end
185
+
186
+ def hash_one_number(hash_code, num, alphabet, alphabet_length)
187
+ char = nil
188
+ insert_at = 0
189
+ while true # standard:disable Style/InfiniteLoop
190
+ char = alphabet[num % alphabet_length]
191
+ insert_at -= 1
192
+ hash_code.insert(insert_at, char)
193
+ num /= alphabet_length
194
+ break unless num > 0
195
+ end
196
+
197
+ char
198
+ end
199
+
200
+ def unhash(input, alphabet)
201
+ num = 0
202
+ input_length = input.length
203
+ alphabet_length = alphabet.length
204
+ i = 0
205
+ while i < input_length
206
+ pos = alphabet.index(input[i].ord)
207
+
208
+ raise InvalidInputError, "unable to unhash" unless pos
209
+
210
+ num += pos * alphabet_length**(input_length - i - 1)
211
+ i += 1
212
+ end
213
+
214
+ num
215
+ end
216
+
217
+ private
218
+
219
+ def hex_string?(string)
220
+ string.to_s.match(/\A[0-9a-fA-F]+\Z/)
221
+ end
222
+
223
+ def consistent_shuffle!(collection_to_shuffle, salt_part_1, salt_part_2, max_salt_length)
224
+ HashIdConsistentShuffle.shuffle!(collection_to_shuffle, salt_part_1, salt_part_2, max_salt_length)
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EncodedId
4
+ class HashIdConsistentShuffle
5
+ def self.shuffle!(collection_to_shuffle, salt_part_1, salt_part_2, max_salt_length)
6
+ salt_part_1_length = salt_part_1.length
7
+ raise SaltError, "Salt is too short in shuffle" if salt_part_1_length < max_salt_length && salt_part_2.nil?
8
+
9
+ return collection_to_shuffle if collection_to_shuffle.empty? || max_salt_length == 0 || salt_part_1.nil? || salt_part_1_length == 0
10
+
11
+ idx = ord_total = 0
12
+ i = collection_to_shuffle.length - 1
13
+ while i >= 1
14
+ n = (idx >= salt_part_1_length) ? salt_part_2[idx - salt_part_1_length] : salt_part_1[idx]
15
+ ord_total += n
16
+ j = (n + idx + ord_total) % i
17
+
18
+ collection_to_shuffle[i], collection_to_shuffle[j] = collection_to_shuffle[j], collection_to_shuffle[i]
19
+
20
+ idx = (idx + 1) % max_salt_length
21
+ i -= 1
22
+ end
23
+
24
+ collection_to_shuffle
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EncodedId
4
+ class HashIdSalt
5
+ def initialize(salt)
6
+ unless salt.is_a?(String)
7
+ raise SaltError, "The salt must be a String"
8
+ end
9
+ @salt = salt.freeze
10
+ @chars = salt.chars.freeze
11
+ end
12
+
13
+ attr_reader :salt, :chars
14
+ end
15
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EncodedId
4
+ class OrdinalAlphabetSeparatorGuards
5
+ SEP_DIV = 3.5
6
+ DEFAULT_SEPS = "cfhistuCFHISTU".chars.map(&:ord).freeze
7
+ GUARD_DIV = 12.0
8
+ SPACE_CHAR = " ".ord
9
+
10
+ def initialize(alphabet, salt)
11
+ @alphabet = alphabet.characters.chars.map(&:ord)
12
+ @salt = salt.chars.map(&:ord)
13
+
14
+ setup_seps
15
+ setup_guards
16
+
17
+ @seps_tr_selector = escape_characters_string_for_tr(@seps.map(&:chr))
18
+ @guards_tr_selector = escape_characters_string_for_tr(@guards.map(&:chr))
19
+
20
+ @alphabet.freeze
21
+ @seps.freeze
22
+ @guards.freeze
23
+ end
24
+
25
+ attr_reader :salt, :alphabet, :seps, :guards, :seps_tr_selector, :guards_tr_selector
26
+
27
+ private
28
+
29
+ def escape_characters_string_for_tr(chars)
30
+ chars.join.gsub(/([-\\^])/) { "\\#{$1}" }
31
+ end
32
+
33
+ def setup_seps
34
+ @seps = DEFAULT_SEPS.dup
35
+
36
+ @seps.length.times do |i|
37
+ # Seps should only contain characters present in alphabet,
38
+ # and alphabet should not contains seps
39
+ if (j = @alphabet.index(@seps[i]))
40
+ @alphabet = pick_characters(@alphabet, j)
41
+ else
42
+ @seps = pick_characters(@seps, i)
43
+ end
44
+ end
45
+
46
+ @alphabet.delete(SPACE_CHAR)
47
+ @seps.delete(SPACE_CHAR)
48
+
49
+ consistent_shuffle!(@seps, @salt, nil, @salt.length)
50
+
51
+ if @seps.length == 0 || (@alphabet.length / @seps.length.to_f) > SEP_DIV
52
+ seps_length = (@alphabet.length / SEP_DIV).ceil
53
+ seps_length = 2 if seps_length == 1
54
+
55
+ if seps_length > @seps.length
56
+ diff = seps_length - @seps.length
57
+
58
+ @seps += @alphabet[0, diff]
59
+ @alphabet = @alphabet[diff..]
60
+ else
61
+ @seps = @seps[0, seps_length]
62
+ end
63
+ end
64
+
65
+ consistent_shuffle!(@alphabet, @salt, nil, @salt.length)
66
+ end
67
+
68
+ def setup_guards
69
+ gc = (@alphabet.length / GUARD_DIV).ceil
70
+
71
+ if @alphabet.length < 3
72
+ @guards = @seps[0, gc]
73
+ @seps = @seps[gc..]
74
+ else
75
+ @guards = @alphabet[0, gc]
76
+ @alphabet = @alphabet[gc..]
77
+ end
78
+ end
79
+
80
+ def pick_characters(array, index)
81
+ tail = array[index + 1..]
82
+ head = array[0, index] + [SPACE_CHAR] # This space seems pointless but the original code does it, and its needed to maintain the same result in shuffling
83
+ tail ? head + tail : head
84
+ end
85
+
86
+ def consistent_shuffle!(collection_to_shuffle, salt_part_1, salt_part_2, max_salt_length)
87
+ HashIdConsistentShuffle.shuffle!(collection_to_shuffle, salt_part_1, salt_part_2, max_salt_length)
88
+ end
89
+ end
90
+ end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "hashids"
4
-
5
3
  # Hashid with a reduced character set Crockford alphabet and split groups
6
4
  # See: https://www.crockford.com/wrmg/base32.html
7
5
  # Build with https://hashids.org
8
6
  # Note hashIds already has a built in profanity limitation algorithm
9
7
  module EncodedId
10
8
  class ReversibleId
11
- def initialize(salt:, length: 8, split_at: 4, split_with: "-", alphabet: Alphabet.modified_crockford, hex_digit_encoding_group_size: 4, max_length: 128)
9
+ def initialize(salt:, length: 8, split_at: 4, split_with: "-", alphabet: Alphabet.modified_crockford, hex_digit_encoding_group_size: 4, max_length: 128, max_inputs_per_id: 32)
12
10
  @alphabet = validate_alphabet(alphabet)
13
11
  @salt = validate_salt(salt)
14
12
  @length = validate_length(length)
@@ -16,13 +14,14 @@ module EncodedId
16
14
  @split_with = validate_split_with(split_with, alphabet)
17
15
  @hex_represention_encoder = HexRepresentation.new(hex_digit_encoding_group_size)
18
16
  @max_length = validate_max_length(max_length)
17
+ @max_inputs_per_id = validate_max_input(max_inputs_per_id)
19
18
  end
20
19
 
21
20
  # Encode the input values into a hash
22
21
  def encode(values)
23
22
  inputs = prepare_input(values)
24
23
  encoded_id = encoded_id_generator.encode(inputs)
25
- encoded_id = humanize_length(encoded_id) unless split_at.nil?
24
+ encoded_id = humanize_length(encoded_id) unless split_with.nil? || split_at.nil?
26
25
 
27
26
  raise EncodedIdLengthError if max_length_exceeded?(encoded_id)
28
27
 
@@ -36,10 +35,10 @@ module EncodedId
36
35
 
37
36
  # Decode the hash to original array
38
37
  def decode(str, downcase: true)
39
- raise InvalidInputError if max_length_exceeded?(str)
38
+ raise EncodedIdFormatError, "Max length of input exceeded" if max_length_exceeded?(str)
40
39
 
41
40
  encoded_id_generator.decode(convert_to_hash(str, downcase))
42
- rescue ::Hashids::InputError => e
41
+ rescue InvalidInputError => e
43
42
  raise EncodedIdFormatError, e.message
44
43
  end
45
44
 
@@ -80,6 +79,11 @@ module EncodedId
80
79
  raise InvalidConfigurationError, "Max length must be an integer greater than 0"
81
80
  end
82
81
 
82
+ def validate_max_input(max_inputs_per_id)
83
+ return max_inputs_per_id if valid_integer_option?(max_inputs_per_id)
84
+ raise InvalidConfigurationError, "Max inputs per ID must be an integer greater than 0"
85
+ end
86
+
83
87
  # Split the encoded string into groups of this size
84
88
  def validate_split_at(split_at)
85
89
  return split_at if valid_integer_option?(split_at) || split_at.nil?
@@ -87,8 +91,8 @@ module EncodedId
87
91
  end
88
92
 
89
93
  def validate_split_with(split_with, alphabet)
90
- return split_with if split_with.is_a?(String) && !alphabet.characters.include?(split_with)
91
- raise InvalidConfigurationError, "Split with must be a string and not part of the alphabet"
94
+ return split_with if split_with.nil? || (split_with.is_a?(String) && !alphabet.characters.include?(split_with))
95
+ raise InvalidConfigurationError, "Split with must be a string and not part of the alphabet or nil"
92
96
  end
93
97
 
94
98
  def valid_integer_option?(value)
@@ -99,11 +103,13 @@ module EncodedId
99
103
  inputs = value.is_a?(Array) ? value.map(&:to_i) : [value.to_i]
100
104
  raise ::EncodedId::InvalidInputError, "Integer IDs to be encoded can only be positive" if inputs.any?(&:negative?)
101
105
 
106
+ raise ::EncodedId::InvalidInputError, "%d integer IDs provided, maximum amount of IDs is %d" % [inputs.length, @max_inputs_per_id] if inputs.length > @max_inputs_per_id
107
+
102
108
  inputs
103
109
  end
104
110
 
105
111
  def encoded_id_generator
106
- @encoded_id_generator ||= ::Hashids.new(salt, length, alphabet.characters)
112
+ @encoded_id_generator ||= HashId.new(salt, length, alphabet)
107
113
  end
108
114
 
109
115
  def split_regex
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EncodedId
4
- VERSION = "1.0.0.rc3"
4
+ VERSION = "1.0.0.rc5"
5
5
  end
data/lib/encoded_id.rb CHANGED
@@ -3,6 +3,12 @@
3
3
  require_relative "encoded_id/version"
4
4
  require_relative "encoded_id/alphabet"
5
5
  require_relative "encoded_id/hex_representation"
6
+
7
+ require_relative "encoded_id/hash_id_salt"
8
+ require_relative "encoded_id/hash_id_consistent_shuffle"
9
+ require_relative "encoded_id/ordinal_alphabet_separator_guards"
10
+ require_relative "encoded_id/hash_id"
11
+
6
12
  require_relative "encoded_id/reversible_id"
7
13
 
8
14
  module EncodedId
@@ -15,4 +21,6 @@ module EncodedId
15
21
  class EncodedIdLengthError < ArgumentError; end
16
22
 
17
23
  class InvalidInputError < ArgumentError; end
24
+
25
+ class SaltError < ArgumentError; end
18
26
  end