sqids 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +9 -9
- data/lib/sqids.rb +37 -56
- data/spec/alphabet_spec.rb +9 -3
- data/spec/blocklist_spec.rb +37 -22
- data/spec/encoding_spec.rb +32 -37
- data/spec/minlength_spec.rb +39 -13
- data/spec/uniques_spec.rb +1 -1
- data/sqids.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f504d0947f3ffd6f0fe3f9dfb4044a056b4c0d30a9d2b95a8ac5b5a043a5c45b
|
4
|
+
data.tar.gz: 62fc2e00992383a7632b5f2a155ecfc09a2d221db4e2a31c505b8c54ea6ec12e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 596b48c403f99904706390dfeb23cfd9c59a075da4d970fada135aa75b9a54e39744bfd810de68b62852c7effe64fe21e3edf376d8f965455a8add0a594ab66e
|
7
|
+
data.tar.gz: 74fbcc76ed257c80fd0a03fc4133ccb1b897ec62381c5377c84b873e372bc58d777194359e2765a67d9e4e38cbac5927a89336eec9a2b0241fe11e29d2e92bc6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
**v0.2.0:** **⚠️ BREAKING CHANGE**
|
4
|
+
- **Breaking change**: IDs change. Algorithm has been fine-tuned for better performance [[Issue #11](https://github.com/sqids/sqids-spec/issues/11)]
|
5
|
+
- `alphabet` cannot contain multibyte characters
|
6
|
+
- `min_length` upper limit has increased from alphabet length to `255`
|
7
|
+
- Max blocklist re-encoding attempts has been capped at the length of the alphabet - 1
|
8
|
+
- Minimum alphabet length has changed from 5 to 3
|
9
|
+
- `min_value()` and `max_value()` functions have been removed
|
10
|
+
|
3
11
|
**v0.1.2:**
|
4
12
|
- Bug fix: spec update (PR #7): blocklist filtering in uppercase-only alphabet [[PR #7](https://github.com/sqids/sqids-spec/pull/7)]
|
5
13
|
- Lower uniques test from 1_000_000 to 10_000
|
data/README.md
CHANGED
@@ -55,34 +55,34 @@ Simple encode & decode:
|
|
55
55
|
|
56
56
|
```ruby
|
57
57
|
sqids = Sqids.new
|
58
|
-
id = sqids.encode([1, 2, 3]) # '
|
58
|
+
id = sqids.encode([1, 2, 3]) # '86Rf07'
|
59
59
|
numbers = sqids.decode(id) # [1, 2, 3]
|
60
60
|
```
|
61
61
|
|
62
62
|
> **Note**
|
63
63
|
> 🚧 Because of the algorithm's design, **multiple IDs can decode back into the same sequence of numbers**. If it's important to your design that IDs are canonical, you have to manually re-encode decoded numbers and check that the generated ID matches.
|
64
64
|
|
65
|
-
|
65
|
+
Enforce a *minimum* length for IDs:
|
66
66
|
|
67
67
|
```ruby
|
68
|
-
sqids = Sqids.new(
|
69
|
-
id = sqids.encode([1, 2, 3]) # '
|
68
|
+
sqids = Sqids.new(min_length: 10)
|
69
|
+
id = sqids.encode([1, 2, 3]) # '86Rf07xd4z'
|
70
70
|
numbers = sqids.decode(id) # [1, 2, 3]
|
71
71
|
```
|
72
72
|
|
73
|
-
|
73
|
+
Randomize IDs by providing a custom alphabet:
|
74
74
|
|
75
75
|
```ruby
|
76
|
-
sqids = Sqids.new(
|
77
|
-
id = sqids.encode([1, 2, 3]) # '
|
76
|
+
sqids = Sqids.new(alphabet: 'FxnXM1kBN6cuhsAvjW3Co7l2RePyY8DwaU04Tzt9fHQrqSVKdpimLGIJOgb5ZE')
|
77
|
+
id = sqids.encode([1, 2, 3]) # 'B4aajs'
|
78
78
|
numbers = sqids.decode(id) # [1, 2, 3]
|
79
79
|
```
|
80
80
|
|
81
81
|
Prevent specific words from appearing anywhere in the auto-generated IDs:
|
82
82
|
|
83
83
|
```ruby
|
84
|
-
sqids = Sqids.new(blocklist: Set.new(%w[
|
85
|
-
id = sqids.encode([1, 2, 3]) # '
|
84
|
+
sqids = Sqids.new(blocklist: Set.new(%w[86Rf07]))
|
85
|
+
id = sqids.encode([1, 2, 3]) # 'se8ojk'
|
86
86
|
numbers = sqids.decode(id) # [1, 2, 3]
|
87
87
|
```
|
88
88
|
|
data/lib/sqids.rb
CHANGED
@@ -15,16 +15,18 @@ class Sqids
|
|
15
15
|
min_length = options[:min_length] || DEFAULT_MIN_LENGTH
|
16
16
|
blocklist = options[:blocklist] || DEFAULT_BLOCKLIST
|
17
17
|
|
18
|
-
raise ArgumentError, 'Alphabet
|
18
|
+
raise ArgumentError, 'Alphabet cannot contain multibyte characters' if contains_multibyte_chars(alphabet)
|
19
|
+
raise ArgumentError, 'Alphabet length must be at least 3' if alphabet.length < 3
|
19
20
|
|
20
21
|
if alphabet.chars.uniq.size != alphabet.length
|
21
22
|
raise ArgumentError,
|
22
23
|
'Alphabet must contain unique characters'
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
+
min_length_limit = 255
|
27
|
+
unless min_length.is_a?(Integer) && min_length >= 0 && min_length <= min_length_limit
|
26
28
|
raise TypeError,
|
27
|
-
"Minimum length has to be between
|
29
|
+
"Minimum length has to be between 0 and #{min_length_limit}"
|
28
30
|
end
|
29
31
|
|
30
32
|
filtered_blocklist = blocklist.select do |word|
|
@@ -39,13 +41,13 @@ class Sqids
|
|
39
41
|
def encode(numbers)
|
40
42
|
return '' if numbers.empty?
|
41
43
|
|
42
|
-
in_range_numbers = numbers.select { |n| n >=
|
44
|
+
in_range_numbers = numbers.select { |n| n >= 0 && n <= Sqids.max_value }
|
43
45
|
unless in_range_numbers.length == numbers.length
|
44
46
|
raise ArgumentError,
|
45
|
-
"Encoding supports numbers between
|
47
|
+
"Encoding supports numbers between 0 and #{Sqids.max_value}"
|
46
48
|
end
|
47
49
|
|
48
|
-
encode_numbers(in_range_numbers
|
50
|
+
encode_numbers(in_range_numbers)
|
49
51
|
end
|
50
52
|
|
51
53
|
def decode(id)
|
@@ -61,26 +63,18 @@ class Sqids
|
|
61
63
|
prefix = id[0]
|
62
64
|
offset = @alphabet.index(prefix)
|
63
65
|
alphabet = @alphabet.slice(offset, @alphabet.length) + @alphabet.slice(0, offset)
|
64
|
-
|
65
|
-
alphabet = alphabet.slice(2, alphabet.length)
|
66
|
+
alphabet = alphabet.reverse
|
66
67
|
|
67
68
|
id = id[1, id.length]
|
68
69
|
|
69
|
-
partition_index = id.index(partition)
|
70
|
-
if !partition_index.nil? && partition_index.positive? && partition_index < id.length - 1
|
71
|
-
id = id[partition_index + 1, id.length]
|
72
|
-
alphabet = shuffle(alphabet)
|
73
|
-
end
|
74
|
-
|
75
70
|
while id.length.positive?
|
76
|
-
separator = alphabet[
|
77
|
-
chunks = id.split(separator, 2)
|
71
|
+
separator = alphabet[0]
|
78
72
|
|
73
|
+
chunks = id.split(separator, 2)
|
79
74
|
if chunks.any?
|
80
|
-
|
81
|
-
return [] unless chunks[0].chars.all? { |c| alphabet_without_separator.include?(c) }
|
75
|
+
return ret if chunks[0] == ''
|
82
76
|
|
83
|
-
ret.push(to_number(chunks[0],
|
77
|
+
ret.push(to_number(chunks[0], alphabet.slice(1, alphabet.length - 1)))
|
84
78
|
alphabet = shuffle(alphabet) if chunks.length > 1
|
85
79
|
end
|
86
80
|
|
@@ -90,14 +84,6 @@ class Sqids
|
|
90
84
|
ret
|
91
85
|
end
|
92
86
|
|
93
|
-
def self.min_value
|
94
|
-
0
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.max_value
|
98
|
-
defined?(Integer::MAX) ? Integer::MAX : ((2**((0.size * 8) - 2)) - 1)
|
99
|
-
end
|
100
|
-
|
101
87
|
private
|
102
88
|
|
103
89
|
def shuffle(alphabet)
|
@@ -115,59 +101,42 @@ class Sqids
|
|
115
101
|
chars.join
|
116
102
|
end
|
117
103
|
|
118
|
-
def encode_numbers(numbers,
|
104
|
+
def encode_numbers(numbers, increment: 0)
|
105
|
+
raise ArgumentError, 'Reached max attempts to re-generate the ID' if increment > @alphabet.length
|
106
|
+
|
119
107
|
offset = numbers.length
|
120
108
|
numbers.each_with_index do |v, i|
|
121
109
|
offset += @alphabet[v % @alphabet.length].ord + i
|
122
110
|
end
|
123
111
|
offset = offset % @alphabet.length
|
112
|
+
offset = (offset + increment) % @alphabet.length
|
124
113
|
|
125
114
|
alphabet = @alphabet.slice(offset, @alphabet.length) + @alphabet.slice(0, offset)
|
126
115
|
prefix = alphabet[0]
|
127
|
-
|
128
|
-
alphabet = alphabet.slice(2, alphabet.length)
|
116
|
+
alphabet = alphabet.reverse
|
129
117
|
ret = [prefix]
|
130
118
|
|
131
119
|
numbers.each_with_index do |num, i|
|
132
|
-
|
133
|
-
ret.push(to_id(num, alphabet_without_separator))
|
120
|
+
ret.push(to_id(num, alphabet.slice(1, alphabet.length - 1)))
|
134
121
|
|
135
122
|
next unless i < numbers.length - 1
|
136
123
|
|
137
|
-
|
138
|
-
if partitioned && i.zero?
|
139
|
-
ret.push(partition)
|
140
|
-
else
|
141
|
-
ret.push(separator)
|
142
|
-
end
|
143
|
-
|
124
|
+
ret.push(alphabet[0])
|
144
125
|
alphabet = shuffle(alphabet)
|
145
126
|
end
|
146
127
|
|
147
128
|
id = ret.join
|
148
129
|
|
149
130
|
if @min_length > id.length
|
150
|
-
|
151
|
-
numbers = [0] + numbers
|
152
|
-
id = encode_numbers(numbers, partitioned: true)
|
153
|
-
end
|
131
|
+
id += alphabet[0]
|
154
132
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
id.length - 1]
|
133
|
+
while (@min_length - id.length).positive?
|
134
|
+
alphabet = shuffle(alphabet)
|
135
|
+
id += alphabet.slice(0, [@min_length - id.length, alphabet.length].min)
|
159
136
|
end
|
160
137
|
end
|
161
138
|
|
162
|
-
if blocked_id?(id)
|
163
|
-
if partitioned
|
164
|
-
numbers[0] += 1
|
165
|
-
else
|
166
|
-
numbers = [0] + numbers
|
167
|
-
end
|
168
|
-
|
169
|
-
id = encode_numbers(numbers, partitioned: true)
|
170
|
-
end
|
139
|
+
id = encode_numbers(numbers, increment: increment + 1) if blocked_id?(id)
|
171
140
|
|
172
141
|
id
|
173
142
|
end
|
@@ -206,4 +175,16 @@ class Sqids
|
|
206
175
|
end
|
207
176
|
end
|
208
177
|
end
|
178
|
+
|
179
|
+
def contains_multibyte_chars(input_str)
|
180
|
+
input_str.each_char do |char|
|
181
|
+
return true if char.bytesize > 1
|
182
|
+
end
|
183
|
+
|
184
|
+
false
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.max_value
|
188
|
+
defined?(Integer::MAX) ? Integer::MAX : ((2**((0.size * 8) - 2)) - 1)
|
189
|
+
end
|
209
190
|
end
|
data/spec/alphabet_spec.rb
CHANGED
@@ -8,14 +8,14 @@ describe Sqids do
|
|
8
8
|
sqids = Sqids.new(alphabet: '0123456789abcdef')
|
9
9
|
|
10
10
|
numbers = [1, 2, 3]
|
11
|
-
id = '
|
11
|
+
id = '489158'
|
12
12
|
|
13
13
|
expect(sqids.encode(numbers)).to eq(id)
|
14
14
|
expect(sqids.decode(id)).to eq(numbers)
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'decodes after encoding with a short alphabet' do
|
18
|
-
sqids = Sqids.new(alphabet: '
|
18
|
+
sqids = Sqids.new(alphabet: 'abc')
|
19
19
|
|
20
20
|
numbers = [1, 2, 3]
|
21
21
|
encoded = sqids.encode(numbers)
|
@@ -33,6 +33,12 @@ describe Sqids do
|
|
33
33
|
expect(sqids.decode(encoded)).to eq(numbers)
|
34
34
|
end
|
35
35
|
|
36
|
+
it 'fails when alphabet has multibyte characters' do
|
37
|
+
expect do
|
38
|
+
Sqids.new(alphabet: 'ë1092')
|
39
|
+
end.to raise_error(ArgumentError)
|
40
|
+
end
|
41
|
+
|
36
42
|
it 'fails when alphabet characters are repeated' do
|
37
43
|
expect do
|
38
44
|
Sqids.new(alphabet: 'aabcdefg')
|
@@ -41,7 +47,7 @@ describe Sqids do
|
|
41
47
|
|
42
48
|
it 'fails when alphabet is too short' do
|
43
49
|
expect do
|
44
|
-
Sqids.new(alphabet: '
|
50
|
+
Sqids.new(alphabet: 'ab')
|
45
51
|
end.to raise_error(ArgumentError)
|
46
52
|
end
|
47
53
|
end
|
data/spec/blocklist_spec.rb
CHANGED
@@ -8,59 +8,74 @@ describe Sqids do
|
|
8
8
|
it 'uses default blocklist if no custom blocklist is provided' do
|
9
9
|
sqids = Sqids.new
|
10
10
|
|
11
|
-
expect(sqids.decode('
|
12
|
-
expect(sqids.encode([
|
11
|
+
expect(sqids.decode('aho1e')).to eq([4_572_721])
|
12
|
+
expect(sqids.encode([4_572_721])).to eq('JExTR')
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'does not use any blocklist if an empty blocklist is provided' do
|
16
16
|
sqids = Sqids.new(blocklist: Set.new([]))
|
17
17
|
|
18
|
-
expect(sqids.decode('
|
19
|
-
expect(sqids.encode([
|
18
|
+
expect(sqids.decode('aho1e')).to eq([4_572_721])
|
19
|
+
expect(sqids.encode([4_572_721])).to eq('aho1e')
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'uses provided blocklist if non-empty blocklist is provided' do
|
23
|
-
sqids = Sqids.new(blocklist: Set.new(['
|
23
|
+
sqids = Sqids.new(blocklist: Set.new(['ArUO']))
|
24
24
|
|
25
|
-
expect(sqids.decode('
|
26
|
-
expect(sqids.encode([
|
25
|
+
expect(sqids.decode('aho1e')).to eq([4_572_721])
|
26
|
+
expect(sqids.encode([4_572_721])).to eq('aho1e')
|
27
27
|
|
28
|
-
expect(sqids.decode('
|
29
|
-
expect(sqids.encode([100_000])).to eq('
|
30
|
-
expect(sqids.decode('
|
28
|
+
expect(sqids.decode('ArUO')).to eq([100_000])
|
29
|
+
expect(sqids.encode([100_000])).to eq('QyG4')
|
30
|
+
expect(sqids.decode('QyG4')).to eq([100_000])
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'uses blocklist to prevent certain encodings' do
|
34
|
-
sqids = Sqids.new(blocklist: Set.new(%w[
|
34
|
+
sqids = Sqids.new(blocklist: Set.new(%w[JSwXFaosAN OCjV9JK64o rBHf 79SM 7tE6]))
|
35
35
|
|
36
|
-
expect(sqids.encode([
|
37
|
-
expect(sqids.decode('
|
36
|
+
expect(sqids.encode([1_000_000, 2_000_000])).to eq('1aYeB7bRUt')
|
37
|
+
expect(sqids.decode('1aYeB7bRUt')).to eq([1_000_000, 2_000_000])
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'can decode blocklist words' do
|
41
|
-
sqids = Sqids.new(blocklist: Set.new(%w[
|
41
|
+
sqids = Sqids.new(blocklist: Set.new(%w[86Rf07 se8ojk ARsz1p Q8AI49 5sQRZO]))
|
42
42
|
|
43
|
-
expect(sqids.decode('
|
44
|
-
expect(sqids.decode('
|
45
|
-
expect(sqids.decode('
|
46
|
-
expect(sqids.decode('
|
47
|
-
expect(sqids.decode('
|
43
|
+
expect(sqids.decode('86Rf07')).to eq([1, 2, 3])
|
44
|
+
expect(sqids.decode('se8ojk')).to eq([1, 2, 3])
|
45
|
+
expect(sqids.decode('ARsz1p')).to eq([1, 2, 3])
|
46
|
+
expect(sqids.decode('Q8AI49')).to eq([1, 2, 3])
|
47
|
+
expect(sqids.decode('5sQRZO')).to eq([1, 2, 3])
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'matches against a short blocklist word' do
|
51
|
-
sqids = Sqids.new(blocklist: Set.new(['
|
51
|
+
sqids = Sqids.new(blocklist: Set.new(['pnd']))
|
52
52
|
|
53
53
|
expect(sqids.decode(sqids.encode([1_000]))).to eq([1_000])
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'blocklist filtering in constructor' do
|
57
57
|
# lowercase blocklist in only-uppercase alphabet
|
58
|
-
sqids = Sqids.new(alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', blocklist: Set.new(['
|
58
|
+
sqids = Sqids.new(alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', blocklist: Set.new(['sxnzkl']))
|
59
59
|
|
60
60
|
id = sqids.encode([1, 2, 3])
|
61
61
|
numbers = sqids.decode(id)
|
62
62
|
|
63
|
-
expect(id).to eq('
|
63
|
+
expect(id).to eq('IBSHOZ') # without blocklist, would've been "SXNZKL"
|
64
64
|
expect(numbers).to eq([1, 2, 3])
|
65
65
|
end
|
66
|
+
|
67
|
+
it 'max encoding attempts' do
|
68
|
+
alphabet = 'abc'
|
69
|
+
min_length = 3
|
70
|
+
blocklist = Set.new(%w[cab abc bca])
|
71
|
+
|
72
|
+
sqids = Sqids.new(alphabet: alphabet, min_length: min_length, blocklist: blocklist)
|
73
|
+
|
74
|
+
expect(min_length).to eq(alphabet.length)
|
75
|
+
expect(min_length).to eq(blocklist.size)
|
76
|
+
|
77
|
+
expect do
|
78
|
+
sqids.encode([0])
|
79
|
+
end.to raise_error(ArgumentError)
|
80
|
+
end
|
66
81
|
end
|
data/spec/encoding_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe 'Sqids' do
|
|
8
8
|
sqids = Sqids.new
|
9
9
|
|
10
10
|
numbers = [1, 2, 3]
|
11
|
-
id = '
|
11
|
+
id = '86Rf07'
|
12
12
|
|
13
13
|
expect(sqids.encode(numbers)).to eq(id)
|
14
14
|
expect(sqids.decode(id)).to eq(numbers)
|
@@ -25,16 +25,16 @@ describe 'Sqids' do
|
|
25
25
|
sqids = Sqids.new
|
26
26
|
|
27
27
|
ids = {
|
28
|
-
'
|
29
|
-
'
|
30
|
-
'
|
31
|
-
'
|
32
|
-
'
|
33
|
-
'
|
34
|
-
'
|
35
|
-
'
|
36
|
-
'
|
37
|
-
'
|
28
|
+
'bM' => [0],
|
29
|
+
'Uk' => [1],
|
30
|
+
'gb' => [2],
|
31
|
+
'Ef' => [3],
|
32
|
+
'Vq' => [4],
|
33
|
+
'uw' => [5],
|
34
|
+
'OI' => [6],
|
35
|
+
'AX' => [7],
|
36
|
+
'p6' => [8],
|
37
|
+
'nJ' => [9]
|
38
38
|
}
|
39
39
|
|
40
40
|
ids.each do |id, numbers|
|
@@ -47,16 +47,16 @@ describe 'Sqids' do
|
|
47
47
|
sqids = Sqids.new
|
48
48
|
|
49
49
|
ids = {
|
50
|
-
'
|
51
|
-
'
|
52
|
-
'
|
53
|
-
'
|
54
|
-
'
|
55
|
-
'
|
56
|
-
'
|
57
|
-
'
|
58
|
-
'
|
59
|
-
'
|
50
|
+
'SvIz' => [0, 0],
|
51
|
+
'n3qa' => [0, 1],
|
52
|
+
'tryF' => [0, 2],
|
53
|
+
'eg6q' => [0, 3],
|
54
|
+
'rSCF' => [0, 4],
|
55
|
+
'sR8x' => [0, 5],
|
56
|
+
'uY2M' => [0, 6],
|
57
|
+
'74dI' => [0, 7],
|
58
|
+
'30WX' => [0, 8],
|
59
|
+
'moxr' => [0, 9]
|
60
60
|
}
|
61
61
|
|
62
62
|
ids.each do |id, numbers|
|
@@ -69,16 +69,16 @@ describe 'Sqids' do
|
|
69
69
|
sqids = Sqids.new
|
70
70
|
|
71
71
|
ids = {
|
72
|
-
'
|
73
|
-
'
|
74
|
-
'
|
75
|
-
'
|
76
|
-
'
|
77
|
-
'
|
78
|
-
'
|
79
|
-
'
|
80
|
-
'
|
81
|
-
'
|
72
|
+
'SvIz' => [0, 0],
|
73
|
+
'nWqP' => [1, 0],
|
74
|
+
'tSyw' => [2, 0],
|
75
|
+
'eX68' => [3, 0],
|
76
|
+
'rxCY' => [4, 0],
|
77
|
+
'sV8a' => [5, 0],
|
78
|
+
'uf2K' => [6, 0],
|
79
|
+
'7Cdk' => [7, 0],
|
80
|
+
'3aWP' => [8, 0],
|
81
|
+
'm2xn' => [9, 0]
|
82
82
|
}
|
83
83
|
|
84
84
|
ids.each do |id, numbers|
|
@@ -110,14 +110,9 @@ describe 'Sqids' do
|
|
110
110
|
expect(sqids.decode('*')).to eq([])
|
111
111
|
end
|
112
112
|
|
113
|
-
it 'decoding an invalid ID with a repeating reserved character' do
|
114
|
-
sqids = Sqids.new
|
115
|
-
expect(sqids.decode('fff')).to eq([])
|
116
|
-
end
|
117
|
-
|
118
113
|
it 'encode out-of-range numbers' do
|
119
114
|
sqids = Sqids.new
|
120
|
-
expect { sqids.encode([
|
115
|
+
expect { sqids.encode([-1]) }.to raise_error(ArgumentError)
|
121
116
|
expect { sqids.encode([Sqids.max_value + 1]) }.to raise_error(ArgumentError)
|
122
117
|
end
|
123
118
|
end
|
data/spec/minlength_spec.rb
CHANGED
@@ -10,26 +10,52 @@ describe Sqids do
|
|
10
10
|
sqids = Sqids.new(min_length: default_alphabet.length)
|
11
11
|
|
12
12
|
numbers = [1, 2, 3]
|
13
|
-
id = '
|
13
|
+
id = '86Rf07xd4zBmiJXQG6otHEbew02c3PWsUOLZxADhCpKj7aVFv9I8RquYrNlSTM'
|
14
14
|
|
15
15
|
expect(sqids.encode(numbers)).to eq(id)
|
16
16
|
expect(sqids.decode(id)).to eq(numbers)
|
17
17
|
end
|
18
18
|
|
19
|
+
it 'encodes and decodes incremental' do
|
20
|
+
numbers = [1, 2, 3]
|
21
|
+
map = {
|
22
|
+
6 => '86Rf07',
|
23
|
+
7 => '86Rf07x',
|
24
|
+
8 => '86Rf07xd',
|
25
|
+
9 => '86Rf07xd4',
|
26
|
+
10 => '86Rf07xd4z',
|
27
|
+
11 => '86Rf07xd4zB',
|
28
|
+
12 => '86Rf07xd4zBm',
|
29
|
+
13 => '86Rf07xd4zBmi'
|
30
|
+
}
|
31
|
+
map[default_alphabet.length + 0] = '86Rf07xd4zBmiJXQG6otHEbew02c3PWsUOLZxADhCpKj7aVFv9I8RquYrNlSTM'
|
32
|
+
map[default_alphabet.length + 1] = '86Rf07xd4zBmiJXQG6otHEbew02c3PWsUOLZxADhCpKj7aVFv9I8RquYrNlSTMy'
|
33
|
+
map[default_alphabet.length + 2] = '86Rf07xd4zBmiJXQG6otHEbew02c3PWsUOLZxADhCpKj7aVFv9I8RquYrNlSTMyf'
|
34
|
+
map[default_alphabet.length + 3] = '86Rf07xd4zBmiJXQG6otHEbew02c3PWsUOLZxADhCpKj7aVFv9I8RquYrNlSTMyf1'
|
35
|
+
|
36
|
+
map.each do |min_length, id|
|
37
|
+
sqids = Sqids.new(min_length: min_length)
|
38
|
+
|
39
|
+
expect(sqids.encode(numbers)).to eq(id)
|
40
|
+
expect(sqids.encode(numbers).length).to eq(min_length)
|
41
|
+
expect(sqids.decode(id)).to eq(numbers)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
19
45
|
it 'encodes and decodes incremental numbers' do
|
20
46
|
sqids = Sqids.new(min_length: default_alphabet.length)
|
21
47
|
|
22
48
|
ids = {
|
23
|
-
'
|
24
|
-
'
|
25
|
-
'
|
26
|
-
'
|
27
|
-
'
|
28
|
-
'
|
29
|
-
'
|
30
|
-
'
|
31
|
-
'
|
32
|
-
'
|
49
|
+
'SvIzsqYMyQwI3GWgJAe17URxX8V924Co0DaTZLtFjHriEn5bPhcSkfmvOslpBu' => [0, 0],
|
50
|
+
'n3qafPOLKdfHpuNw3M61r95svbeJGk7aAEgYn4WlSjXURmF8IDqZBy0CT2VxQc' => [0, 1],
|
51
|
+
'tryFJbWcFMiYPg8sASm51uIV93GXTnvRzyfLleh06CpodJD42B7OraKtkQNxUZ' => [0, 2],
|
52
|
+
'eg6ql0A3XmvPoCzMlB6DraNGcWSIy5VR8iYup2Qk4tjZFKe1hbwfgHdUTsnLqE' => [0, 3],
|
53
|
+
'rSCFlp0rB2inEljaRdxKt7FkIbODSf8wYgTsZM1HL9JzN35cyoqueUvVWCm4hX' => [0, 4],
|
54
|
+
'sR8xjC8WQkOwo74PnglH1YFdTI0eaf56RGVSitzbjuZ3shNUXBrqLxEJyAmKv2' => [0, 5],
|
55
|
+
'uY2MYFqCLpgx5XQcjdtZK286AwWV7IBGEfuS9yTmbJvkzoUPeYRHr4iDs3naN0' => [0, 6],
|
56
|
+
'74dID7X28VLQhBlnGmjZrec5wTA1fqpWtK4YkaoEIM9SRNiC3gUJH0OFvsPDdy' => [0, 7],
|
57
|
+
'30WXpesPhgKiEI5RHTY7xbB1GnytJvXOl2p0AcUjdF6waZDo9Qk8VLzMuWrqCS' => [0, 8],
|
58
|
+
'moxr3HqLAK0GsTND6jowfZz3SUx7cQ8aC54Pl1RbIvFXmEJuBMYVeW9yrdOtin' => [0, 9]
|
33
59
|
}
|
34
60
|
|
35
61
|
ids.each do |id, numbers|
|
@@ -41,7 +67,7 @@ describe Sqids do
|
|
41
67
|
it 'encodes with different min lengths' do
|
42
68
|
[0, 1, 5, 10, default_alphabet.length].each do |min_length|
|
43
69
|
[
|
44
|
-
[
|
70
|
+
[0],
|
45
71
|
[0, 0, 0, 0, 0],
|
46
72
|
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
47
73
|
[100, 200, 300],
|
@@ -60,6 +86,6 @@ describe Sqids do
|
|
60
86
|
|
61
87
|
it 'raises error for out-of-range invalid min lengths' do
|
62
88
|
expect { Sqids.new(min_length: -1) }.to raise_error(TypeError)
|
63
|
-
expect { Sqids.new(min_length:
|
89
|
+
expect { Sqids.new(min_length: 256) }.to raise_error(TypeError)
|
64
90
|
end
|
65
91
|
end
|
data/spec/uniques_spec.rb
CHANGED
data/sqids.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqids
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sqids Maintainers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|