hashids 0.3.0 → 1.0.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/.travis.yml +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +48 -40
- data/Rakefile +0 -10
- data/lib/hashids.rb +33 -23
- data/spec/hashids_spec.rb +86 -78
- metadata +7 -9
- data/spec/hashids_profile.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9ecc5fa611d4448889d020379a0a2ea2475e6b9
|
4
|
+
data.tar.gz: 700c86ac657671ca5f973ab22b21e3072cab3057
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b0acfa4caffe611002a1dc0b93780ecd9f4f6cca128b65727fd3d0c9e1aac86c7ff6ff1c07aad6a58e835798b4a01be9bfc72900e1a06cfed960c66aacfda8f
|
7
|
+
data.tar.gz: 356964b48a8056faa446552a8e40d123cd3345defdf27f4db7018fdd69df34cad142ee40687f7c44e704d851fa70e3c65913b5cb9e87f48e29bd4d9c00635765
|
data/.travis.yml
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
# Hashids
|
2
2
|
|
3
|
-
A small Ruby gem to generate YouTube-like
|
3
|
+
A small Ruby gem to generate YouTube-like ids from one or many numbers.
|
4
4
|
Use hashids when you do not want to expose your database ids to the user.
|
5
5
|
|
6
|
-
[http://
|
6
|
+
[http://hashids.org/ruby/](http://hashids.org/ruby/)
|
7
7
|
|
8
8
|
[](http://travis-ci.org/peterhellberg/hashids.rb)
|
9
|
-
(1.
|
9
|
+
(2.1.2, 2.0.0, 1.9.3, jruby-19mode, rbx-19mode)
|
10
10
|
|
11
11
|
## What is it?
|
12
12
|
|
13
|
-
hashids (Hash ID's) creates short, unique,
|
13
|
+
hashids (Hash ID's) creates short, unique, decodable hashes from unsigned integers.
|
14
14
|
|
15
15
|
_(NOTE: This is **NOT** a true cryptographic hash, since it is reversible)_
|
16
16
|
|
17
|
-
It was designed for websites to use in URL shortening, tracking stuff, or
|
17
|
+
It was designed for websites to use in URL shortening, tracking stuff, or
|
18
18
|
making pages private (or at least unguessable).
|
19
19
|
|
20
20
|
This algorithm tries to satisfy the following requirements:
|
21
21
|
|
22
|
-
1. Hashes must be unique and
|
22
|
+
1. Hashes must be unique and decodable.
|
23
23
|
2. They should be able to contain more than one integer (so you can use them in complex or clustered systems).
|
24
24
|
3. You should be able to specify minimum hash length.
|
25
25
|
4. Hashes should not contain basic English curse words (since they are meant to appear in public places - like the URL).
|
26
26
|
|
27
27
|
Instead of showing items as `1`, `2`, or `3`, you could show them as `jR`, `k5`, and `l5`.
|
28
|
-
You don't have to store these hashes in the database, but can
|
28
|
+
You don't have to store these hashes in the database, but can encode + decode on the fly.
|
29
29
|
|
30
30
|
All integers need to be greater than or equal to zero.
|
31
31
|
|
@@ -45,87 +45,87 @@ Or install it yourself as:
|
|
45
45
|
|
46
46
|
## Usage
|
47
47
|
|
48
|
-
###
|
48
|
+
### Encoding one number
|
49
49
|
|
50
|
-
You can pass a unique salt value so your hashes differ from everyone else's.
|
50
|
+
You can pass a unique salt value so your hashes differ from everyone else's.
|
51
51
|
I use **this is my salt** as an example.
|
52
52
|
|
53
53
|
```ruby
|
54
54
|
hashids = Hashids.new("this is my salt")
|
55
|
-
hash = hashids.
|
55
|
+
hash = hashids.encode(12345)
|
56
56
|
```
|
57
57
|
|
58
58
|
`hash` is now going to be:
|
59
59
|
|
60
60
|
NkK9
|
61
61
|
|
62
|
-
###
|
62
|
+
### Decoding
|
63
63
|
|
64
|
-
Notice during
|
64
|
+
Notice during decoding, same salt value is used:
|
65
65
|
|
66
66
|
```ruby
|
67
67
|
hashids = Hashids.new("this is my salt")
|
68
|
-
numbers = hashids.
|
68
|
+
numbers = hashids.decode("NkK9")
|
69
69
|
```
|
70
70
|
|
71
71
|
`numbers` is now going to be:
|
72
72
|
|
73
73
|
[ 12345 ]
|
74
74
|
|
75
|
-
###
|
75
|
+
### Decoding with different salt
|
76
76
|
|
77
|
-
|
77
|
+
Decoding will not work if salt is changed:
|
78
78
|
|
79
79
|
```ruby
|
80
80
|
hashids = Hashids.new("this is my pepper")
|
81
|
-
numbers = hashids.
|
81
|
+
numbers = hashids.decode("NkK9")
|
82
82
|
```
|
83
83
|
|
84
84
|
`numbers` is now going to be:
|
85
85
|
|
86
86
|
[]
|
87
87
|
|
88
|
-
###
|
88
|
+
### Encoding several numbers
|
89
89
|
|
90
90
|
```ruby
|
91
91
|
hashids = Hashids.new("this is my salt")
|
92
|
-
hash = hashids.
|
92
|
+
hash = hashids.encode(683, 94108, 123, 5)
|
93
93
|
```
|
94
94
|
|
95
95
|
`hash` is now going to be:
|
96
96
|
|
97
97
|
aBMswoO2UB3Sj
|
98
|
-
|
99
|
-
###
|
98
|
+
|
99
|
+
### Decoding is done the same way
|
100
100
|
|
101
101
|
```ruby
|
102
102
|
hashids = Hashids.new("this is my salt")
|
103
|
-
numbers = hashids.
|
103
|
+
numbers = hashids.decode("aBMswoO2UB3Sj")
|
104
104
|
```
|
105
105
|
|
106
106
|
`numbers` is now going to be:
|
107
107
|
|
108
108
|
[ 683, 94108, 123, 5 ]
|
109
109
|
|
110
|
-
###
|
110
|
+
### Encoding and specifying minimum hash length
|
111
111
|
|
112
|
-
Here we
|
112
|
+
Here we encode integer 1, and set the minimum hash length to **8**
|
113
113
|
(by default it's **0** -- meaning hashes will be the shortest possible length).
|
114
114
|
|
115
115
|
```ruby
|
116
116
|
hashids = Hashids.new("this is my salt", 8)
|
117
|
-
hash = hashids.
|
117
|
+
hash = hashids.encode(1)
|
118
118
|
```
|
119
119
|
|
120
120
|
`hash` is now going to be:
|
121
121
|
|
122
122
|
gB0NV05e
|
123
123
|
|
124
|
-
###
|
124
|
+
### Decoding with minimum hash length
|
125
125
|
|
126
126
|
```ruby
|
127
127
|
hashids = Hashids.new("this is my salt", 8)
|
128
|
-
numbers = hashids.
|
128
|
+
numbers = hashids.decode("gB0NV05e")
|
129
129
|
```
|
130
130
|
|
131
131
|
`numbers` is now going to be:
|
@@ -138,7 +138,7 @@ Here we set the alphabet to consist of: "abcdefghijkABCDEFGHIJK12345"
|
|
138
138
|
|
139
139
|
```ruby
|
140
140
|
hashids = Hashids.new("this is my salt", 0, "abcdefghijkABCDEFGHIJK12345")
|
141
|
-
hash = hashids.
|
141
|
+
hash = hashids.encode(1, 2, 3, 4, 5)
|
142
142
|
```
|
143
143
|
|
144
144
|
`hash` is now going to be:
|
@@ -154,7 +154,7 @@ Having said that, this algorithm does try to make these hashes unguessable and u
|
|
154
154
|
|
155
155
|
```ruby
|
156
156
|
hashids = Hashids.new("this is my salt")
|
157
|
-
hash = hashids.
|
157
|
+
hash = hashids.encode(5, 5, 5, 5)
|
158
158
|
```
|
159
159
|
|
160
160
|
You don't see any repeating patterns that might show there's 4 identical numbers in the hash:
|
@@ -165,41 +165,41 @@ Same with incremented numbers:
|
|
165
165
|
|
166
166
|
```ruby
|
167
167
|
hashids = Hashids.new("this is my salt")
|
168
|
-
hash = hashids.
|
168
|
+
hash = hashids.encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
169
169
|
```
|
170
170
|
|
171
171
|
`hash` is now going to be:
|
172
172
|
|
173
173
|
kRHnurhptKcjIDTWC3sx
|
174
174
|
|
175
|
-
### Incrementing number
|
175
|
+
### Incrementing number ids:
|
176
176
|
|
177
177
|
```ruby
|
178
178
|
hashids = Hashids.new("this is my salt")
|
179
179
|
|
180
|
-
hashids.
|
181
|
-
hashids.
|
182
|
-
hashids.
|
183
|
-
hashids.
|
184
|
-
hashids.
|
180
|
+
hashids.encode 1 #=> NV
|
181
|
+
hashids.encode 2 #=> 6m
|
182
|
+
hashids.encode 3 #=> yD
|
183
|
+
hashids.encode 4 #=> 2l
|
184
|
+
hashids.encode 5 #=> rD
|
185
185
|
```
|
186
186
|
|
187
|
-
###
|
187
|
+
### Encoding using a HEX string
|
188
188
|
|
189
189
|
```ruby
|
190
190
|
hashids = Hashids.new("this is my salt")
|
191
|
-
hash = hashids.
|
191
|
+
hash = hashids.encode_hex('DEADBEEF')
|
192
192
|
```
|
193
193
|
|
194
194
|
`hash` is now going to be:
|
195
195
|
|
196
196
|
kRNrpKlJ
|
197
197
|
|
198
|
-
###
|
198
|
+
### Decoding to a HEX string
|
199
199
|
|
200
200
|
```ruby
|
201
201
|
hashids = Hashids.new("this is my salt")
|
202
|
-
hex_str = hashids.
|
202
|
+
hex_str = hashids.decode_hex("kRNrpKlJ")
|
203
203
|
```
|
204
204
|
|
205
205
|
`hex_str` is now going to be:
|
@@ -208,6 +208,14 @@ hex_str = hashids.decrypt_hex("kRNrpKlJ")
|
|
208
208
|
|
209
209
|
## Changelog
|
210
210
|
|
211
|
+
**1.0.0**
|
212
|
+
|
213
|
+
- Public functions renamed to be more appropriate:
|
214
|
+
- `encrypt` changed to `encode`
|
215
|
+
- `encrypt_hex` changed to `encode_hex`
|
216
|
+
- `decrypt` changed to `decode`
|
217
|
+
- `decrypt_hex` changed to `decode_hex`
|
218
|
+
|
211
219
|
**0.3.0**
|
212
220
|
|
213
221
|
- Bumped the version number since hashids.rb now support the new algorithm
|
@@ -224,7 +232,7 @@ hex_str = hashids.decrypt_hex("kRNrpKlJ")
|
|
224
232
|
- Using scan over split where appropriate
|
225
233
|
|
226
234
|
**0.0.1**
|
227
|
-
|
235
|
+
|
228
236
|
- First commit (Heavily based on the [CoffeeScript version](https://github.com/ivanakimov/hashids.coffee))
|
229
237
|
|
230
238
|
## Contact
|
data/Rakefile
CHANGED
@@ -6,13 +6,3 @@ task :default => :spec
|
|
6
6
|
Rake::TestTask.new(:spec) do |t|
|
7
7
|
t.test_files = FileList['spec/**/*_spec.rb']
|
8
8
|
end
|
9
|
-
|
10
|
-
task :profile do
|
11
|
-
Bundler.with_clean_env do
|
12
|
-
exec 'CPUPROFILE=/tmp/hashids_profile ' +
|
13
|
-
'RUBYOPT="-r`gem which \'perftools.rb\' | tail -1`" ' +
|
14
|
-
'ruby spec/hashids_profile.rb && ' +
|
15
|
-
'pprof.rb --gif /tmp/hashids_profile > /tmp/hashids_profile.gif && ' +
|
16
|
-
'open /tmp/hashids_profile.gif'
|
17
|
-
end
|
18
|
-
end
|
data/lib/hashids.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
class Hashids
|
4
|
-
VERSION
|
4
|
+
VERSION = "1.0.0"
|
5
5
|
|
6
6
|
MIN_ALPHABET_LENGTH = 16
|
7
7
|
SEP_DIV = 3.5
|
8
8
|
GUARD_DIV = 12.0
|
9
9
|
|
10
|
+
DEFAULT_SEPS = "cfhistuCFHISTU"
|
11
|
+
|
10
12
|
DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyz" +
|
11
13
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
12
14
|
"1234567890"
|
@@ -21,36 +23,35 @@ class Hashids
|
|
21
23
|
setup_alphabet
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
26
|
+
def encode(*numbers)
|
25
27
|
numbers.flatten! if numbers.length == 1
|
26
28
|
|
27
29
|
if numbers.empty? || numbers.reject { |n| Integer(n) && n >= 0 }.any?
|
28
30
|
""
|
29
31
|
else
|
30
|
-
|
32
|
+
internal_encode(numbers)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
35
|
-
return "" unless str
|
36
|
+
def encode_hex(str)
|
37
|
+
return "" unless hex_string?(str)
|
36
38
|
|
37
39
|
numbers = str.scan(/[\w\W]{1,12}/).map do |num|
|
38
40
|
"1#{num}".to_i(16)
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
encode(numbers)
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
46
|
+
def decode(hash)
|
45
47
|
return [] if hash.nil? || hash.empty?
|
46
48
|
|
47
|
-
|
49
|
+
internal_decode(hash, @alphabet)
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
|
52
|
+
def decode_hex(hash)
|
52
53
|
ret = ""
|
53
|
-
numbers =
|
54
|
+
numbers = decode(hash)
|
54
55
|
|
55
56
|
numbers.length.times do |i|
|
56
57
|
ret += numbers[i].to_s(16)[1 .. -1]
|
@@ -61,7 +62,7 @@ class Hashids
|
|
61
62
|
|
62
63
|
protected
|
63
64
|
|
64
|
-
def
|
65
|
+
def internal_encode(numbers)
|
65
66
|
ret = ""
|
66
67
|
|
67
68
|
alphabet = @alphabet
|
@@ -110,7 +111,7 @@ class Hashids
|
|
110
111
|
ret
|
111
112
|
end
|
112
113
|
|
113
|
-
def
|
114
|
+
def internal_decode(hash, alphabet)
|
114
115
|
ret = []
|
115
116
|
|
116
117
|
breakdown = hash.gsub(/[#{@guards}]/, " ")
|
@@ -190,7 +191,7 @@ class Hashids
|
|
190
191
|
def setup_alphabet
|
191
192
|
validate_attributes
|
192
193
|
|
193
|
-
@alphabet = alphabet
|
194
|
+
@alphabet = uniq_characters(alphabet)
|
194
195
|
|
195
196
|
setup_seps
|
196
197
|
setup_guards
|
@@ -199,18 +200,15 @@ class Hashids
|
|
199
200
|
end
|
200
201
|
|
201
202
|
def setup_seps
|
202
|
-
@seps =
|
203
|
-
|
204
|
-
# seps should contain only characters present in alphabet
|
205
|
-
# alphabet should not contains seps
|
203
|
+
@seps = DEFAULT_SEPS
|
206
204
|
|
207
205
|
seps.length.times do |i|
|
208
|
-
|
209
|
-
|
210
|
-
if j.
|
211
|
-
@
|
206
|
+
# Seps should only contain characters present in alphabet,
|
207
|
+
# and alphabet should not contains seps
|
208
|
+
if j = alphabet.index(seps[i])
|
209
|
+
@alphabet = pick_characters(alphabet, j)
|
212
210
|
else
|
213
|
-
@
|
211
|
+
@seps = pick_characters(seps, i)
|
214
212
|
end
|
215
213
|
end
|
216
214
|
|
@@ -280,4 +278,16 @@ class Hashids
|
|
280
278
|
"#{MIN_ALPHABET_LENGTH} unique characters."
|
281
279
|
end
|
282
280
|
end
|
281
|
+
|
282
|
+
def hex_string?(string)
|
283
|
+
string.to_s.match(/\A[0-9a-fA-F]+\Z/)
|
284
|
+
end
|
285
|
+
|
286
|
+
def pick_characters(array, index)
|
287
|
+
array[0, index] + " " + array[index + 1 .. -1]
|
288
|
+
end
|
289
|
+
|
290
|
+
def uniq_characters(string)
|
291
|
+
string.split('').uniq.join('')
|
292
|
+
end
|
283
293
|
end
|
data/spec/hashids_spec.rb
CHANGED
@@ -12,6 +12,10 @@ describe Hashids do
|
|
12
12
|
let(:guards) { 'AdG0' }
|
13
13
|
let(:hashids) { Hashids.new(salt) }
|
14
14
|
|
15
|
+
let(:default_seps) {
|
16
|
+
"cfhistuCFHISTU"
|
17
|
+
}
|
18
|
+
|
15
19
|
let(:default_alphabet) {
|
16
20
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
17
21
|
}
|
@@ -25,8 +29,12 @@ describe Hashids do
|
|
25
29
|
Hashids::DEFAULT_ALPHABET.must_equal default_alphabet
|
26
30
|
end
|
27
31
|
|
32
|
+
it "has default separators" do
|
33
|
+
Hashids::DEFAULT_SEPS.must_equal default_seps
|
34
|
+
end
|
35
|
+
|
28
36
|
it "has a default salt" do
|
29
|
-
Hashids.new.
|
37
|
+
Hashids.new.encode(1,2,3).must_equal "o2fXhV"
|
30
38
|
end
|
31
39
|
|
32
40
|
it "has the correct salt" do
|
@@ -62,152 +70,152 @@ describe Hashids do
|
|
62
70
|
end
|
63
71
|
end
|
64
72
|
|
65
|
-
describe "
|
66
|
-
it "
|
67
|
-
hashids.
|
73
|
+
describe "encode" do
|
74
|
+
it "encodes a single number" do
|
75
|
+
hashids.encode(12345).must_equal 'NkK9'
|
68
76
|
|
69
77
|
hashids.tap do |h|
|
70
|
-
h.
|
71
|
-
h.
|
72
|
-
h.
|
73
|
-
h.
|
74
|
-
h.
|
75
|
-
h.
|
76
|
-
h.
|
77
|
-
h.
|
78
|
+
h.encode(-1).must_equal ''
|
79
|
+
h.encode(1).must_equal 'NV'
|
80
|
+
h.encode(22).must_equal 'K4'
|
81
|
+
h.encode(333).must_equal 'OqM'
|
82
|
+
h.encode(9999).must_equal 'kQVg'
|
83
|
+
h.encode(123_000).must_equal '58LzD'
|
84
|
+
h.encode(456_000_000).must_equal '5gn6mQP'
|
85
|
+
h.encode(987_654_321).must_equal 'oyjYvry'
|
78
86
|
end
|
79
87
|
end
|
80
88
|
|
81
|
-
it "can
|
89
|
+
it "can encode a list of numbers" do
|
82
90
|
hashids.tap do |h|
|
83
|
-
h.
|
84
|
-
h.
|
85
|
-
h.
|
91
|
+
h.encode(1,2,3).must_equal "laHquq"
|
92
|
+
h.encode(2,4,6).must_equal "44uotN"
|
93
|
+
h.encode(99,25).must_equal "97Jun"
|
86
94
|
|
87
|
-
h.
|
95
|
+
h.encode(1337,42,314).
|
88
96
|
must_equal "7xKhrUxm"
|
89
97
|
|
90
|
-
h.
|
98
|
+
h.encode(683, 94108, 123, 5).
|
91
99
|
must_equal "aBMswoO2UB3Sj"
|
92
100
|
|
93
|
-
h.
|
101
|
+
h.encode(547, 31, 241271, 311, 31397, 1129, 71129).
|
94
102
|
must_equal "3RoSDhelEyhxRsyWpCx5t1ZK"
|
95
103
|
|
96
|
-
h.
|
104
|
+
h.encode(21979508, 35563591, 57543099, 93106690, 150649789).
|
97
105
|
must_equal "p2xkL3CK33JjcrrZ8vsw4YRZueZX9k"
|
98
106
|
end
|
99
107
|
end
|
100
108
|
|
101
|
-
it "can
|
102
|
-
hashids.
|
109
|
+
it "can encode a list of numbers passed in as an array" do
|
110
|
+
hashids.encode([1,2,3]).must_equal "laHquq"
|
103
111
|
end
|
104
112
|
|
105
113
|
it "returns an empty string if no numbers" do
|
106
|
-
hashids.
|
114
|
+
hashids.encode.must_equal ""
|
107
115
|
end
|
108
116
|
|
109
117
|
it "returns an empty string if any of the numbers are negative" do
|
110
|
-
hashids.
|
111
|
-
hashids.
|
118
|
+
hashids.encode(-1).must_equal ""
|
119
|
+
hashids.encode(10,-10).must_equal ""
|
112
120
|
end
|
113
121
|
|
114
|
-
it "can
|
122
|
+
it "can encode to a minumum length" do
|
115
123
|
h = Hashids.new(salt, 18)
|
116
|
-
h.
|
124
|
+
h.encode(1).must_equal "aJEDngB0NV05ev1WwP"
|
117
125
|
|
118
|
-
h.
|
126
|
+
h.encode(4140, 21147, 115975, 678570, 4213597, 27644437).
|
119
127
|
must_equal "pLMlCWnJSXr1BSpKgqUwbJ7oimr7l6"
|
120
128
|
end
|
121
129
|
|
122
|
-
it "can
|
130
|
+
it "can encode with a custom alphabet" do
|
123
131
|
h = Hashids.new(salt, 0, "ABCDEFGhijklmn34567890-:")
|
124
|
-
h.
|
132
|
+
h.encode(1,2,3,4,5).must_equal "6nhmFDikA0"
|
125
133
|
end
|
126
134
|
|
127
135
|
it "does not produce repeating patterns for identical numbers" do
|
128
|
-
hashids.
|
136
|
+
hashids.encode(5,5,5,5).must_equal "1Wc8cwcE"
|
129
137
|
end
|
130
138
|
|
131
139
|
it "does not produce repeating patterns for incremented numbers" do
|
132
|
-
hashids.
|
140
|
+
hashids.encode(*(1..10).to_a).must_equal "kRHnurhptKcjIDTWC3sx"
|
133
141
|
end
|
134
142
|
|
135
143
|
it "does not produce similarities between incrementing number hashes" do
|
136
|
-
hashids.
|
137
|
-
hashids.
|
138
|
-
hashids.
|
139
|
-
hashids.
|
140
|
-
hashids.
|
144
|
+
hashids.encode(1).must_equal 'NV'
|
145
|
+
hashids.encode(2).must_equal '6m'
|
146
|
+
hashids.encode(3).must_equal 'yD'
|
147
|
+
hashids.encode(4).must_equal '2l'
|
148
|
+
hashids.encode(5).must_equal 'rD'
|
141
149
|
end
|
142
150
|
end
|
143
151
|
|
144
|
-
describe "
|
145
|
-
it "
|
152
|
+
describe "encode_hex" do
|
153
|
+
it "encodes hex string" do
|
146
154
|
hashids.tap { |h|
|
147
|
-
h.
|
148
|
-
h.
|
149
|
-
h.
|
150
|
-
h.
|
151
|
-
h.
|
152
|
-
h.
|
153
|
-
|
154
|
-
h.
|
155
|
-
h.
|
155
|
+
h.encode_hex("FA").must_equal "lzY"
|
156
|
+
h.encode_hex("26dd").must_equal "MemE"
|
157
|
+
h.encode_hex("FF1A").must_equal "eBMrb"
|
158
|
+
h.encode_hex("12abC").must_equal "D9NPE"
|
159
|
+
h.encode_hex("185b0").must_equal "9OyNW"
|
160
|
+
h.encode_hex("17b8d").must_equal "MRWNE"
|
161
|
+
|
162
|
+
h.encode_hex("1d7f21dd38").must_equal "4o6Z7KqxE"
|
163
|
+
h.encode_hex("20015111d").must_equal "ooweQVNB"
|
156
164
|
}
|
157
165
|
end
|
158
166
|
|
159
167
|
it "returns an empty string if passed non-hex string" do
|
160
|
-
hashids.
|
168
|
+
hashids.encode_hex("XYZ123").must_equal ""
|
161
169
|
end
|
162
170
|
end
|
163
171
|
|
164
|
-
describe "
|
165
|
-
it "
|
166
|
-
hashids.
|
167
|
-
hashids.
|
168
|
-
hashids.
|
172
|
+
describe "decode" do
|
173
|
+
it "decodes an encoded number" do
|
174
|
+
hashids.decode("NkK9").must_equal [12345]
|
175
|
+
hashids.decode("5O8yp5P").must_equal [666555444]
|
176
|
+
hashids.decode("KVO9yy1oO5j").must_equal [666555444333222]
|
169
177
|
|
170
178
|
hashids.tap { |h|
|
171
|
-
h.
|
172
|
-
h.
|
173
|
-
h.
|
179
|
+
h.decode("Wzo").must_equal [1337]
|
180
|
+
h.decode("DbE").must_equal [808]
|
181
|
+
h.decode("yj8").must_equal [303]
|
174
182
|
}
|
175
183
|
end
|
176
184
|
|
177
|
-
it "
|
178
|
-
hashids.
|
179
|
-
hashids.
|
185
|
+
it "decodes a list of encoded numbers" do
|
186
|
+
hashids.decode("1gRYUwKxBgiVuX").must_equal [66655,5444333,2,22]
|
187
|
+
hashids.decode('aBMswoO2UB3Sj').must_equal [683, 94108, 123, 5]
|
180
188
|
|
181
189
|
hashids.tap { |h|
|
182
|
-
h.
|
183
|
-
h.
|
190
|
+
h.decode('jYhp').must_equal [3, 4]
|
191
|
+
h.decode('k9Ib').must_equal [6, 5]
|
184
192
|
|
185
|
-
h.
|
186
|
-
h.
|
193
|
+
h.decode('EMhN').must_equal [31, 41]
|
194
|
+
h.decode('glSgV').must_equal [13, 89]
|
187
195
|
}
|
188
196
|
end
|
189
197
|
|
190
|
-
it "does not
|
198
|
+
it "does not decode with a different salt" do
|
191
199
|
peppers = Hashids.new('this is my pepper')
|
192
200
|
|
193
|
-
hashids.
|
194
|
-
peppers.
|
201
|
+
hashids.decode('NkK9').must_equal [12345]
|
202
|
+
peppers.decode('NkK9').must_equal []
|
195
203
|
end
|
196
204
|
|
197
|
-
it "can
|
205
|
+
it "can decode from a hash with a minimum length" do
|
198
206
|
h = Hashids.new(salt, 8)
|
199
|
-
h.
|
207
|
+
h.decode("gB0NV05e").must_equal [1]
|
200
208
|
|
201
|
-
h.
|
202
|
-
h.
|
209
|
+
h.decode("mxi8XH87").must_equal [25, 100, 950]
|
210
|
+
h.decode("KQcmkIW8hX").must_equal [5,200,195, 1]
|
203
211
|
end
|
204
212
|
end
|
205
213
|
|
206
|
-
describe "
|
207
|
-
it "
|
208
|
-
hashids.
|
209
|
-
hashids.
|
210
|
-
hashids.
|
214
|
+
describe "decode_hex" do
|
215
|
+
it "decodes hex string" do
|
216
|
+
hashids.decode_hex("lzY").must_equal "FA"
|
217
|
+
hashids.decode_hex("eBMrb").must_equal "FF1A"
|
218
|
+
hashids.decode_hex("D9NPE").must_equal "12ABC"
|
211
219
|
end
|
212
220
|
end
|
213
221
|
|
@@ -247,9 +255,9 @@ describe Hashids do
|
|
247
255
|
end
|
248
256
|
end
|
249
257
|
|
250
|
-
describe "
|
258
|
+
describe "internal_decode" do
|
251
259
|
it "decodes" do
|
252
|
-
hashids.send(:
|
260
|
+
hashids.send(:internal_decode, 'NV', alphabet).must_equal [1]
|
253
261
|
end
|
254
262
|
end
|
255
263
|
|
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: 0.
|
4
|
+
version: 1.0.0
|
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: 2014-09-11 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,15 +17,14 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- .gitignore
|
21
|
-
- .travis.yml
|
20
|
+
- ".gitignore"
|
21
|
+
- ".travis.yml"
|
22
22
|
- Gemfile
|
23
23
|
- LICENSE.txt
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
26
|
- hashids.gemspec
|
27
27
|
- lib/hashids.rb
|
28
|
-
- spec/hashids_profile.rb
|
29
28
|
- spec/hashids_spec.rb
|
30
29
|
homepage: https://github.com/peterhellberg/hashids.rb
|
31
30
|
licenses: []
|
@@ -36,20 +35,19 @@ require_paths:
|
|
36
35
|
- lib
|
37
36
|
required_ruby_version: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
|
-
- -
|
38
|
+
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
40
|
version: 1.9.3
|
42
41
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
42
|
requirements:
|
44
|
-
- -
|
43
|
+
- - ">="
|
45
44
|
- !ruby/object:Gem::Version
|
46
45
|
version: '0'
|
47
46
|
requirements: []
|
48
47
|
rubyforge_project:
|
49
|
-
rubygems_version: 2.
|
48
|
+
rubygems_version: 2.2.2
|
50
49
|
signing_key:
|
51
50
|
specification_version: 4
|
52
51
|
summary: Generate YouTube-like hashes from one or many numbers.
|
53
52
|
test_files:
|
54
|
-
- spec/hashids_profile.rb
|
55
53
|
- spec/hashids_spec.rb
|
data/spec/hashids_profile.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# Profile with perftools.rb
|
4
|
-
#
|
5
|
-
# CPUPROFILE=/tmp/hashids_profile \
|
6
|
-
# RUBYOPT="-r`gem which 'perftools.rb' | tail -1`" \
|
7
|
-
# ruby spec/hashids_profile.rb
|
8
|
-
#
|
9
|
-
# Generate diagram
|
10
|
-
#
|
11
|
-
# pprof.rb --gif /tmp/hashids_profile > /tmp/hashids_profile.gif && \
|
12
|
-
# open /tmp/hashids_profile.gif
|
13
|
-
#
|
14
|
-
|
15
|
-
require_relative "../lib/hashids"
|
16
|
-
|
17
|
-
h = Hashids.new('this is my salt')
|
18
|
-
|
19
|
-
10_000.times do |n|
|
20
|
-
h.decrypt(h.encrypt(n))
|
21
|
-
end
|