hashids 1.0.2 → 1.0.6
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 +5 -5
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/tests.yml +30 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -1
- data/README.md +24 -2
- data/hashids.gemspec +1 -0
- data/lib/hashids.rb +23 -25
- data/spec/hashids_spec.rb +117 -109
- metadata +7 -6
- data/.travis.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9bd407187c5ce1192bccaa9c8a7ade234459074d81e6bd878814fa6d5bb2fe0d
|
4
|
+
data.tar.gz: 98c7b15fe5cea31af4764503c2f13948fe1c7034c5f0bd806cc5be35e04e186b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1ec375ecfe8ab134d5f5fbafad43fdd00253fdbf9c4ad16f00363b93a303df71fe380abe3b0b0bc5ea81f5bb730a6c1d3ddcba13711413b5767ce3ec679cae1
|
7
|
+
data.tar.gz: 9e8985ae3da3ab8909892e609afe967d4f10eaf6d52bb6e444de499024ac131eb923f0a094af2da5202534af0dea14d07b05ded59587183a083679889d34c3e6
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ko_fi: peterhellberg
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: Tests
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
timeout-minutes: 10
|
9
|
+
|
10
|
+
env:
|
11
|
+
RUBYOPT: "--enable=frozen-string-literal"
|
12
|
+
|
13
|
+
strategy:
|
14
|
+
fail-fast: false
|
15
|
+
matrix:
|
16
|
+
os: [ubuntu]
|
17
|
+
ruby: [2.6, 2.7, 3.0, jruby, jruby-head, truffleruby, truffleruby-head]
|
18
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v2
|
22
|
+
|
23
|
+
- name: Set up Ruby
|
24
|
+
uses: ruby/setup-ruby@v1
|
25
|
+
with:
|
26
|
+
ruby-version: ${{ matrix.ruby }}
|
27
|
+
bundler-cache: true # Runs also bundle install
|
28
|
+
|
29
|
+
- name: Run tests
|
30
|
+
run: bundle exec rake
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -5,8 +5,7 @@ Use hashids when you do not want to expose your database ids to the user.
|
|
5
5
|
|
6
6
|
[http://hashids.org/ruby/](http://hashids.org/ruby/)
|
7
7
|
|
8
|
-
[
|
8
|
+
[](https://github.com/peterhellberg/hashids.rb/actions/workflows/tests.yml)
|
10
9
|
|
11
10
|
## What is it?
|
12
11
|
|
@@ -208,6 +207,29 @@ hex_str = hashids.decode_hex("kRNrpKlJ")
|
|
208
207
|
|
209
208
|
## Changelog
|
210
209
|
|
210
|
+
**1.0.6**
|
211
|
+
|
212
|
+
- Fixed using lib with frozen strings
|
213
|
+
- Remove deprecated global use of `must_equal` and `must_raise`
|
214
|
+
- Use GitHub Actions instead of Travis-CI
|
215
|
+
|
216
|
+
**1.0.5**
|
217
|
+
|
218
|
+
- Improve shuffle performance
|
219
|
+
- Update rubies used by Travis-CI
|
220
|
+
|
221
|
+
**1.0.4**
|
222
|
+
|
223
|
+
- Improved encode/decode performance
|
224
|
+
|
225
|
+
**1.0.3**
|
226
|
+
|
227
|
+
- Support for Ruby 2.4.0
|
228
|
+
|
229
|
+
**1.0.2**
|
230
|
+
|
231
|
+
- Handle invalid input by raising InputError
|
232
|
+
|
211
233
|
**1.0.1**
|
212
234
|
|
213
235
|
- Final alphabet length can now be shorter than the minimum alphabet length
|
data/hashids.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.summary = %q{Generate YouTube-like hashes from one or many numbers.}
|
12
12
|
gem.description = %q{Use hashids when you do not want to expose your database ids to the user.}
|
13
13
|
gem.homepage = "https://github.com/peterhellberg/hashids.rb"
|
14
|
+
gem.license = "MIT"
|
14
15
|
|
15
16
|
gem.required_ruby_version = '>= 1.9.3'
|
16
17
|
|
data/lib/hashids.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
class Hashids
|
4
|
-
VERSION = "1.0.
|
4
|
+
VERSION = "1.0.6"
|
5
5
|
|
6
6
|
MIN_ALPHABET_LENGTH = 16
|
7
7
|
SEP_DIV = 3.5
|
@@ -26,11 +26,11 @@ class Hashids
|
|
26
26
|
def encode(*numbers)
|
27
27
|
numbers.flatten! if numbers.length == 1
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
numbers.map! { |n| Integer(n) } # raises if conversion fails
|
30
|
+
|
31
|
+
return '' if numbers.empty? || numbers.any? { |n| n < 0 }
|
32
|
+
|
33
|
+
internal_encode(numbers)
|
34
34
|
end
|
35
35
|
|
36
36
|
def encode_hex(str)
|
@@ -114,18 +114,18 @@ class Hashids
|
|
114
114
|
def internal_decode(hash, alphabet)
|
115
115
|
ret = []
|
116
116
|
|
117
|
-
breakdown = hash.
|
117
|
+
breakdown = hash.tr(@guards, " ")
|
118
118
|
array = breakdown.split(" ")
|
119
119
|
|
120
120
|
i = [3,2].include?(array.length) ? 1 : 0
|
121
121
|
|
122
122
|
if breakdown = array[i]
|
123
123
|
lottery = breakdown[0]
|
124
|
-
breakdown = breakdown[1 .. -1].
|
124
|
+
breakdown = breakdown[1 .. -1].tr(@seps, " ")
|
125
125
|
array = breakdown.split(" ")
|
126
126
|
|
127
|
-
array.length.times do |
|
128
|
-
sub_hash = array[
|
127
|
+
array.length.times do |time|
|
128
|
+
sub_hash = array[time]
|
129
129
|
buffer = lottery + salt + alphabet
|
130
130
|
alphabet = consistent_shuffle(alphabet, buffer[0, alphabet.length])
|
131
131
|
|
@@ -143,23 +143,21 @@ class Hashids
|
|
143
143
|
def consistent_shuffle(alphabet, salt)
|
144
144
|
return alphabet if salt.nil? || salt.empty?
|
145
145
|
|
146
|
-
|
147
|
-
|
146
|
+
chars = alphabet.each_char.to_a
|
147
|
+
salt_ords = salt.codepoints.to_a
|
148
|
+
salt_length = salt_ords.length
|
149
|
+
idx = ord_total = 0
|
148
150
|
|
149
151
|
(alphabet.length-1).downto(1) do |i|
|
150
|
-
|
151
|
-
|
152
|
-
j = (n + v + p) % i
|
153
|
-
|
154
|
-
tmp_char = alphabet[j]
|
152
|
+
ord_total += n = salt_ords[idx]
|
153
|
+
j = (n + idx + ord_total) % i
|
155
154
|
|
156
|
-
|
157
|
-
alphabet = alphabet[0, i] + tmp_char + alphabet[i + 1..-1]
|
155
|
+
chars[i], chars[j] = chars[j], chars[i]
|
158
156
|
|
159
|
-
|
157
|
+
idx = (idx + 1) % salt_length
|
160
158
|
end
|
161
159
|
|
162
|
-
|
160
|
+
chars.join
|
163
161
|
end
|
164
162
|
|
165
163
|
def hash(input, alphabet)
|
@@ -194,7 +192,7 @@ class Hashids
|
|
194
192
|
def setup_alphabet
|
195
193
|
validate_attributes
|
196
194
|
|
197
|
-
@alphabet = uniq_characters(alphabet)
|
195
|
+
@alphabet = String.new(uniq_characters(alphabet))
|
198
196
|
|
199
197
|
validate_alphabet
|
200
198
|
|
@@ -203,7 +201,7 @@ class Hashids
|
|
203
201
|
end
|
204
202
|
|
205
203
|
def setup_seps
|
206
|
-
@seps = DEFAULT_SEPS
|
204
|
+
@seps = String.new(DEFAULT_SEPS)
|
207
205
|
|
208
206
|
seps.length.times do |i|
|
209
207
|
# Seps should only contain characters present in alphabet,
|
@@ -259,8 +257,8 @@ class Hashids
|
|
259
257
|
raise SaltError, "The salt must be a String"
|
260
258
|
end
|
261
259
|
|
262
|
-
unless min_hash_length.kind_of?(
|
263
|
-
raise MinLengthError, "The min length must be a
|
260
|
+
unless min_hash_length.kind_of?(Integer)
|
261
|
+
raise MinLengthError, "The min length must be a Integer"
|
264
262
|
end
|
265
263
|
|
266
264
|
unless min_hash_length >= 0
|
data/spec/hashids_spec.rb
CHANGED
@@ -26,293 +26,301 @@ describe Hashids do
|
|
26
26
|
|
27
27
|
describe "setup" do
|
28
28
|
it "has a default alphabet" do
|
29
|
-
Hashids::DEFAULT_ALPHABET.must_equal default_alphabet
|
29
|
+
_(Hashids::DEFAULT_ALPHABET).must_equal default_alphabet
|
30
30
|
end
|
31
31
|
|
32
32
|
it "has default separators" do
|
33
|
-
Hashids::DEFAULT_SEPS.must_equal default_seps
|
33
|
+
_(Hashids::DEFAULT_SEPS).must_equal default_seps
|
34
34
|
end
|
35
35
|
|
36
36
|
it "has a default salt" do
|
37
|
-
Hashids.new.encode(1,2,3).must_equal "o2fXhV"
|
37
|
+
_(Hashids.new.encode(1,2,3)).must_equal "o2fXhV"
|
38
38
|
end
|
39
39
|
|
40
40
|
it "has the correct salt" do
|
41
|
-
hashids.instance_variable_get(:@salt).must_equal salt
|
41
|
+
_(hashids.instance_variable_get(:@salt)).must_equal salt
|
42
42
|
end
|
43
43
|
|
44
44
|
it "defaults to a min_length of 0" do
|
45
|
-
hashids.instance_variable_get(:@min_hash_length).must_equal 0
|
45
|
+
_(hashids.instance_variable_get(:@min_hash_length)).must_equal 0
|
46
46
|
end
|
47
47
|
|
48
48
|
it "generates the correct seps" do
|
49
|
-
hashids.instance_variable_get(:@seps).must_equal seps
|
49
|
+
_(hashids.instance_variable_get(:@seps)).must_equal seps
|
50
50
|
end
|
51
51
|
|
52
52
|
it "generates the correct @guards" do
|
53
|
-
hashids.instance_variable_get(:@guards).must_equal guards
|
53
|
+
_(hashids.instance_variable_get(:@guards)).must_equal guards
|
54
54
|
end
|
55
55
|
|
56
56
|
it "generates the correct alphabet" do
|
57
|
-
hashids.instance_variable_get(:@alphabet).must_equal alphabet
|
57
|
+
_(hashids.instance_variable_get(:@alphabet)).must_equal alphabet
|
58
58
|
end
|
59
59
|
|
60
60
|
it "has a minimum alphabet length" do
|
61
|
-
-> {
|
61
|
+
_(-> {
|
62
62
|
Hashids.new("", 0, 'shortalphabet')
|
63
|
-
}.must_raise Hashids::AlphabetError
|
63
|
+
}).must_raise Hashids::AlphabetError
|
64
64
|
end
|
65
65
|
|
66
66
|
it "has a final alphabet length that can be shorter than the minimum" do
|
67
|
-
Hashids.new("this is my salt", 0, 'cfhistuCFHISTU01').
|
68
|
-
alphabet.must_equal "10"
|
67
|
+
_(Hashids.new("this is my salt", 0, 'cfhistuCFHISTU01').
|
68
|
+
alphabet).must_equal "10"
|
69
69
|
end
|
70
70
|
|
71
71
|
it "checks the alphabet for spaces" do
|
72
|
-
-> {
|
72
|
+
_(-> {
|
73
73
|
Hashids.new("", 0, 'abc odefghijklmnopqrstuv')
|
74
|
-
}.must_raise Hashids::AlphabetError
|
74
|
+
}).must_raise Hashids::AlphabetError
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
78
|
describe "encode" do
|
79
79
|
it "encodes a single number" do
|
80
|
-
hashids.encode(12345).must_equal 'NkK9'
|
80
|
+
_(hashids.encode(12345)).must_equal 'NkK9'
|
81
81
|
|
82
82
|
hashids.tap do |h|
|
83
|
-
h.encode(-1).must_equal ''
|
84
|
-
h.encode(1).must_equal 'NV'
|
85
|
-
h.encode(22).must_equal 'K4'
|
86
|
-
h.encode(333).must_equal 'OqM'
|
87
|
-
h.encode(9999).must_equal 'kQVg'
|
88
|
-
h.encode(123_000).must_equal '58LzD'
|
89
|
-
h.encode(456_000_000).must_equal '5gn6mQP'
|
90
|
-
h.encode(987_654_321).must_equal 'oyjYvry'
|
83
|
+
_(h.encode(-1)).must_equal ''
|
84
|
+
_(h.encode(1)).must_equal 'NV'
|
85
|
+
_(h.encode(22)).must_equal 'K4'
|
86
|
+
_(h.encode(333)).must_equal 'OqM'
|
87
|
+
_(h.encode(9999)).must_equal 'kQVg'
|
88
|
+
_(h.encode(123_000)).must_equal '58LzD'
|
89
|
+
_(h.encode(456_000_000)).must_equal '5gn6mQP'
|
90
|
+
_(h.encode(987_654_321)).must_equal 'oyjYvry'
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
94
|
it "can encode a list of numbers" do
|
95
95
|
hashids.tap do |h|
|
96
|
-
h.encode(1,2,3).must_equal "laHquq"
|
97
|
-
h.encode(2,4,6).must_equal "44uotN"
|
98
|
-
h.encode(99,25).must_equal "97Jun"
|
96
|
+
_(h.encode(1,2,3)).must_equal "laHquq"
|
97
|
+
_(h.encode(2,4,6)).must_equal "44uotN"
|
98
|
+
_(h.encode(99,25)).must_equal "97Jun"
|
99
99
|
|
100
|
-
h.encode(1337,42,314).
|
100
|
+
_(h.encode(1337,42,314)).
|
101
101
|
must_equal "7xKhrUxm"
|
102
102
|
|
103
|
-
h.encode(683, 94108, 123, 5).
|
103
|
+
_(h.encode(683, 94108, 123, 5)).
|
104
104
|
must_equal "aBMswoO2UB3Sj"
|
105
105
|
|
106
|
-
h.encode(547, 31, 241271, 311, 31397, 1129, 71129).
|
106
|
+
_(h.encode(547, 31, 241271, 311, 31397, 1129, 71129)).
|
107
107
|
must_equal "3RoSDhelEyhxRsyWpCx5t1ZK"
|
108
108
|
|
109
|
-
h.encode(21979508, 35563591, 57543099, 93106690, 150649789).
|
109
|
+
_(h.encode(21979508, 35563591, 57543099, 93106690, 150649789)).
|
110
110
|
must_equal "p2xkL3CK33JjcrrZ8vsw4YRZueZX9k"
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
114
|
it "can encode a list of numbers passed in as an array" do
|
115
|
-
hashids.encode([1,2,3]).must_equal "laHquq"
|
115
|
+
_(hashids.encode([1,2,3])).must_equal "laHquq"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "can encode string encoded number" do
|
119
|
+
_(hashids.encode('1')).must_equal "NV"
|
120
|
+
_(hashids.encode('-1')).must_equal ""
|
121
|
+
end
|
122
|
+
|
123
|
+
it "raises exception if integer conversion fails" do
|
124
|
+
_(-> { hashids.encode('-') }).must_raise ArgumentError
|
116
125
|
end
|
117
126
|
|
118
127
|
it "returns an empty string if no numbers" do
|
119
|
-
hashids.encode.must_equal ""
|
128
|
+
_(hashids.encode).must_equal ""
|
120
129
|
end
|
121
130
|
|
122
131
|
it "returns an empty string if any of the numbers are negative" do
|
123
|
-
hashids.encode(-1).must_equal ""
|
124
|
-
hashids.encode(10,-10).must_equal ""
|
132
|
+
_(hashids.encode(-1)).must_equal ""
|
133
|
+
_(hashids.encode(10,-10)).must_equal ""
|
125
134
|
end
|
126
135
|
|
127
136
|
it "can encode to a minumum length" do
|
128
137
|
h = Hashids.new(salt, 18)
|
129
|
-
h.encode(1).must_equal "aJEDngB0NV05ev1WwP"
|
138
|
+
_(h.encode(1)).must_equal "aJEDngB0NV05ev1WwP"
|
130
139
|
|
131
|
-
h.encode(4140, 21147, 115975, 678570, 4213597, 27644437).
|
140
|
+
_(h.encode(4140, 21147, 115975, 678570, 4213597, 27644437)).
|
132
141
|
must_equal "pLMlCWnJSXr1BSpKgqUwbJ7oimr7l6"
|
133
142
|
end
|
134
143
|
|
135
144
|
it "can encode with a custom alphabet" do
|
136
145
|
h = Hashids.new(salt, 0, "ABCDEFGhijklmn34567890-:")
|
137
|
-
h.encode(1,2,3,4,5).must_equal "6nhmFDikA0"
|
146
|
+
_(h.encode(1,2,3,4,5)).must_equal "6nhmFDikA0"
|
138
147
|
end
|
139
148
|
|
140
149
|
it "does not produce repeating patterns for identical numbers" do
|
141
|
-
hashids.encode(5,5,5,5).must_equal "1Wc8cwcE"
|
150
|
+
_(hashids.encode(5,5,5,5)).must_equal "1Wc8cwcE"
|
142
151
|
end
|
143
152
|
|
144
153
|
it "does not produce repeating patterns for incremented numbers" do
|
145
|
-
hashids.encode(*(1..10).to_a).must_equal "kRHnurhptKcjIDTWC3sx"
|
154
|
+
_(hashids.encode(*(1..10).to_a)).must_equal "kRHnurhptKcjIDTWC3sx"
|
146
155
|
end
|
147
156
|
|
148
157
|
it "does not produce similarities between incrementing number hashes" do
|
149
|
-
hashids.encode(1).must_equal 'NV'
|
150
|
-
hashids.encode(2).must_equal '6m'
|
151
|
-
hashids.encode(3).must_equal 'yD'
|
152
|
-
hashids.encode(4).must_equal '2l'
|
153
|
-
hashids.encode(5).must_equal 'rD'
|
158
|
+
_(hashids.encode(1)).must_equal 'NV'
|
159
|
+
_(hashids.encode(2)).must_equal '6m'
|
160
|
+
_(hashids.encode(3)).must_equal 'yD'
|
161
|
+
_(hashids.encode(4)).must_equal '2l'
|
162
|
+
_(hashids.encode(5)).must_equal 'rD'
|
154
163
|
end
|
155
164
|
end
|
156
165
|
|
157
166
|
describe "encode_hex" do
|
158
167
|
it "encodes hex string" do
|
159
168
|
hashids.tap { |h|
|
160
|
-
h.encode_hex("FA").must_equal "lzY"
|
161
|
-
h.encode_hex("26dd").must_equal "MemE"
|
162
|
-
h.encode_hex("FF1A").must_equal "eBMrb"
|
163
|
-
h.encode_hex("12abC").must_equal "D9NPE"
|
164
|
-
h.encode_hex("185b0").must_equal "9OyNW"
|
165
|
-
h.encode_hex("17b8d").must_equal "MRWNE"
|
166
|
-
|
167
|
-
h.encode_hex("1d7f21dd38").must_equal "4o6Z7KqxE"
|
168
|
-
h.encode_hex("20015111d").must_equal "ooweQVNB"
|
169
|
+
_(h.encode_hex("FA")).must_equal "lzY"
|
170
|
+
_(h.encode_hex("26dd")).must_equal "MemE"
|
171
|
+
_(h.encode_hex("FF1A")).must_equal "eBMrb"
|
172
|
+
_(h.encode_hex("12abC")).must_equal "D9NPE"
|
173
|
+
_(h.encode_hex("185b0")).must_equal "9OyNW"
|
174
|
+
_(h.encode_hex("17b8d")).must_equal "MRWNE"
|
175
|
+
|
176
|
+
_(h.encode_hex("1d7f21dd38")).must_equal "4o6Z7KqxE"
|
177
|
+
_(h.encode_hex("20015111d")).must_equal "ooweQVNB"
|
169
178
|
}
|
170
179
|
end
|
171
180
|
|
172
181
|
it "returns an empty string if passed non-hex string" do
|
173
|
-
hashids.encode_hex("XYZ123").must_equal ""
|
182
|
+
_(hashids.encode_hex("XYZ123")).must_equal ""
|
174
183
|
end
|
175
184
|
end
|
176
185
|
|
177
186
|
describe "decode" do
|
178
187
|
it "decodes an encoded number" do
|
179
|
-
hashids.decode("NkK9").must_equal [12345]
|
180
|
-
hashids.decode("5O8yp5P").must_equal [666555444]
|
181
|
-
hashids.decode("KVO9yy1oO5j").must_equal [666555444333222]
|
188
|
+
_(hashids.decode("NkK9")).must_equal [12345]
|
189
|
+
_(hashids.decode("5O8yp5P")).must_equal [666555444]
|
190
|
+
_(hashids.decode("KVO9yy1oO5j")).must_equal [666555444333222]
|
182
191
|
|
183
192
|
hashids.tap { |h|
|
184
|
-
h.decode("Wzo").must_equal [1337]
|
185
|
-
h.decode("DbE").must_equal [808]
|
186
|
-
h.decode("yj8").must_equal [303]
|
193
|
+
_(h.decode("Wzo")).must_equal [1337]
|
194
|
+
_(h.decode("DbE")).must_equal [808]
|
195
|
+
_(h.decode("yj8")).must_equal [303]
|
187
196
|
}
|
188
197
|
end
|
189
198
|
|
190
199
|
it "decodes a list of encoded numbers" do
|
191
|
-
hashids.decode("1gRYUwKxBgiVuX").must_equal [66655,5444333,2,22]
|
192
|
-
hashids.decode('aBMswoO2UB3Sj').must_equal [683, 94108, 123, 5]
|
200
|
+
_(hashids.decode("1gRYUwKxBgiVuX")).must_equal [66655,5444333,2,22]
|
201
|
+
_(hashids.decode('aBMswoO2UB3Sj')).must_equal [683, 94108, 123, 5]
|
193
202
|
|
194
203
|
hashids.tap { |h|
|
195
|
-
h.decode('jYhp').must_equal [3, 4]
|
196
|
-
h.decode('k9Ib').must_equal [6, 5]
|
204
|
+
_(h.decode('jYhp')).must_equal [3, 4]
|
205
|
+
_(h.decode('k9Ib')).must_equal [6, 5]
|
197
206
|
|
198
|
-
h.decode('EMhN').must_equal [31, 41]
|
199
|
-
h.decode('glSgV').must_equal [13, 89]
|
207
|
+
_(h.decode('EMhN')).must_equal [31, 41]
|
208
|
+
_(h.decode('glSgV')).must_equal [13, 89]
|
200
209
|
}
|
201
210
|
end
|
202
211
|
|
203
212
|
it "does not decode with a different salt" do
|
204
213
|
peppers = Hashids.new('this is my pepper')
|
205
214
|
|
206
|
-
hashids.decode('NkK9').must_equal [12345]
|
207
|
-
peppers.decode('NkK9').must_equal []
|
215
|
+
_(hashids.decode('NkK9')).must_equal [12345]
|
216
|
+
_(peppers.decode('NkK9')).must_equal []
|
208
217
|
end
|
209
218
|
|
210
219
|
it "can decode from a hash with a minimum length" do
|
211
220
|
h = Hashids.new(salt, 8)
|
212
|
-
h.decode("gB0NV05e").must_equal [1]
|
221
|
+
_(h.decode("gB0NV05e")).must_equal [1]
|
213
222
|
|
214
|
-
h.decode("mxi8XH87").must_equal [25, 100, 950]
|
215
|
-
h.decode("KQcmkIW8hX").must_equal [5,200,195, 1]
|
223
|
+
_(h.decode("mxi8XH87")).must_equal [25, 100, 950]
|
224
|
+
_(h.decode("KQcmkIW8hX")).must_equal [5,200,195, 1]
|
216
225
|
end
|
217
226
|
|
218
227
|
it "handles invalid input by raising InputError" do
|
219
|
-
-> { hashids.decode('asdf-') }.must_raise Hashids::InputError
|
228
|
+
_(-> { hashids.decode('asdf-') }).must_raise Hashids::InputError
|
220
229
|
end
|
221
230
|
end
|
222
231
|
|
223
232
|
describe "decode_hex" do
|
224
233
|
it "decodes hex string" do
|
225
|
-
hashids.decode_hex("lzY").must_equal "FA"
|
226
|
-
hashids.decode_hex("eBMrb").must_equal "FF1A"
|
227
|
-
hashids.decode_hex("D9NPE").must_equal "12ABC"
|
234
|
+
_(hashids.decode_hex("lzY")).must_equal "FA"
|
235
|
+
_(hashids.decode_hex("eBMrb")).must_equal "FF1A"
|
236
|
+
_(hashids.decode_hex("D9NPE")).must_equal "12ABC"
|
228
237
|
end
|
229
238
|
end
|
230
239
|
|
231
240
|
describe "setup" do
|
232
241
|
it "raises an exception if the alphabet has less than 16 unique chars" do
|
233
|
-
-> { Hashids.new('salt', 0, 'abc') }.
|
242
|
+
_(-> { Hashids.new('salt', 0, 'abc') }).
|
234
243
|
must_raise Hashids::AlphabetError
|
235
244
|
end
|
236
245
|
end
|
237
246
|
|
238
247
|
describe "validation of attributes" do
|
239
248
|
it "raises an ArgumentError unless the salt is a String" do
|
240
|
-
-> { Hashids.new(:not_a_string) }.
|
249
|
+
_(-> { Hashids.new(:not_a_string) }).
|
241
250
|
must_raise Hashids::SaltError
|
242
251
|
end
|
243
252
|
|
244
|
-
it "raises an ArgumentError unless the min_length is
|
245
|
-
-> { Hashids.new('salt', :
|
253
|
+
it "raises an ArgumentError unless the min_length is an Integer" do
|
254
|
+
_(-> { Hashids.new('salt', :not_an_integer)}).
|
246
255
|
must_raise Hashids::MinLengthError
|
247
256
|
end
|
248
257
|
|
249
258
|
it "raises an ArgumentError unless the alphabet is a String" do
|
250
|
-
-> { Hashids.new('salt', 2, :not_a_string) }.
|
259
|
+
_(-> { Hashids.new('salt', 2, :not_a_string) }).
|
251
260
|
must_raise Hashids::AlphabetError
|
252
261
|
end
|
253
262
|
end
|
254
263
|
|
255
264
|
describe "protected methods" do
|
256
|
-
|
257
265
|
describe "unhash" do
|
258
266
|
it "unhashes" do
|
259
|
-
hashids.send(:unhash, 'bb', 'abc').must_equal 4
|
260
|
-
hashids.send(:unhash, 'aaa', 'abc').must_equal 0
|
261
|
-
hashids.send(:unhash, 'cba', 'abc').must_equal 21
|
262
|
-
hashids.send(:unhash, 'cbaabc', 'abc').must_equal 572
|
263
|
-
hashids.send(:unhash, 'aX11b', 'abcXYZ123').must_equal 2728
|
267
|
+
_(hashids.send(:unhash, 'bb', 'abc')).must_equal 4
|
268
|
+
_(hashids.send(:unhash, 'aaa', 'abc')).must_equal 0
|
269
|
+
_(hashids.send(:unhash, 'cba', 'abc')).must_equal 21
|
270
|
+
_(hashids.send(:unhash, 'cbaabc', 'abc')).must_equal 572
|
271
|
+
_(hashids.send(:unhash, 'aX11b', 'abcXYZ123')).must_equal 2728
|
264
272
|
end
|
265
273
|
end
|
266
274
|
|
267
275
|
describe "internal_decode" do
|
268
276
|
it "decodes" do
|
269
|
-
hashids.send(:internal_decode, 'NV', alphabet).must_equal [1]
|
277
|
+
_(hashids.send(:internal_decode, 'NV', alphabet)).must_equal [1]
|
270
278
|
end
|
271
279
|
end
|
272
280
|
|
273
281
|
describe "consistent_shuffle" do
|
274
282
|
it "returns the alphabet if empty salt" do
|
275
|
-
hashids.send(:consistent_shuffle, default_alphabet, '').
|
283
|
+
_(hashids.send(:consistent_shuffle, default_alphabet, '')).
|
276
284
|
must_equal default_alphabet
|
277
285
|
end
|
278
286
|
|
279
287
|
it "shuffles consistently" do
|
280
|
-
hashids.send(:consistent_shuffle, 'ab', salt).must_equal 'ba'
|
281
|
-
hashids.send(:consistent_shuffle, 'abc', salt).must_equal 'bca'
|
282
|
-
hashids.send(:consistent_shuffle, 'abcd', salt).must_equal 'cadb'
|
283
|
-
hashids.send(:consistent_shuffle, 'abcde', salt).must_equal 'dceba'
|
288
|
+
_(hashids.send(:consistent_shuffle, 'ab', salt)).must_equal 'ba'
|
289
|
+
_(hashids.send(:consistent_shuffle, 'abc', salt)).must_equal 'bca'
|
290
|
+
_(hashids.send(:consistent_shuffle, 'abcd', salt)).must_equal 'cadb'
|
291
|
+
_(hashids.send(:consistent_shuffle, 'abcde', salt)).must_equal 'dceba'
|
284
292
|
|
285
|
-
hashids.send(:consistent_shuffle, default_alphabet, 'salt').
|
293
|
+
_(hashids.send(:consistent_shuffle, default_alphabet, 'salt')).
|
286
294
|
must_equal "f17a8zvCwo0iuqYDXlJ4RmAS2end5gh" +
|
287
295
|
"TcpjbOWLK9GFyE6xUI3ZBMQtPsNHrkV"
|
288
296
|
|
289
|
-
hashids.send(:consistent_shuffle, 'abcdefghijklmnopqrstuvwxyz', salt).
|
297
|
+
_(hashids.send(:consistent_shuffle, 'abcdefghijklmnopqrstuvwxyz', salt)).
|
290
298
|
must_equal 'fcaodykrgqvblxjwmtupzeisnh'
|
291
299
|
end
|
292
300
|
end
|
293
301
|
|
294
302
|
describe "hash" do
|
295
303
|
it "hashes" do
|
296
|
-
hashids.send(:hash, 12, 'abcdefg').must_equal "bf"
|
297
|
-
hashids.send(:hash, 42, 'abcdefg').must_equal "ga"
|
298
|
-
hashids.send(:hash, 123, 'abcdefg').must_equal "cde"
|
299
|
-
hashids.send(:hash, 1024, 'abcdefg').must_equal "cggc"
|
300
|
-
hashids.send(:hash, 950000, 'abcdefg').must_equal "bbadeefc"
|
301
|
-
hashids.send(:hash, 950000, 'åäö-ÅÄÖ').must_equal "ääå-ÅÅÄö"
|
302
|
-
hashids.send(:hash, 3500000, 'abcdefg').must_equal "ebfbfaea"
|
303
|
-
hashids.send(:hash, 3500000, 'Xyz01-å').must_equal "1y-y-X1X"
|
304
|
+
_(hashids.send(:hash, 12, 'abcdefg')).must_equal "bf"
|
305
|
+
_(hashids.send(:hash, 42, 'abcdefg')).must_equal "ga"
|
306
|
+
_(hashids.send(:hash, 123, 'abcdefg')).must_equal "cde"
|
307
|
+
_(hashids.send(:hash, 1024, 'abcdefg')).must_equal "cggc"
|
308
|
+
_(hashids.send(:hash, 950000, 'abcdefg')).must_equal "bbadeefc"
|
309
|
+
_(hashids.send(:hash, 950000, 'åäö-ÅÄÖ')).must_equal "ääå-ÅÅÄö"
|
310
|
+
_(hashids.send(:hash, 3500000, 'abcdefg')).must_equal "ebfbfaea"
|
311
|
+
_(hashids.send(:hash, 3500000, 'Xyz01-å')).must_equal "1y-y-X1X"
|
304
312
|
end
|
305
313
|
end
|
306
314
|
|
307
315
|
describe "unhash" do
|
308
316
|
it "unhashes" do
|
309
|
-
hashids.send(:unhash, 'abbd', 'abcdefg').must_equal 59
|
310
|
-
hashids.send(:unhash, 'abcd', 'abcdefg').must_equal 66
|
311
|
-
hashids.send(:unhash, 'acac', 'abcdefg').must_equal 100
|
312
|
-
hashids.send(:unhash, 'acfg', 'abcdefg').must_equal 139
|
313
|
-
hashids.send(:unhash, 'x21y', 'xyz1234').must_equal 218
|
314
|
-
hashids.send(:unhash, 'yy44', 'xyz1234').must_equal 440
|
315
|
-
hashids.send(:unhash, '1xzz', 'xyz1234').must_equal 1045
|
317
|
+
_(hashids.send(:unhash, 'abbd', 'abcdefg')).must_equal 59
|
318
|
+
_(hashids.send(:unhash, 'abcd', 'abcdefg')).must_equal 66
|
319
|
+
_(hashids.send(:unhash, 'acac', 'abcdefg')).must_equal 100
|
320
|
+
_(hashids.send(:unhash, 'acfg', 'abcdefg')).must_equal 139
|
321
|
+
_(hashids.send(:unhash, 'x21y', 'xyz1234')).must_equal 218
|
322
|
+
_(hashids.send(:unhash, 'yy44', 'xyz1234')).must_equal 440
|
323
|
+
_(hashids.send(:unhash, '1xzz', 'xyz1234')).must_equal 1045
|
316
324
|
end
|
317
325
|
end
|
318
326
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashids
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Hellberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Use hashids when you do not want to expose your database ids to the user.
|
14
14
|
email:
|
@@ -17,8 +17,9 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- ".github/FUNDING.yml"
|
21
|
+
- ".github/workflows/tests.yml"
|
20
22
|
- ".gitignore"
|
21
|
-
- ".travis.yml"
|
22
23
|
- Gemfile
|
23
24
|
- LICENSE.txt
|
24
25
|
- README.md
|
@@ -27,7 +28,8 @@ files:
|
|
27
28
|
- lib/hashids.rb
|
28
29
|
- spec/hashids_spec.rb
|
29
30
|
homepage: https://github.com/peterhellberg/hashids.rb
|
30
|
-
licenses:
|
31
|
+
licenses:
|
32
|
+
- MIT
|
31
33
|
metadata: {}
|
32
34
|
post_install_message:
|
33
35
|
rdoc_options: []
|
@@ -44,8 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
46
|
- !ruby/object:Gem::Version
|
45
47
|
version: '0'
|
46
48
|
requirements: []
|
47
|
-
|
48
|
-
rubygems_version: 2.4.3
|
49
|
+
rubygems_version: 3.2.3
|
49
50
|
signing_key:
|
50
51
|
specification_version: 4
|
51
52
|
summary: Generate YouTube-like hashes from one or many numbers.
|