sqids 0.1.2 → 0.2.0
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 +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:
|