hashids 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.gem
2
+ Gemfile.lock
2
3
  *.rbc
3
4
  .bundle
4
5
  .config
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ bundler_args: --without documentation
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-19mode # JRuby in 1.9 mode
7
+ - rbx-19mode
8
+ - ruby-head
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in hashids.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ gem "rake"
8
+ gem "minitest" if RUBY_VERSION < '1.9.3'
9
+ end
data/README.md CHANGED
@@ -5,10 +5,15 @@ Use hashids when you do not want to expose your database ids to the user.
5
5
 
6
6
  [http://www.hashids.org/ruby/](http://www.hashids.org/ruby/)
7
7
 
8
+ [![Build Status](https://secure.travis-ci.org/peterhellberg/hashids.rb.png)](http://travis-ci.org/peterhellberg/hashids.rb)
9
+ (1.9.2, 1.9.3, jruby-19mode, rbx-19mode and ruby-head)
10
+
8
11
  ## What is it?
9
12
 
10
13
  hashids (Hash ID's) creates short, unique, decryptable hashes from unsigned integers.
11
14
 
15
+ _(NOTE: This is **NOT** a true cryptographic hash, since it is reversible)_
16
+
12
17
  It was designed for websites to use in URL shortening, tracking stuff, or
13
18
  making pages private (or at least unguessable).
14
19
 
@@ -12,6 +12,8 @@ Gem::Specification.new do |gem|
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
14
 
15
+ gem.required_ruby_version = '>= 1.9.2'
16
+
15
17
  gem.files = `git ls-files`.split($/)
16
18
  gem.test_files = gem.files.grep(%r{^(spec)/})
17
19
  gem.require_paths = ["lib"]
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class Hashids
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  DEFAULT_ALPHABET = "xcS4F6h89aUbideAI7tkynuopqrXCgTE5GBKHLMjfRsz"
6
6
  PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43]
7
7
 
@@ -10,22 +10,22 @@ class Hashids
10
10
  class AlphabetError < ArgumentError; end
11
11
 
12
12
  def initialize(salt = "", min_length = 0, alphabet = DEFAULT_ALPHABET)
13
- @salt = salt
14
- @min_length = min_length
15
- @alphabet = alphabet
13
+ @salt = salt
14
+ @min_length = min_length
15
+ @alphabet = alphabet
16
+
17
+ @chars_regex = /./
16
18
 
17
19
  validate_attributes
18
20
  setup_alphabet
19
21
  end
20
22
 
21
23
  def encrypt(*numbers)
22
- return "" unless numbers.any?
23
-
24
- numbers.each do |number|
25
- return "" if !number.kind_of?(Fixnum) || number < 0
24
+ if numbers.empty? || numbers.reject { |n| Integer(n) && n > 0 }.any?
25
+ ""
26
+ else
27
+ encode(numbers, @alphabet, @salt, @min_length)
26
28
  end
27
-
28
- encode(numbers, @alphabet, @salt, @min_length)
29
29
  end
30
30
 
31
31
  def decrypt(hash)
@@ -52,7 +52,7 @@ class Hashids
52
52
  @seps = []
53
53
  @guards = []
54
54
 
55
- @alphabet = @alphabet.split('').uniq.join
55
+ @alphabet = @alphabet.scan(@chars_regex).uniq.join('')
56
56
 
57
57
  if @alphabet.length < 4
58
58
  raise AlphabetError, "Alphabet must contain at least 4 unique characters."
@@ -63,7 +63,7 @@ class Hashids
63
63
 
64
64
  break if char.nil?
65
65
 
66
- @seps.push char
66
+ @seps << char
67
67
  @alphabet.gsub!(char, ' ')
68
68
  end
69
69
 
@@ -71,7 +71,7 @@ class Hashids
71
71
  separator = @seps[index]
72
72
 
73
73
  unless separator.nil?
74
- @guards.push(separator)
74
+ @guards << separator
75
75
  @seps.delete_at(index)
76
76
  end
77
77
  end
@@ -83,13 +83,13 @@ class Hashids
83
83
  def encode(numbers, alphabet, salt, min_length = 0)
84
84
  ret = ""
85
85
 
86
- seps = consistent_shuffle(@seps, numbers).split("")
86
+ seps = consistent_shuffle(@seps, numbers).scan(@chars_regex)
87
87
  lottery_char = ""
88
88
 
89
89
  numbers.each_with_index do |number, i|
90
90
  if i == 0
91
91
  lottery_salt = numbers.join('-')
92
- numbers.each { |n| lottery_salt += "-" + ((n.to_i + 1) * 2).to_s }
92
+ numbers.each { |n| lottery_salt += "-#{(n + 1) * 2}" }
93
93
 
94
94
  lottery = consistent_shuffle(alphabet, lottery_salt)
95
95
 
@@ -172,8 +172,8 @@ class Hashids
172
172
  end
173
173
 
174
174
  if alphabet.length > 0 && lottery_char.length > 0
175
- alphabet = consistent_shuffle(alphabet, (lottery_char.ord & 12345).to_s + "" + @salt)
176
- ret.push unhash(sub_hash, alphabet)
175
+ alphabet = consistent_shuffle(alphabet, (lottery_char.ord & 12345).to_s + @salt)
176
+ ret << unhash(sub_hash, alphabet)
177
177
  end
178
178
  end
179
179
  end
@@ -187,24 +187,21 @@ class Hashids
187
187
  def consistent_shuffle(alphabet, salt)
188
188
  ret = ""
189
189
 
190
- alphabet = alphabet.join "" if alphabet.respond_to? :join
191
- salt = salt.join "" if salt.respond_to? :join
190
+ alphabet = alphabet.join("") if alphabet.respond_to? :join
191
+ salt = salt.join("") if salt.respond_to? :join
192
192
 
193
- alphabet_array = alphabet.split('')
194
- salt_array = salt.split('')
195
- sorting_array = []
193
+ alphabet_array = alphabet.scan(@chars_regex)
194
+ salt_array = salt.scan(@chars_regex)
195
+ sorting_array = []
196
196
 
197
- salt_array.push "" unless salt_array.any?
198
-
199
- salt_array.each do |salt_char|
200
- sorting_array.push salt_char.ord || 0
201
- end
197
+ salt_array << "" if salt_array.empty?
198
+ salt_array.each { |char| sorting_array << char.ord }
202
199
 
203
200
  sorting_array.each_with_index do |int,i|
204
201
  add = true
205
202
  k = i
206
203
 
207
- while k != (sorting_array.length + i - 1)
204
+ while k != sorting_array.length + i - 1
208
205
  next_index = (k + 1) % sorting_array.length
209
206
 
210
207
  if add
@@ -223,9 +220,8 @@ class Hashids
223
220
  i = 0
224
221
 
225
222
  while alphabet_array.length > 0
226
- alphabet_size = alphabet_array.length
227
223
  pos = sorting_array[i]
228
- pos %= alphabet_size if pos >= alphabet_size
224
+ pos %= alphabet_array.length if pos >= alphabet_array.length
229
225
  ret += alphabet_array[pos]
230
226
 
231
227
  alphabet_array.delete_at(pos)
@@ -237,11 +233,10 @@ class Hashids
237
233
 
238
234
  def hash(number, alphabet)
239
235
  hash = ""
240
- alphabet_length = alphabet.length
241
236
 
242
237
  while number > 0
243
- hash = alphabet[number % alphabet_length] + hash
244
- number = number / alphabet_length
238
+ hash = alphabet[number % alphabet.length] + hash
239
+ number = number / alphabet.length
245
240
  end
246
241
 
247
242
  hash
@@ -250,15 +245,12 @@ class Hashids
250
245
  def unhash(hash, alphabet)
251
246
  number = 0
252
247
 
253
- hash.split('').each_with_index { |char, i|
254
- pos = alphabet.index char
255
-
256
- return if pos.nil?
257
-
258
- number += pos * alphabet.length ** (hash.length - i - 1)
259
- }
248
+ hash.split('').each_with_index do |char, i|
249
+ if pos = alphabet.index(char)
250
+ number += pos * alphabet.length ** (hash.length - i - 1)
251
+ end
252
+ end
260
253
 
261
254
  number
262
255
  end
263
-
264
256
  end
@@ -0,0 +1,21 @@
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
@@ -89,15 +89,15 @@ describe Hashids do
89
89
  h.encrypt(1,2,3,4,5).must_equal 'adcdacddcdaacdad'
90
90
  end
91
91
 
92
- it "doesn’t produce repeating patterns for identical numbers" do
92
+ it "does not produce repeating patterns for identical numbers" do
93
93
  hashids.encrypt(5,5,5,5).must_equal 'GLh5SMs9'
94
94
  end
95
95
 
96
- it "doesn’t produce repeating patterns for incremented numbers" do
96
+ it "does not produce repeating patterns for incremented numbers" do
97
97
  hashids.encrypt(*(1..10).to_a).must_equal 'zEUzfySGIpuyhpF6HaC7'
98
98
  end
99
99
 
100
- it "doesn’t produce similarities between incrementing number hashes" do
100
+ it "does not produce similarities between incrementing number hashes" do
101
101
  hashids.encrypt(1).must_equal 'LX'
102
102
  hashids.encrypt(2).must_equal 'ed'
103
103
  hashids.encrypt(3).must_equal 'o9'
@@ -126,7 +126,7 @@ describe Hashids do
126
126
  }
127
127
  end
128
128
 
129
- it "doesn’t decrypt with a different salt" do
129
+ it "does not decrypt with a different salt" do
130
130
  peppers = Hashids.new('this is my pepper')
131
131
  hashids.decrypt('ryBo').must_equal [12345]
132
132
  peppers.decrypt('ryBo').must_equal []
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashids
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -19,12 +19,14 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - .gitignore
22
+ - .travis.yml
22
23
  - Gemfile
23
24
  - LICENSE.txt
24
25
  - README.md
25
26
  - Rakefile
26
27
  - hashids.gemspec
27
28
  - lib/hashids.rb
29
+ - spec/hashids_profile.rb
28
30
  - spec/hashids_spec.rb
29
31
  homepage: https://github.com/peterhellberg/hashids.rb
30
32
  licenses: []
@@ -37,13 +39,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
37
39
  requirements:
38
40
  - - ! '>='
39
41
  - !ruby/object:Gem::Version
40
- version: '0'
42
+ version: 1.9.2
41
43
  required_rubygems_version: !ruby/object:Gem::Requirement
42
44
  none: false
43
45
  requirements:
44
46
  - - ! '>='
45
47
  - !ruby/object:Gem::Version
46
48
  version: '0'
49
+ segments:
50
+ - 0
51
+ hash: 2124593182474944467
47
52
  requirements: []
48
53
  rubyforge_project:
49
54
  rubygems_version: 1.8.24
@@ -51,5 +56,5 @@ signing_key:
51
56
  specification_version: 3
52
57
  summary: Generate YouTube-like hashes from one or many numbers.
53
58
  test_files:
59
+ - spec/hashids_profile.rb
54
60
  - spec/hashids_spec.rb
55
- has_rdoc: