redir 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +16 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +20 -0
- data/README.md +87 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/lib/model/redirect.rb +91 -0
- data/lib/model/redirect_log.rb +7 -0
- data/lib/rack/redir.rb +51 -0
- data/lib/redir.rb +5 -0
- data/lib/redirector.rb +18 -0
- data/redir.gemspec +81 -0
- data/spec/factories/redirect.rb +6 -0
- data/spec/mongoid.yml +29 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/model/redirect_spec.rb +88 -0
- data/spec/unit/rack/redir_spec.rb +189 -0
- data/spec/unit/redirector_spec.rb +42 -0
- metadata +213 -0
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
ruby '1.9.3'
|
4
|
+
|
5
|
+
gem 'mongoid', '~> 3.0.0'
|
6
|
+
gem 'rack'
|
7
|
+
|
8
|
+
group :test, :development do
|
9
|
+
gem 'rack-test', require: 'rack/test'
|
10
|
+
gem 'rspec'
|
11
|
+
gem 'factory_girl'
|
12
|
+
gem 'timecop'
|
13
|
+
gem 'jeweler'
|
14
|
+
gem 'simplecov'
|
15
|
+
gem 'yard'
|
16
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (3.2.8)
|
5
|
+
activesupport (= 3.2.8)
|
6
|
+
builder (~> 3.0.0)
|
7
|
+
activesupport (3.2.8)
|
8
|
+
i18n (~> 0.6)
|
9
|
+
multi_json (~> 1.0)
|
10
|
+
builder (3.0.3)
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
factory_girl (4.1.0)
|
13
|
+
activesupport (>= 3.0.0)
|
14
|
+
git (1.2.5)
|
15
|
+
i18n (0.6.1)
|
16
|
+
jeweler (1.8.4)
|
17
|
+
bundler (~> 1.0)
|
18
|
+
git (>= 1.2.5)
|
19
|
+
rake
|
20
|
+
rdoc
|
21
|
+
json (1.7.5)
|
22
|
+
mongoid (3.0.6)
|
23
|
+
activemodel (~> 3.1)
|
24
|
+
moped (~> 1.1)
|
25
|
+
origin (~> 1.0)
|
26
|
+
tzinfo (~> 0.3.22)
|
27
|
+
moped (1.2.5)
|
28
|
+
multi_json (1.3.6)
|
29
|
+
origin (1.0.9)
|
30
|
+
rack (1.4.1)
|
31
|
+
rack-test (0.6.1)
|
32
|
+
rack (>= 1.0)
|
33
|
+
rake (0.9.2.2)
|
34
|
+
rdoc (3.12)
|
35
|
+
json (~> 1.4)
|
36
|
+
rspec (2.11.0)
|
37
|
+
rspec-core (~> 2.11.0)
|
38
|
+
rspec-expectations (~> 2.11.0)
|
39
|
+
rspec-mocks (~> 2.11.0)
|
40
|
+
rspec-core (2.11.1)
|
41
|
+
rspec-expectations (2.11.3)
|
42
|
+
diff-lcs (~> 1.1.3)
|
43
|
+
rspec-mocks (2.11.3)
|
44
|
+
simplecov (0.7.1)
|
45
|
+
multi_json (~> 1.0)
|
46
|
+
simplecov-html (~> 0.7.1)
|
47
|
+
simplecov-html (0.7.1)
|
48
|
+
timecop (0.5.3)
|
49
|
+
tzinfo (0.3.33)
|
50
|
+
yard (0.8.3)
|
51
|
+
|
52
|
+
PLATFORMS
|
53
|
+
ruby
|
54
|
+
|
55
|
+
DEPENDENCIES
|
56
|
+
factory_girl
|
57
|
+
jeweler
|
58
|
+
mongoid (~> 3.0.0)
|
59
|
+
rack
|
60
|
+
rack-test
|
61
|
+
rspec
|
62
|
+
simplecov
|
63
|
+
timecop
|
64
|
+
yard
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Springbot
|
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.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
Redir
|
2
|
+
=====
|
3
|
+
|
4
|
+
There are many gems that allow you to create a short url and redirect a user to another website. But there are not many store information about the requests that use Mongo which is why we created redir.
|
5
|
+
|
6
|
+
### Features
|
7
|
+
* Fully rack compliant
|
8
|
+
* Generates a unique shortened url for you
|
9
|
+
* Takes care of the mongo heavy lifting for you
|
10
|
+
* Stores all of the request header information to gather analytics
|
11
|
+
* Allows the addition to two sets of request parameters for conversion analytics
|
12
|
+
|
13
|
+
How to use it
|
14
|
+
-------------
|
15
|
+
|
16
|
+
Redir is currently under active development.
|
17
|
+
|
18
|
+
### Rails
|
19
|
+
include the gem in your Gemfile
|
20
|
+
in your application.rb add
|
21
|
+
|
22
|
+
config.middleware.use Rack::Redir
|
23
|
+
|
24
|
+
in your environments/ development.rb, test.rb or production.rb file add.
|
25
|
+
|
26
|
+
Redirect.host = '<your hostname>/'
|
27
|
+
|
28
|
+
add a config/mongoid.yml file. Setup a local mongodb instance or use one from a cloud provider and add those configuration settings to your mongoid.yml file as described here http://mongoid.org/en/mongoid/docs/installation.html#configuration
|
29
|
+
|
30
|
+
Redir by default uses the /a route for redirect requests. IE: http://<your url>/a/<shortened_id> If you have another route that is already set at a you can change this by adding to your application.rb.
|
31
|
+
|
32
|
+
Redirect.path = '<new path>/'
|
33
|
+
|
34
|
+
To create a shortened Url in your code
|
35
|
+
|
36
|
+
Redir.create_shortened_url <your url>
|
37
|
+
|
38
|
+
The Redirect object is a Mongoid object class. Therefore you can search for redirect information based on it's attributes. In the case of Redirect those attributes are original_url and shortened_id. For example
|
39
|
+
|
40
|
+
results = Redirect.where(:original_url => www.polyglotprogramminginc.com).all
|
41
|
+
|
42
|
+
Mongoid results a Mongoid::Criteria object. To get at the results you can use something like
|
43
|
+
|
44
|
+
results.to_a
|
45
|
+
|
46
|
+
to get an array of results. See the mongoid documentation for further details. The shortened id is only the 8 character unique id of the shortened url. For example for http://www.springbot/a/ddffggrr ddffggrr would be the shortened_id. There is also a shortened_url and shortened_path method. See the redirect.rb docucumentation for more information. To get the full url that the user will be able to hit to be redirected use the shortened_url helper....ie
|
47
|
+
|
48
|
+
redir = Redirect.create_shortened_url <your url>
|
49
|
+
redir.shortened_url #the full shortened url that the user would hit to be directed back to <your url>
|
50
|
+
|
51
|
+
RedirectLog contains information about redirects that have been done. We are currently working on helper methods to make this easier, but for the time being you can get at that data by doing the following.
|
52
|
+
|
53
|
+
read the _id field from a redirect object that you want to get logging information for. IE:
|
54
|
+
|
55
|
+
my_redirect = Redirect.where(:shortened_id => 'rrffttee').to_a.last
|
56
|
+
|
57
|
+
and running a query against the RedirectLog object
|
58
|
+
|
59
|
+
redir_log = RedirectLog.where(:redirect_id => my_redirect._id)
|
60
|
+
|
61
|
+
an easier way to do this is
|
62
|
+
|
63
|
+
Redirector.find_logs <a shortened id>
|
64
|
+
|
65
|
+
you use the redir_log like any mongo object. the headers attribute contains the raw request headers and request time has the date/time the request came in.
|
66
|
+
|
67
|
+
### Other configuration options
|
68
|
+
|
69
|
+
Redirect.append_tracking_info
|
70
|
+
|
71
|
+
adds redirect_mongo_id=<Redirect._id>&redirect_log_mongo_id=<RedirectLog._id> to the end of the url being redirected to for conversion tracking
|
72
|
+
|
73
|
+
Redirect.append_google_analytics
|
74
|
+
|
75
|
+
adds utm_source=<@@host>&utm_campaign=<Redirect._id>__<RedirectLog._id> to the end of the url being redirected to for google analytics tracking
|
76
|
+
|
77
|
+
Contributing
|
78
|
+
------------
|
79
|
+
|
80
|
+
Just fork us on GitHub and send a pull request when you are ready.
|
81
|
+
|
82
|
+
License
|
83
|
+
-------
|
84
|
+
|
85
|
+
redir is released under the MIT license:
|
86
|
+
|
87
|
+
* http://www.opensource.org/licenses/MIT
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "redir"
|
18
|
+
gem.homepage = "http://github.com/springbot/redir"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{A Mongo based url shortener and data gathering gem.}
|
21
|
+
gem.description = %Q{This gem adds functionality to shorten url's and gather data about requests going through it.}
|
22
|
+
gem.email = "lgleason@polyglotprogramminginc.com"
|
23
|
+
gem.authors = ["Lance Gleason"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
require 'yard'
|
37
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class Redirect
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :original_url
|
5
|
+
field :shortened_id
|
6
|
+
|
7
|
+
@@host = 'http://localhost:3000/'
|
8
|
+
@@path = 'a/'
|
9
|
+
@@append_tracking_info = false
|
10
|
+
@@append_google_analytics = false
|
11
|
+
|
12
|
+
# Sets the value of the flag to determine if google analytics info should be sent with the url
|
13
|
+
# appends utm_source=<@@host>&utm_campaign=<Redirect._id>__<RedirectLog._id>
|
14
|
+
# @param [Boolean] value to set append_google_analytics flag to
|
15
|
+
def self.append_google_analytics= google_analytics_flag
|
16
|
+
@@append_google_analytics = google_analytics_flag
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gets the value of the flag to determine if google analytics info should be sent with the url
|
20
|
+
# @returns [Boolean] value of the append_google_analytics flag
|
21
|
+
def self.append_google_analytics
|
22
|
+
@@append_google_analytics
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sets the value of the flag to determine if tracking info should be sent with the url
|
26
|
+
# adds the following to the url being redirected to
|
27
|
+
# redirect_mongo_id=<Redirect._id>&redirect_log_mongo_id=<RedirectLog._id>
|
28
|
+
# @param [Boolean] value to set append_tracking_info flag to
|
29
|
+
def self.append_tracking_info= tracking_info_flag
|
30
|
+
@@append_tracking_info = tracking_info_flag
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets the value of the flag to determine if tracking info should be sent with the url
|
34
|
+
# @returns [Boolean] value of append_tracking_info flag
|
35
|
+
def self.append_tracking_info
|
36
|
+
@@append_tracking_info
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sets the path to use in the shortened url
|
40
|
+
# @param [String] the path you want to use for your shortened url instead of the default a/
|
41
|
+
def self.path= path
|
42
|
+
@@path = path
|
43
|
+
end
|
44
|
+
|
45
|
+
# Gets the path for the shortened url
|
46
|
+
# @return [String] the path
|
47
|
+
def self.path
|
48
|
+
path = @@path.end_with?('/') ? @@path : "#{@@path}/"
|
49
|
+
path.start_with?('/') ? path[1..path.length] : path
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sets the host to use in the shortened url
|
53
|
+
# @param [String] the host to use in the shotened url
|
54
|
+
def self.host= host
|
55
|
+
@@host = host
|
56
|
+
end
|
57
|
+
|
58
|
+
# Gets the host for the shortened url
|
59
|
+
# @return [String] the host for the shortened url
|
60
|
+
def self.host
|
61
|
+
@@host.end_with?('/') ? @@host : "#{@@host}/"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Creates a shortened url id of 8 characters, creates and saves a redirect object with the
|
65
|
+
# new shortened url id.
|
66
|
+
# @param [String] the url to redirect to
|
67
|
+
# @return [Redirect] a saved redirect object with the newly created shortened url.
|
68
|
+
def self.create_shortened_url(original_url)
|
69
|
+
redir = self.new :original_url => original_url
|
70
|
+
shortened_id = SecureRandom.urlsafe_base64(6)
|
71
|
+
duplicate_find = Redirect.where(:shortened_id => shortened_id)
|
72
|
+
if duplicate_find and duplicate_find.last and (shortened_id == duplicate_find.last.shortened_id)
|
73
|
+
shortened_id = SecureRandom.urlsafe_base64(6)
|
74
|
+
end
|
75
|
+
redir.shortened_id = shortened_id
|
76
|
+
redir.save!
|
77
|
+
redir
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the entire shortened url which consists of the host, path and shortened id
|
81
|
+
# @return [String] the shortened url
|
82
|
+
def shortened_url
|
83
|
+
"#{self.class.host}#{self.class.path}#{shortened_id}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns the shortened url path consisting of the path and shortened id
|
87
|
+
# @return [String] the shortened path
|
88
|
+
def shortened_path
|
89
|
+
"#{self.class.path}#{shortened_id}"
|
90
|
+
end
|
91
|
+
end
|
data/lib/rack/redir.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Bounce those annoying favicon.ico requests
|
5
|
+
class Redir
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
env['PATH_INFO'] =~ %r{^a/(.+)$}
|
12
|
+
parsed_path = env['PATH_INFO'].split(/\//)
|
13
|
+
if "#{parsed_path.second}/" == Redirect.path
|
14
|
+
redir_asset = parsed_path.last
|
15
|
+
redirect_record = (Redirect.where shortened_id: redir_asset).to_a.last
|
16
|
+
headers = env.select {|k,v| k.start_with? 'HTTP_'}
|
17
|
+
if redirect_record and redirect_record.shortened_id == redir_asset
|
18
|
+
redirect_url = redirect_record.original_url.strip
|
19
|
+
redirect_to_url = redirect_url.start_with?('http') ? redirect_url : "http://#{redirect_url}"
|
20
|
+
redirect_log = RedirectLog.new(:redirect_id => redirect_record.id,
|
21
|
+
:headers => headers, :request_time => Time.now)
|
22
|
+
redirect_log.save!
|
23
|
+
if Redirect.append_tracking_info
|
24
|
+
redirect_to_url = append_parameter_separater redirect_to_url
|
25
|
+
redirect_to_url = "#{redirect_to_url}redirect_mongo_id=" +
|
26
|
+
"#{redirect_log.redirect_id}&redirect_log_mongo_id=#{redirect_log._id}"
|
27
|
+
end
|
28
|
+
if Redirect.append_google_analytics
|
29
|
+
redirect_to_url = append_parameter_separater redirect_to_url
|
30
|
+
redirect_to_url = "#{redirect_to_url}utm_source=#{Rack::Utils.escape Redirect.host}" +
|
31
|
+
"&utm_campaign=#{redirect_log.redirect_id}__#{redirect_log._id}"
|
32
|
+
end
|
33
|
+
[302, {'Location' => redirect_to_url}, self]
|
34
|
+
else
|
35
|
+
[404, {}, self]
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@app.call env
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def append_parameter_separater url
|
44
|
+
url.match('\?') ? "#{url}&" : "#{url}?"
|
45
|
+
end
|
46
|
+
|
47
|
+
def each(&block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/lib/redir.rb
ADDED
data/lib/redirector.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Redirector
|
2
|
+
# finds logs associated with the shortened url
|
3
|
+
# @params [String] the shortened id to find logs for
|
4
|
+
# @returns [Array] the logs for the shortened id as an array
|
5
|
+
def Redirector.find_logs shortened_id
|
6
|
+
RedirectLog.where(:redirect_id => find_redirect_by_shortened_id(shortened_id)).to_a
|
7
|
+
end
|
8
|
+
|
9
|
+
# finds the number of times a redirect has been accessed
|
10
|
+
# @returns [Integer] the number of times the redirect has been accessed
|
11
|
+
def Redirector.number_of_redirect_hits shortened_id
|
12
|
+
RedirectLog.where(:redirect_id => find_redirect_by_shortened_id(shortened_id)).count
|
13
|
+
end
|
14
|
+
|
15
|
+
def Redirector.find_redirect_by_shortened_id shortened_id
|
16
|
+
Redirect.where(:shortened_id => shortened_id).to_a.last._id
|
17
|
+
end
|
18
|
+
end
|
data/redir.gemspec
ADDED
@@ -0,0 +1,81 @@
|
|
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 = "redir"
|
8
|
+
s.version = "0.0.4"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Lance Gleason"]
|
12
|
+
s.date = "2012-10-24"
|
13
|
+
s.description = "This gem adds functionality to shorten url's and gather data about requests going through it."
|
14
|
+
s.email = "lgleason@polyglotprogramminginc.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/model/redirect.rb",
|
27
|
+
"lib/model/redirect_log.rb",
|
28
|
+
"lib/rack/redir.rb",
|
29
|
+
"lib/redir.rb",
|
30
|
+
"lib/redirector.rb",
|
31
|
+
"redir.gemspec",
|
32
|
+
"spec/factories/redirect.rb",
|
33
|
+
"spec/mongoid.yml",
|
34
|
+
"spec/spec_helper.rb",
|
35
|
+
"spec/unit/model/redirect_spec.rb",
|
36
|
+
"spec/unit/rack/redir_spec.rb",
|
37
|
+
"spec/unit/redirector_spec.rb"
|
38
|
+
]
|
39
|
+
s.homepage = "http://github.com/springbot/redir"
|
40
|
+
s.licenses = ["MIT"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = "1.8.24"
|
43
|
+
s.summary = "A Mongo based url shortener and data gathering gem."
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_runtime_dependency(%q<mongoid>, ["~> 3.0.0"])
|
50
|
+
s.add_runtime_dependency(%q<rack>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<rack-test>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<factory_girl>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<mongoid>, ["~> 3.0.0"])
|
60
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
61
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
62
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
63
|
+
s.add_dependency(%q<factory_girl>, [">= 0"])
|
64
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
65
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
66
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
67
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<mongoid>, ["~> 3.0.0"])
|
71
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
73
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
74
|
+
s.add_dependency(%q<factory_girl>, [">= 0"])
|
75
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
76
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
77
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
78
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/spec/mongoid.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Tell Mongoid which environment this configuration is for.
|
2
|
+
test:
|
3
|
+
# This starts the session configuration settings. You may have as
|
4
|
+
# many sessions as you like, but you must have at least 1 named
|
5
|
+
# 'default'.
|
6
|
+
sessions:
|
7
|
+
# Define the default session.
|
8
|
+
default:
|
9
|
+
# A session can have any number of hosts. Usually 1 for a single
|
10
|
+
# server setup, and at least 3 for a replica set. Hosts must be
|
11
|
+
# an array of host:port pairs. This session is single server.
|
12
|
+
hosts:
|
13
|
+
- localhost:27017
|
14
|
+
# Define the default database name.
|
15
|
+
database: www_test
|
16
|
+
# Since this database points at a session connected to MongoHQ, we must
|
17
|
+
# provide the authentication details.
|
18
|
+
options:
|
19
|
+
allow_dynamic_fields: true
|
20
|
+
identity_map_enabled: true
|
21
|
+
include_root_in_json: true
|
22
|
+
# Note this can also be true if you want to preload everything, but this is
|
23
|
+
# almost never necessary. Most of the time set this to false.
|
24
|
+
scope_overwrite_exception: true
|
25
|
+
raise_not_found_error: false
|
26
|
+
skip_version_check: false
|
27
|
+
use_activesupport_time_zone: false
|
28
|
+
use_utc: true
|
29
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'bundler'
|
4
|
+
require 'mongoid'
|
5
|
+
require 'factory_girl'
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start
|
8
|
+
|
9
|
+
Mongoid.load!('./spec/mongoid.yml', :test)
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.include FactoryGirl::Syntax::Methods
|
13
|
+
end
|
14
|
+
|
15
|
+
FactoryGirl.find_definitions
|
16
|
+
|
17
|
+
Dir['lib/**/*.rb'].each {|f| require File.join(File.dirname(__FILE__), '..', f.gsub(/.rb/, ''))}
|
18
|
+
|
19
|
+
module RedirHelper
|
20
|
+
require 'rack/test'
|
21
|
+
include Rack::Test::Methods
|
22
|
+
|
23
|
+
def app
|
24
|
+
test_app = lambda do |env|
|
25
|
+
[200, {}, 'test app']
|
26
|
+
end
|
27
|
+
|
28
|
+
Rack::Redir.new test_app
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include RedirHelper
|
3
|
+
|
4
|
+
describe :redirect do
|
5
|
+
|
6
|
+
after :each do
|
7
|
+
Redirect.delete_all
|
8
|
+
RedirectLog.delete_all
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'redirect generator' do
|
12
|
+
context 'should generate a unique url' do
|
13
|
+
before :each do
|
14
|
+
SecureRandom.should_receive(:urlsafe_base64).with(6).and_return('eeeeee')
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:redirect) { Redirect.create_shortened_url 'http://www.google.com' }
|
18
|
+
subject {redirect}
|
19
|
+
its (:shortened_id) {should eq 'eeeeee'}
|
20
|
+
its (:shortened_path) {should eq 'a/eeeeee'}
|
21
|
+
its (:shortened_url) {should eq 'http://localhost:3000/a/eeeeee'}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
context 'duplicate redirects' do
|
26
|
+
before do
|
27
|
+
SecureRandom.should_receive(:urlsafe_base64).with(6).twice.and_return('eeeeee')
|
28
|
+
SecureRandom.should_receive(:urlsafe_base64).with(6).once.and_return('ffffff')
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:redirect) { Redirect.create_shortened_url 'http://www.google.com' }
|
32
|
+
let(:second_redirect) { Redirect.create_shortened_url 'http://www.yahoo.com' }
|
33
|
+
|
34
|
+
it "should get a unique url on each request" do
|
35
|
+
redirect.shortened_id.should eq 'eeeeee'
|
36
|
+
second_redirect.shortened_id.should eq 'ffffff'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'leading and trailing slashes' do
|
42
|
+
context 'host' do
|
43
|
+
context 'no trailing slash' do
|
44
|
+
let (:redirect) {Redirect.create_shortened_url 'www.springbot.com'}
|
45
|
+
|
46
|
+
before do
|
47
|
+
Redirect.host = 'www.honeybadger.com'
|
48
|
+
SecureRandom.should_receive(:urlsafe_base64).with(6).at_most(:once).and_return('eeeeee')
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'global host' do
|
52
|
+
subject {Redirect}
|
53
|
+
its (:host) {should eq 'www.honeybadger.com/'}
|
54
|
+
end
|
55
|
+
|
56
|
+
subject {redirect}
|
57
|
+
its (:shortened_url) {should eq 'www.honeybadger.com/a/eeeeee'}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'path' do
|
62
|
+
|
63
|
+
shared_examples_for 'a correct redirect' do
|
64
|
+
before {SecureRandom.should_receive(:urlsafe_base64).with(6).at_most(:once).and_return('eeeeee')}
|
65
|
+
let (:redirect) {Redirect.create_shortened_url 'www.springbot.com'}
|
66
|
+
context 'global host' do
|
67
|
+
subject {Redirect}
|
68
|
+
its (:path) {should eq 'badger/'}
|
69
|
+
end
|
70
|
+
|
71
|
+
subject {redirect}
|
72
|
+
its (:shortened_url) {should eq 'www.honeybadger.com/badger/eeeeee'}
|
73
|
+
its (:shortened_path) {should eq 'badger/eeeeee'}
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'no trailing slash' do
|
77
|
+
before { Redirect.path = 'badger'}
|
78
|
+
it_behaves_like 'a correct redirect'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'no trailing slash and slash at the beginning' do
|
82
|
+
before { Redirect.path = '/badger' }
|
83
|
+
it_behaves_like 'a correct redirect'
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include RedirHelper
|
3
|
+
|
4
|
+
describe :redir do
|
5
|
+
|
6
|
+
after :each do
|
7
|
+
Redirect.delete_all
|
8
|
+
RedirectLog.delete_all
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples_for 'code that redirects' do
|
12
|
+
|
13
|
+
before do
|
14
|
+
before
|
15
|
+
get redirect.shortened_path.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'redirects' do
|
19
|
+
before do
|
20
|
+
follow_redirect!
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'url' do
|
24
|
+
subject {last_request}
|
25
|
+
its(:url) {should eq redirect.original_url}
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'response' do
|
29
|
+
subject {last_response.errors.size}
|
30
|
+
it {should eq 0}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:before) {Time.now}
|
37
|
+
let(:after) {Time.now}
|
38
|
+
|
39
|
+
context 'should apply class level settings for the url and path' do
|
40
|
+
before do
|
41
|
+
SecureRandom.should_receive(:urlsafe_base64).with(6).and_return('eeeeee')
|
42
|
+
Redirect.path = 'foo/'
|
43
|
+
Redirect.host = 'http://myredir.com/'
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:redirect) { Redirect.create_shortened_url 'http://www.google.com/' }
|
47
|
+
subject {redirect}
|
48
|
+
its (:shortened_id) {should eq 'eeeeee'}
|
49
|
+
its (:shortened_path) {should eq 'foo/eeeeee'}
|
50
|
+
its (:shortened_url) {should eq 'http://myredir.com/foo/eeeeee'}
|
51
|
+
|
52
|
+
context 'non default path' do
|
53
|
+
it_behaves_like 'code that redirects'
|
54
|
+
end
|
55
|
+
|
56
|
+
after do
|
57
|
+
Redirect.path = 'a/'
|
58
|
+
Redirect.host = 'http://localhost:3000/'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
context 'general redirect' do
|
64
|
+
|
65
|
+
let(:redirect) {create :redirect}
|
66
|
+
before do
|
67
|
+
before
|
68
|
+
get redirect.shortened_path.to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
it_behaves_like 'code that redirects'
|
72
|
+
|
73
|
+
let(:redirect_log) {RedirectLog.where(:redirect_id => redirect.id).to_a.last}
|
74
|
+
|
75
|
+
context 'headers' do
|
76
|
+
subject {redirect_log.headers}
|
77
|
+
its (['HTTP_HOST']) {should eq 'example.org'}
|
78
|
+
its (['HTTP_COOKIE']) {should eq ''}
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'request time' do
|
82
|
+
subject {redirect_log}
|
83
|
+
its (:request_time) {should > before}
|
84
|
+
its (:request_time) {should < after}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'redirect with tracking info appended' do
|
89
|
+
before do
|
90
|
+
Redirect.append_tracking_info = true
|
91
|
+
get redirect.shortened_path.to_s
|
92
|
+
follow_redirect!
|
93
|
+
end
|
94
|
+
let (:redirect_log) {Redirector.find_logs(redirect.shortened_id).last}
|
95
|
+
|
96
|
+
context 'with existing url data' do
|
97
|
+
let (:redirect) {create :redirect, :original_url => 'www.google.com/?foo=bar'}
|
98
|
+
subject {last_request}
|
99
|
+
its (:url) {should eq "http://www.google.com/?foo=bar&redirect_mongo_id=#{redirect_log.redirect_id}" +
|
100
|
+
"&redirect_log_mongo_id=#{redirect_log._id}"}
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'without existing url data' do
|
104
|
+
let (:redirect) {create :redirect, :original_url => 'www.google.com'}
|
105
|
+
subject {last_request}
|
106
|
+
its (:url) {should eq "http://www.google.com/?redirect_mongo_id=#{redirect_log.redirect_id}" +
|
107
|
+
"&redirect_log_mongo_id=#{redirect_log._id}"}
|
108
|
+
end
|
109
|
+
|
110
|
+
after do
|
111
|
+
Redirect.append_tracking_info = false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'redirect with google analytics info appended' do
|
116
|
+
before do
|
117
|
+
Redirect.append_google_analytics = true
|
118
|
+
get redirect.shortened_path.to_s
|
119
|
+
follow_redirect!
|
120
|
+
end
|
121
|
+
let (:redirect_log) {Redirector.find_logs(redirect.shortened_id).last}
|
122
|
+
|
123
|
+
context 'with existing url data' do
|
124
|
+
let (:redirect) {create :redirect, :original_url => 'www.google.com/?foo=bar'}
|
125
|
+
subject {last_request}
|
126
|
+
its (:url) {should eq "http://www.google.com/?foo=bar&utm_source=http%3A%2F%2Flocalhost%3A3000%2F" +
|
127
|
+
"&utm_campaign=#{redirect_log.redirect_id}__#{redirect_log._id}"}
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'without existing url data' do
|
131
|
+
let (:redirect) {create :redirect, :original_url => 'www.google.com'}
|
132
|
+
subject {last_request}
|
133
|
+
its (:url) {should eq "http://www.google.com/?utm_source=http%3A%2F%2Flocalhost%3A3000%2F" +
|
134
|
+
"&utm_campaign=#{redirect_log.redirect_id}__#{redirect_log._id}"}
|
135
|
+
end
|
136
|
+
|
137
|
+
after do
|
138
|
+
Redirect.append_google_analytics = false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'redirect with no preceeding http' do
|
143
|
+
before do
|
144
|
+
get redirect.shortened_path.to_s
|
145
|
+
follow_redirect!
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'url without http' do
|
149
|
+
let (:redirect) {create :redirect, :original_url => 'www.google.com'}
|
150
|
+
subject {last_request}
|
151
|
+
its (:url) {should eq 'http://www.google.com/'}
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'url without http and leading space' do
|
155
|
+
let (:redirect) {create :redirect, :original_url => ' www.google.com'}
|
156
|
+
subject {last_request}
|
157
|
+
its (:url) {should eq 'http://www.google.com/'}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'bad redirect' do
|
162
|
+
|
163
|
+
before do
|
164
|
+
get "/a/ugh"
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'status' do
|
168
|
+
subject {last_response.status}
|
169
|
+
it {should eq 404}
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'non rdr path' do
|
175
|
+
|
176
|
+
before do
|
177
|
+
get "/rddd/ugh"
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'status' do
|
181
|
+
subject {last_response.status}
|
182
|
+
it {should eq 200}
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include RedirHelper
|
3
|
+
|
4
|
+
describe :redirector do
|
5
|
+
|
6
|
+
let(:redirect) { Redirect.create_shortened_url 'http://www.google.com/' }
|
7
|
+
before {get redirect.shortened_path.to_s}
|
8
|
+
|
9
|
+
context 'find logs' do
|
10
|
+
|
11
|
+
subject {Redirector.find_logs(redirect.shortened_id).to_a}
|
12
|
+
its(:size) {should eq 1}
|
13
|
+
|
14
|
+
context 'data' do
|
15
|
+
subject {Redirector.find_logs(redirect.shortened_id).to_a.last.headers['HTTP_HOST']}
|
16
|
+
it {should eq 'example.org'}
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'multiple requests' do
|
20
|
+
before {get redirect.shortened_path.to_s}
|
21
|
+
subject {Redirector.find_logs(redirect.shortened_id).to_a}
|
22
|
+
its(:size) {should eq 2}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'number of redirect hits' do
|
27
|
+
subject {Redirector.number_of_redirect_hits redirect.shortened_id}
|
28
|
+
it {should eq 1}
|
29
|
+
|
30
|
+
context 'multiple requests' do
|
31
|
+
before {get redirect.shortened_path.to_s}
|
32
|
+
subject {Redirector.number_of_redirect_hits redirect.shortened_id}
|
33
|
+
it {should eq 2}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
after :all do
|
39
|
+
Redirect.delete_all
|
40
|
+
RedirectLog.delete_all
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redir
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lance Gleason
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mongoid
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rack
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rack-test
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: factory_girl
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: timecop
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: jeweler
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: yard
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
description: This gem adds functionality to shorten url's and gather data about requests
|
159
|
+
going through it.
|
160
|
+
email: lgleason@polyglotprogramminginc.com
|
161
|
+
executables: []
|
162
|
+
extensions: []
|
163
|
+
extra_rdoc_files:
|
164
|
+
- LICENSE.txt
|
165
|
+
- README.md
|
166
|
+
files:
|
167
|
+
- Gemfile
|
168
|
+
- Gemfile.lock
|
169
|
+
- LICENSE.txt
|
170
|
+
- README.md
|
171
|
+
- Rakefile
|
172
|
+
- VERSION
|
173
|
+
- lib/model/redirect.rb
|
174
|
+
- lib/model/redirect_log.rb
|
175
|
+
- lib/rack/redir.rb
|
176
|
+
- lib/redir.rb
|
177
|
+
- lib/redirector.rb
|
178
|
+
- redir.gemspec
|
179
|
+
- spec/factories/redirect.rb
|
180
|
+
- spec/mongoid.yml
|
181
|
+
- spec/spec_helper.rb
|
182
|
+
- spec/unit/model/redirect_spec.rb
|
183
|
+
- spec/unit/rack/redir_spec.rb
|
184
|
+
- spec/unit/redirector_spec.rb
|
185
|
+
homepage: http://github.com/springbot/redir
|
186
|
+
licenses:
|
187
|
+
- MIT
|
188
|
+
post_install_message:
|
189
|
+
rdoc_options: []
|
190
|
+
require_paths:
|
191
|
+
- lib
|
192
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
segments:
|
199
|
+
- 0
|
200
|
+
hash: 1346305912499164627
|
201
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
203
|
+
requirements:
|
204
|
+
- - ! '>='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
requirements: []
|
208
|
+
rubyforge_project:
|
209
|
+
rubygems_version: 1.8.24
|
210
|
+
signing_key:
|
211
|
+
specification_version: 3
|
212
|
+
summary: A Mongo based url shortener and data gathering gem.
|
213
|
+
test_files: []
|