url_hash 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +61 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/url_hash.rb +90 -0
- data/test/helper.rb +18 -0
- data/test/test_url_hash.rb +28 -0
- data/url_hash.gemspec +63 -0
- metadata +138 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# openssl, digest, base64 come from the standard library
|
4
|
+
|
5
|
+
# Add dependencies to develop your gem here.
|
6
|
+
# Include everything needed to run rake, tests, features, etc.
|
7
|
+
group :development do
|
8
|
+
gem "shoulda", ">= 0"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.2"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.5.2)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.8.7)
|
10
|
+
rcov (0.9.9)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.5.2)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Tom Coleman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
= url_hash
|
2
|
+
|
3
|
+
A simple little library for converting integers to X-character hashes, suitable for uses in urls.
|
4
|
+
Hashes may or may not be encrypted, depending on usage.
|
5
|
+
|
6
|
+
Sample uses (inside Rails projects):
|
7
|
+
1. Shortening urls for commonly used models. Add something like this to the bottom of your routes.rb:
|
8
|
+
match ':hash', :constraints => {:hash => /.{8}/},
|
9
|
+
:to => redirect { |params| "/models/#{UrlHash.from_hash(params[:hash])}" }
|
10
|
+
|
11
|
+
And something like this to your model
|
12
|
+
class Model ...
|
13
|
+
def hash
|
14
|
+
save! if new_record?
|
15
|
+
UrlHash.to_hash(self.id)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Notes:
|
20
|
+
* You probably don't need to encrypt in this case, unless your ids are private somehow.
|
21
|
+
* It'd probably be better to use a metal to do this, rather than the route, as we don't need any environmental stuff, take this code as pointer in the right direction.
|
22
|
+
|
23
|
+
2. A Short URL service. We store a map from hashes to urls in the database. Something like:
|
24
|
+
class ShortUrl < ActiveRecord::Base
|
25
|
+
validates_presence_of :url
|
26
|
+
validates_uniqueness_of :url
|
27
|
+
|
28
|
+
def self.find_by_hash(hash, opts = {})
|
29
|
+
# use conditions rather than a find so that we don't throw an exception
|
30
|
+
find :first, {:conditions => {:id => UrlHash.from_hash(hash)}}.merge(opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
def hash
|
34
|
+
save! if new_record?
|
35
|
+
UrlHash.to_hash(self.id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
And something like (in routes.rb)
|
40
|
+
match ':hash', :constraints => {:hash => /.{8}/},
|
41
|
+
:to => redirect { |params| ShortUrl.find_by_hash(params[:hash]).url }
|
42
|
+
|
43
|
+
Notes:
|
44
|
+
* You will want to use find_or_create_by_url to create the short_urls and, you'll want an index on url.
|
45
|
+
* If you have any kind of security based on URLs being difficult to guess, you'll want to use encryption
|
46
|
+
|
47
|
+
== Contributing to url_hash
|
48
|
+
|
49
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
50
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
51
|
+
* Fork the project
|
52
|
+
* Start a feature/bugfix branch
|
53
|
+
* Commit and push until you are happy with your contribution
|
54
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
55
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
56
|
+
|
57
|
+
== Copyright
|
58
|
+
|
59
|
+
Copyright (c) 2011 Tom Coleman. See LICENSE.txt for
|
60
|
+
further details.
|
61
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "url_hash"
|
16
|
+
gem.homepage = "http://github.com/tmeasday/url_hash"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Create url-embeddable hashes from integers}
|
19
|
+
gem.description = %Q{Create url-embeddable hashes from integers, for use in short-url services or simple to shorten resource accesses.}
|
20
|
+
gem.email = "tom@thesnail.org"
|
21
|
+
gem.authors = ["Tom Coleman"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |test|
|
38
|
+
test.libs << 'test'
|
39
|
+
test.pattern = 'test/**/test_*.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "url_hash #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/url_hash.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module UrlHash
|
5
|
+
DEFAULT_HASH_LENGTH = 8
|
6
|
+
ALGORITHM = 'aes-256-cfb8'
|
7
|
+
|
8
|
+
# convert an id (an integer) to a hash, a URL-compatible string.
|
9
|
+
#
|
10
|
+
# for example. UrlHash.to_hash(1001) -> '+xDdeave3'
|
11
|
+
#
|
12
|
+
# options:
|
13
|
+
# :hash_length => how many characters to use for the hash. Defaults to 8.
|
14
|
+
# descreasing this increase the probability of a collision
|
15
|
+
# :key, :iv => provide these two options if you want to encrypt the hash.
|
16
|
+
# otherwise, it will relatively trivial for users to predict your hashes,
|
17
|
+
# and to work out ids based on them. Decide for yourself if this is a problem.
|
18
|
+
# It is recommended to generate them using Digest::SHA2.hexdigest.
|
19
|
+
def self.to_hash(id, options = {})
|
20
|
+
options = {:hash_length => DEFAULT_HASH_LENGTH}.merge(options)
|
21
|
+
|
22
|
+
# buffers use all 256 bytes, hashes just 64, thus we can only use 3/4 the numbers
|
23
|
+
# -> 256 ** buffer_length <= 64 ** hash_length
|
24
|
+
buffer_length = (3 * options[:hash_length] / 4).floor
|
25
|
+
|
26
|
+
buffer = int_to_buffer(id, buffer_length)
|
27
|
+
|
28
|
+
if (options.has_key? :key and options.has_key? :iv)
|
29
|
+
# encrypt the buffer
|
30
|
+
buffer = self.encrypt(buffer, true, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
# use -'s instead of + as we like that better
|
34
|
+
Base64.encode64(buffer).tr("+", "-").strip
|
35
|
+
end
|
36
|
+
|
37
|
+
# convert an hash, as produced by to_hash, back into the original integer
|
38
|
+
#
|
39
|
+
# for example. UrlHash.to_hash('+xDdeave3') -> 1001
|
40
|
+
#
|
41
|
+
# options:
|
42
|
+
# :key, :iv => provide these again if you are encrypting hashes
|
43
|
+
def self.from_hash(hash, options = {})
|
44
|
+
buffer = Base64.decode64(hash.tr("-", "+"))
|
45
|
+
|
46
|
+
if (options.has_key? :key and options.has_key? :iv)
|
47
|
+
# encrypt the buffer
|
48
|
+
buffer = self.encrypt(buffer, false, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
buffer_to_int(buffer)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def self.encrypt(buffer, forward, options)
|
56
|
+
c = OpenSSL::Cipher::Cipher.new(ALGORITHM)
|
57
|
+
forward ? c.encrypt : c.decrypt
|
58
|
+
c.key = options[:key]
|
59
|
+
c.iv = options[:iv]
|
60
|
+
|
61
|
+
e = c.update(buffer)
|
62
|
+
e << c.final
|
63
|
+
|
64
|
+
e
|
65
|
+
end
|
66
|
+
|
67
|
+
# turn a integer into a string representation.
|
68
|
+
# we need to ensure that we use put the non-zero stuff on the
|
69
|
+
# the MSB side so that it randomizes the string properly:
|
70
|
+
# see : http://www.columbia.edu/~ariel/ssleay/fip81/fip81.html#td2
|
71
|
+
def self.int_to_buffer(int, size)
|
72
|
+
"".tap do |buf|
|
73
|
+
size.times do
|
74
|
+
buf << (int & 0xff)
|
75
|
+
int /= 0x100
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.buffer_to_int(buffer)
|
81
|
+
int = 0
|
82
|
+
multiplier = 1
|
83
|
+
buffer.each_byte do |b|
|
84
|
+
int += multiplier * b
|
85
|
+
multiplier *= 0x100
|
86
|
+
end
|
87
|
+
|
88
|
+
int
|
89
|
+
end
|
90
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'url_hash'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
class TestUrlHash < Test::Unit::TestCase
|
5
|
+
context "UrlHash" do
|
6
|
+
should "convert between integers and buffers" do
|
7
|
+
assert_equal 1001, UrlHash.buffer_to_int(UrlHash.int_to_buffer(1001, 8))
|
8
|
+
assert_equal 1001, UrlHash.buffer_to_int(UrlHash.int_to_buffer(1001, 10))
|
9
|
+
end
|
10
|
+
|
11
|
+
should "convert between integers and hashes without encryption" do
|
12
|
+
assert_equal 1001, UrlHash.from_hash(UrlHash.to_hash(1001))
|
13
|
+
end
|
14
|
+
|
15
|
+
should "correctly set the hash length" do
|
16
|
+
assert_equal 8, UrlHash.to_hash(1001, :hash_length => 8).length
|
17
|
+
assert_equal 12, UrlHash.to_hash(1001, :hash_length => 12).length
|
18
|
+
end
|
19
|
+
|
20
|
+
should "convert between integers and hashes with encryption" do
|
21
|
+
options = {
|
22
|
+
:key => Digest::SHA2.hexdigest('test key'),
|
23
|
+
:iv => Digest::SHA2.hexdigest('test initial value')
|
24
|
+
}
|
25
|
+
assert_equal 1001, UrlHash.from_hash(UrlHash.to_hash(1001, options), options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/url_hash.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{url_hash}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tom Coleman"]
|
12
|
+
s.date = %q{2011-04-27}
|
13
|
+
s.description = %q{Create url-embeddable hashes from integers, for use in short-url services or simple to shorten resource accesses.}
|
14
|
+
s.email = %q{tom@thesnail.org}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/url_hash.rb",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/test_url_hash.rb",
|
30
|
+
"url_hash.gemspec"
|
31
|
+
]
|
32
|
+
s.homepage = %q{http://github.com/tmeasday/url_hash}
|
33
|
+
s.licenses = ["MIT"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = %q{1.5.2}
|
36
|
+
s.summary = %q{Create url-embeddable hashes from integers}
|
37
|
+
s.test_files = [
|
38
|
+
"test/helper.rb",
|
39
|
+
"test/test_url_hash.rb"
|
40
|
+
]
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
48
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
49
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
52
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
53
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
54
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
55
|
+
end
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
58
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
60
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: url_hash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Tom Coleman
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-27 00:00:00 +10:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
type: :development
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
name: shoulda
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
prerelease: false
|
37
|
+
type: :development
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 23
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 0
|
47
|
+
- 0
|
48
|
+
version: 1.0.0
|
49
|
+
name: bundler
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
prerelease: false
|
53
|
+
type: :development
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 7
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 5
|
63
|
+
- 2
|
64
|
+
version: 1.5.2
|
65
|
+
name: jeweler
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
prerelease: false
|
69
|
+
type: :development
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
name: rcov
|
80
|
+
version_requirements: *id004
|
81
|
+
description: Create url-embeddable hashes from integers, for use in short-url services or simple to shorten resource accesses.
|
82
|
+
email: tom@thesnail.org
|
83
|
+
executables: []
|
84
|
+
|
85
|
+
extensions: []
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.rdoc
|
90
|
+
files:
|
91
|
+
- .document
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.rdoc
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- lib/url_hash.rb
|
99
|
+
- test/helper.rb
|
100
|
+
- test/test_url_hash.rb
|
101
|
+
- url_hash.gemspec
|
102
|
+
has_rdoc: true
|
103
|
+
homepage: http://github.com/tmeasday/url_hash
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
hash: 3
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
hash: 3
|
126
|
+
segments:
|
127
|
+
- 0
|
128
|
+
version: "0"
|
129
|
+
requirements: []
|
130
|
+
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 1.5.2
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: Create url-embeddable hashes from integers
|
136
|
+
test_files:
|
137
|
+
- test/helper.rb
|
138
|
+
- test/test_url_hash.rb
|