shortener 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.rdoc +17 -14
- data/app/controllers/shortener/shortened_urls_controller.rb +2 -2
- data/app/helpers/shortener/shortener_helper.rb +1 -1
- data/app/models/shortener/shortened_url.rb +12 -9
- data/config/routes.rb +1 -1
- data/lib/generators/shortener/shortener_generator.rb +5 -3
- data/lib/generators/shortener/templates/migration.rb +5 -5
- data/lib/shortener/active_record_extension.rb +1 -1
- data/lib/shortener/shorten_url_interceptor.rb +1 -1
- data/lib/shortener/version.rb +1 -1
- data/lib/shortener.rb +7 -2
- data/shortener.gemspec +3 -1
- data/spec/controllers/shortened_urls_controller_spec.rb +62 -29
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/config/initializers/session_store.rb +1 -1
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/dummy/db/migrate/20120213084304_create_shortened_urls_table.rb +5 -5
- data/spec/helpers/shortener_helper_spec.rb +20 -5
- data/spec/models/shortened_url_spec.rb +80 -48
- data/spec/shortener/shorten_url_interceptor_spec.rb +9 -9
- data/spec/spec_helper.rb +2 -0
- metadata +33 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f4d4b7d3190fc69489c4b1801b999f68d343d63
|
4
|
+
data.tar.gz: 56ab4d022830a4fa77fd076bde77d0d24d995e81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6aa5e1de18874e3c1df7ce6fe526c3ac4cc13a36dfa23c985c625b0d66b714e779409dcb9ddef2ca048fe52a0d0367628bf0384d537e05450f99d8c293cb0b3
|
7
|
+
data.tar.gz: 86253d34dcb01f8db8636a0df687dce67d0ca486fcab4f9754a98a01a91f3b1fc1d77b5040265a0f79ab7718f1209a73eca06c19fb08034aa903fc2b9ba50189
|
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -36,29 +36,34 @@ The majority of the Shortener consists of three parts:
|
|
36
36
|
You can use the latest Rails 3 gem with the latest Shortener gem. In your Gemfile:
|
37
37
|
|
38
38
|
gem 'shortener'
|
39
|
-
|
39
|
+
|
40
40
|
After you install Shortener run the generator:
|
41
41
|
|
42
42
|
rails generate shortener
|
43
|
-
|
43
|
+
|
44
44
|
This generator will create a migration to create the shortened_urls table where your shortened URLs will be stored.
|
45
45
|
|
46
46
|
Then add to your routes:
|
47
47
|
|
48
48
|
match '/:id' => "shortener/shortened_urls#show"
|
49
49
|
|
50
|
-
==
|
51
|
-
|
52
|
-
By default, the shortener will generate keys that are 5 characters long. You can change that by specifying the length of the key in the config/initializers/shortener.rb file.
|
50
|
+
== Configuration
|
51
|
+
The gem can be configured in a config/initializers/shortener.rb file.
|
53
52
|
|
53
|
+
By default, the shortener will generate keys that are 5 characters long. You can change that by specifying the length of the key like so;
|
54
|
+
```
|
54
55
|
Shortener.unique_key_length = 6
|
55
|
-
|
56
|
+
```
|
57
|
+
By default, when a unique key isn't matched the site is redirected to "/". You can change that by specifying a different url like so;
|
58
|
+
```
|
59
|
+
Shortener.default_redirect = "http://www.someurl.com"
|
60
|
+
```
|
56
61
|
== Usage
|
57
62
|
|
58
63
|
To generate a Shortened URL object for the URL "http://dealush.com" within your controller / models do the following:
|
59
|
-
|
64
|
+
|
60
65
|
Shortener::ShortenedUrl.generate("http://dealush.com")
|
61
|
-
|
66
|
+
|
62
67
|
or
|
63
68
|
|
64
69
|
Shortener::ShortenedUrl.generate("dealush.com")
|
@@ -66,7 +71,7 @@ or
|
|
66
71
|
To generate and display a shortened URL in your application use the helper method:
|
67
72
|
|
68
73
|
short_url("dealush.com")
|
69
|
-
|
74
|
+
|
70
75
|
This will generate a shortened URL. store it to the db and return a string representing the shortened URL.
|
71
76
|
|
72
77
|
=== Shortened URLs with owner
|
@@ -79,7 +84,7 @@ You can link shortened URLs to an owner, to scope them. To do so, add the follow
|
|
79
84
|
|
80
85
|
This will allow you to pass the owner when generating URLs:
|
81
86
|
|
82
|
-
Shortener::ShortenedUrl.generate("
|
87
|
+
Shortener::ShortenedUrl.generate("example.com", user)
|
83
88
|
|
84
89
|
And to access those URLs:
|
85
90
|
|
@@ -103,16 +108,14 @@ The interceptor supports a few more arguments, see the implementation for detail
|
|
103
108
|
|
104
109
|
== Origins
|
105
110
|
|
106
|
-
Shortener is based on code from Dealush[http://
|
111
|
+
Shortener is based on code from Dealush[http://example.com], for a bit of backstory to Shortener see this {blog post}[http://jamespmcgrath.com/a-simple-link-shortener-in-rails/].
|
107
112
|
|
108
113
|
== In The Wild
|
109
114
|
|
110
|
-
Shortener is used in a number of production systems:
|
115
|
+
Shortener is used in a number of production systems, including, but not limited to:
|
111
116
|
|
112
117
|
{Doorkeeper - An Event Management Tool}[http://www.doorkeeperhq.com/]
|
113
118
|
|
114
|
-
{Dealush - A Local shopping Sales Notification Service}[http://dealush.com]
|
115
|
-
|
116
119
|
If you are using Shortener in your project and would like to be added to this list, please get in touch!
|
117
120
|
|
118
121
|
== Authors
|
@@ -18,11 +18,11 @@ class Shortener::ShortenedUrlsController < ActionController::Base
|
|
18
18
|
ActiveRecord::Base.connection.close
|
19
19
|
end
|
20
20
|
# do a 301 redirect to the destination url
|
21
|
-
redirect_to sl.url, :
|
21
|
+
redirect_to sl.url, status: :moved_permanently
|
22
22
|
else
|
23
23
|
# if we don't find the shortened link, redirect to the root
|
24
24
|
# make this configurable in future versions
|
25
|
-
redirect_to
|
25
|
+
redirect_to Shortener.default_redirect
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -3,7 +3,7 @@ module Shortener::ShortenerHelper
|
|
3
3
|
# generate a url from a url string
|
4
4
|
def short_url(url, owner=nil)
|
5
5
|
short_url = Shortener::ShortenedUrl.generate(url, owner)
|
6
|
-
short_url ? url_for(:
|
6
|
+
short_url ? url_for(controller: :"shortener/shortened_urls", action: :show, id: short_url.unique_key, only_path: false) : url
|
7
7
|
end
|
8
8
|
|
9
9
|
end
|
@@ -3,10 +3,10 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
|
|
3
3
|
URL_PROTOCOL_HTTP = "http://"
|
4
4
|
REGEX_LINK_HAS_PROTOCOL = Regexp.new('\Ahttp:\/\/|\Ahttps:\/\/', Regexp::IGNORECASE)
|
5
5
|
|
6
|
-
validates :url, :
|
6
|
+
validates :url, presence: true
|
7
7
|
|
8
8
|
# allows the shortened link to be associated with a user
|
9
|
-
belongs_to :owner, :
|
9
|
+
belongs_to :owner, polymorphic: true
|
10
10
|
|
11
11
|
# ensure the url starts with it protocol and is normalized
|
12
12
|
def self.clean_url(url)
|
@@ -21,15 +21,18 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
|
|
21
21
|
def self.generate!(orig_url, owner=nil)
|
22
22
|
# if we get a shortened_url object with a different owner, generate
|
23
23
|
# new one for the new owner. Otherwise return same object
|
24
|
-
if orig_url.is_a?
|
25
|
-
|
24
|
+
if orig_url.is_a? Shortener::ShortenedUrl
|
25
|
+
if orig_url.owner == owner
|
26
|
+
result = orig_url
|
27
|
+
else
|
28
|
+
result generate!(orig_url.url, owner)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
scope = owner ? owner.shortened_urls : self
|
32
|
+
result = scope.where(url: clean_url(orig_url)).first_or_create
|
26
33
|
end
|
27
34
|
|
28
|
-
|
29
|
-
# so check the datastore
|
30
|
-
cleaned_url = clean_url(orig_url)
|
31
|
-
scope = owner ? owner.shortened_urls : self
|
32
|
-
scope.where(:url => cleaned_url).first_or_create
|
35
|
+
result
|
33
36
|
end
|
34
37
|
|
35
38
|
# return shortened url on success, nil on failure
|
data/config/routes.rb
CHANGED
@@ -3,10 +3,11 @@ require 'rails/generators/migration'
|
|
3
3
|
|
4
4
|
class ShortenerGenerator < Rails::Generators::Base
|
5
5
|
include Rails::Generators::Migration
|
6
|
+
|
6
7
|
def self.source_root
|
7
8
|
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
8
9
|
end
|
9
|
-
|
10
|
+
|
10
11
|
def self.next_migration_number(dirname)
|
11
12
|
if ActiveRecord::Base.timestamped_migrations
|
12
13
|
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
@@ -14,8 +15,9 @@ class ShortenerGenerator < Rails::Generators::Base
|
|
14
15
|
"%.3d" % (current_migration_number(dirname) + 1)
|
15
16
|
end
|
16
17
|
end
|
17
|
-
|
18
|
+
|
18
19
|
def create_migration_file
|
19
20
|
migration_template 'migration.rb', 'db/migrate/create_shortened_urls_table.rb'
|
20
21
|
end
|
21
|
-
|
22
|
+
|
23
|
+
end
|
@@ -3,23 +3,23 @@ class CreateShortenedUrlsTable < ActiveRecord::Migration
|
|
3
3
|
create_table :shortened_urls do |t|
|
4
4
|
# we can link this to a user for interesting things
|
5
5
|
t.integer :owner_id
|
6
|
-
t.string :owner_type, :
|
6
|
+
t.string :owner_type, limit: 20
|
7
7
|
|
8
8
|
# the real url that we will redirect to
|
9
|
-
t.string :url, :
|
9
|
+
t.string :url, null: false
|
10
10
|
|
11
11
|
# the unique key
|
12
|
-
t.string :unique_key, :
|
12
|
+
t.string :unique_key, limit: 10, null: false
|
13
13
|
|
14
14
|
# how many times the link has been clicked
|
15
|
-
t.integer :use_count, :
|
15
|
+
t.integer :use_count, null: false, default: 0
|
16
16
|
|
17
17
|
t.timestamps
|
18
18
|
end
|
19
19
|
|
20
20
|
# we will lookup the links in the db by key, urls and owners.
|
21
21
|
# also make sure the unique keys are actually unique
|
22
|
-
add_index :shortened_urls, :unique_key, :
|
22
|
+
add_index :shortened_urls, :unique_key, unique: true
|
23
23
|
add_index :shortened_urls, :url
|
24
24
|
add_index :shortened_urls, [:owner_id, :owner_type]
|
25
25
|
end
|
data/lib/shortener/version.rb
CHANGED
data/lib/shortener.rb
CHANGED
@@ -6,8 +6,9 @@ module Shortener
|
|
6
6
|
autoload :ShortenUrlInterceptor, "shortener/shorten_url_interceptor"
|
7
7
|
|
8
8
|
CHARSETS = {
|
9
|
-
:
|
10
|
-
:
|
9
|
+
alphanum: ('a'..'z').to_a + (0..9).to_a,
|
10
|
+
alphanumcase: ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
|
11
|
+
}
|
11
12
|
|
12
13
|
# default key length: 5 characters
|
13
14
|
mattr_accessor :unique_key_length
|
@@ -19,6 +20,10 @@ module Shortener
|
|
19
20
|
mattr_accessor :charset
|
20
21
|
self.charset = :alphanum
|
21
22
|
|
23
|
+
#The default redirection url when the key isn't found
|
24
|
+
mattr_accessor :default_redirect
|
25
|
+
self.default_redirect = '/'
|
26
|
+
|
22
27
|
def self.key_chars
|
23
28
|
CHARSETS[charset]
|
24
29
|
end
|
data/shortener.gemspec
CHANGED
@@ -16,8 +16,10 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.required_rubygems_version = "> 1.3.6"
|
17
17
|
s.add_dependency "rails", ">= 3.0.7"
|
18
18
|
s.add_development_dependency "sqlite3"
|
19
|
-
s.add_development_dependency "rspec-rails", '~>
|
19
|
+
s.add_development_dependency "rspec-rails", '~> 3.3.0'
|
20
20
|
s.add_development_dependency "shoulda-matchers"
|
21
|
+
s.add_development_dependency "faker"
|
22
|
+
s.add_development_dependency "byebug"
|
21
23
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
22
24
|
s.require_path = 'lib'
|
23
25
|
end
|
@@ -1,40 +1,73 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
response.should redirect_to("http://www.doorkeeperhq.com/")
|
8
|
-
end
|
9
|
-
end
|
4
|
+
describe Shortener::ShortenedUrlsController, type: :controller do
|
5
|
+
let(:destination) { Faker::Internet.url }
|
6
|
+
let(:short_url) { Shortener::ShortenedUrl.generate(destination) }
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
8
|
+
describe '#show' do
|
9
|
+
before do
|
10
|
+
get :show, id: key
|
11
|
+
end
|
17
12
|
|
18
|
-
|
19
|
-
|
13
|
+
context 'valid keys' do
|
14
|
+
context 'real key' do
|
15
|
+
let(:key) { short_url.unique_key}
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
it 'redirects to the destination url' do
|
18
|
+
expect(response).to redirect_to destination
|
19
|
+
end
|
20
|
+
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
it_should_behave_like "good code"
|
29
|
-
end
|
22
|
+
context 'real key with trailing characters' do
|
23
|
+
let(:key) { "#{short_url.unique_key}-" }
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
it 'redirects to the destination url' do
|
26
|
+
expect(response).to redirect_to destination
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'invalid keys' do
|
32
|
+
context 'non existant key' do
|
33
|
+
let(:key) { "nonexistantkey" }
|
34
|
+
|
35
|
+
it 'redirects to the root url' do
|
36
|
+
expect(response).to redirect_to root_url
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'key with invalid characters' do
|
41
|
+
let(:key) { "-" }
|
42
|
+
|
43
|
+
it 'redirects to the root url' do
|
44
|
+
expect(response).to redirect_to root_url
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "custom default redirect set" do
|
49
|
+
before do
|
50
|
+
Shortener.default_redirect = 'http://www.default_redirect.com'
|
51
|
+
# call again for the get is done with the setting
|
52
|
+
get :show, id: key
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'non existant key' do
|
56
|
+
let(:key) { "nonexistantkey" }
|
57
|
+
|
58
|
+
it 'redirects to the root url' do
|
59
|
+
expect(response).to redirect_to 'http://www.default_redirect.com'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'key with invalid characters' do
|
64
|
+
let(:key) { "-" }
|
35
65
|
|
36
|
-
|
37
|
-
|
38
|
-
|
66
|
+
it 'redirects to the root url' do
|
67
|
+
expect(response).to redirect_to 'http://www.default_redirect.com'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
39
72
|
end
|
40
73
|
end
|
@@ -37,6 +37,6 @@ module Dummy
|
|
37
37
|
# Configure sensitive parameters which will be filtered from the log file.
|
38
38
|
config.filter_parameters += [:password]
|
39
39
|
|
40
|
-
config.action_mailer.default_url_options = { :
|
40
|
+
config.action_mailer.default_url_options = { host: "mbln.jp" }
|
41
41
|
end
|
42
42
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Be sure to restart your server when you modify this file.
|
2
2
|
|
3
|
-
Dummy::Application.config.session_store :cookie_store, :
|
3
|
+
Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
|
4
4
|
|
5
5
|
# Use the database for sessions instead of the cookie-based default,
|
6
6
|
# which shouldn't be used to store highly confidential information
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -3,23 +3,23 @@ class CreateShortenedUrlsTable < ActiveRecord::Migration
|
|
3
3
|
create_table :shortened_urls do |t|
|
4
4
|
# we can link this to a user for interesting things
|
5
5
|
t.integer :owner_id
|
6
|
-
t.string :owner_type, :
|
6
|
+
t.string :owner_type, limit: 20
|
7
7
|
|
8
8
|
# the real url that we will redirect to
|
9
|
-
t.string :url, :
|
9
|
+
t.string :url, null: false
|
10
10
|
|
11
11
|
# the unique key
|
12
|
-
t.string :unique_key, :
|
12
|
+
t.string :unique_key, limit: 10, null: false
|
13
13
|
|
14
14
|
# how many times the link has been clicked
|
15
|
-
t.integer :use_count, :
|
15
|
+
t.integer :use_count, null: false, default: 0
|
16
16
|
|
17
17
|
t.timestamps
|
18
18
|
end
|
19
19
|
|
20
20
|
# we will lookup the links in the db by key and owners.
|
21
21
|
# also make sure the unique keys are actually unique
|
22
|
-
add_index :shortened_urls, :unique_key, :
|
22
|
+
add_index :shortened_urls, :unique_key, unique: true
|
23
23
|
add_index :shortened_urls, :url
|
24
24
|
add_index :shortened_urls, [:owner_id, :owner_type]
|
25
25
|
end
|
@@ -1,12 +1,27 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
-
describe Shortener::ShortenerHelper do
|
5
|
-
|
4
|
+
describe Shortener::ShortenerHelper, type: :helper do
|
5
|
+
describe '#short_url' do
|
6
|
+
let(:destination) { Faker::Internet.url }
|
7
|
+
before do
|
8
|
+
expect(Shortener::ShortenedUrl).to receive(:generate).with(destination, nil).and_return(shortened_url)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'short url was generated' do
|
12
|
+
let(:shortened_url) { instance_double('ShortenedUrl', unique_key: '12345') }
|
13
|
+
|
14
|
+
it "shortens the url" do
|
15
|
+
expect(helper.short_url(destination)).to eq "http://test.host/12345"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'short url could not be generated' do
|
20
|
+
let(:shortened_url) { nil }
|
6
21
|
|
7
|
-
|
8
|
-
|
9
|
-
|
22
|
+
it 'returns the original url' do
|
23
|
+
expect(helper.short_url(destination)).to eq destination
|
24
|
+
end
|
10
25
|
end
|
11
26
|
end
|
12
27
|
end
|
@@ -1,67 +1,99 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
-
describe Shortener::ShortenedUrl do
|
4
|
+
describe Shortener::ShortenedUrl, type: :model do
|
5
5
|
it { should belong_to :owner }
|
6
6
|
it { should validate_presence_of :url }
|
7
7
|
|
8
|
-
|
9
|
-
let(:short_url) { Shortener::ShortenedUrl.generate!(long_url, owner) }
|
10
|
-
it "should be shortened" do
|
11
|
-
short_url.should_not be_nil
|
12
|
-
short_url.url.should == expected_long_url
|
13
|
-
short_url.unique_key.length.should == 5
|
14
|
-
short_url.owner.should == owner
|
15
|
-
end
|
16
|
-
end
|
8
|
+
describe '#generate!' do
|
17
9
|
|
18
|
-
|
19
|
-
|
20
|
-
let(:expected_long_url) { long_url }
|
21
|
-
let(:owner) { nil }
|
22
|
-
it_should_behave_like "shortened url"
|
23
|
-
end
|
10
|
+
context 'shortened url record for requested url does not exist' do
|
11
|
+
let(:expected_url) { Faker::Internet.url }
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
13
|
+
shared_examples_for "shortened url" do
|
14
|
+
let(:short_url) { Shortener::ShortenedUrl.generate!(long_url, owner) }
|
15
|
+
it 'creates a shortened url record for the url' do
|
16
|
+
expect{short_url}.to change{Shortener::ShortenedUrl.count}.by(1)
|
17
|
+
expect(short_url.url).to eq expected_url
|
18
|
+
expect(short_url.unique_key.length).to eq 5
|
19
|
+
expect(short_url.owner).to eq owner
|
20
|
+
end
|
21
|
+
end
|
31
22
|
|
32
|
-
|
33
|
-
|
34
|
-
let(:expected_long_url) { long_url }
|
35
|
-
let(:owner) { nil }
|
36
|
-
it_should_behave_like "shortened url"
|
37
|
-
end
|
23
|
+
context 'userless url' do
|
24
|
+
let(:owner) { nil }
|
38
25
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
26
|
+
context 'shortened url ' do
|
27
|
+
it_should_behave_like "shortened url" do
|
28
|
+
let(:long_url) { expected_url }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'shortened url with partial URL' do
|
33
|
+
it_should_behave_like "shortened url" do
|
34
|
+
let(:long_url) { expected_url.gsub('http://', '') }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "shortened url with i18n path" do
|
39
|
+
it_should_behave_like "shortened url" do
|
40
|
+
let(:long_url) { "#{Faker::Internet.url}/%E6%97%A5%E6%9C%AC%E8%AA%9E" }
|
41
|
+
let(:expected_url) { long_url }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
context "shortened url with user" do
|
47
|
+
it_should_behave_like "shortened url" do
|
48
|
+
let(:owner) { User.create }
|
49
|
+
let(:long_url) { expected_url }
|
50
|
+
end
|
51
|
+
end
|
51
52
|
end
|
52
|
-
|
53
|
-
|
53
|
+
|
54
|
+
context "existing shortened URL" do
|
55
|
+
let(:url) { Faker::Internet.url }
|
56
|
+
let!(:existing_shortened_url) { Shortener::ShortenedUrl.generate!(url) }
|
57
|
+
|
58
|
+
context 'same url as existing' do
|
59
|
+
let(:protocol_free_url) { url.gsub('http://', '') }
|
60
|
+
|
61
|
+
it 'finds the shortened url from protocol free url' do
|
62
|
+
expect(Shortener::ShortenedUrl.generate!(protocol_free_url)).to eq existing_shortened_url
|
63
|
+
end
|
64
|
+
it "should look up exsiting URL" do
|
65
|
+
expect(Shortener::ShortenedUrl.generate!(url)).to eq existing_shortened_url
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'different url from existing' do
|
70
|
+
it "generates a new shortened url record for a different url" do
|
71
|
+
expect(Shortener::ShortenedUrl.generate!(Faker::Internet.url)).not_to eq existing_shortened_url
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "duplicate unique key" do
|
76
|
+
before do
|
77
|
+
expect_any_instance_of(Shortener::ShortenedUrl).to receive(:generate_unique_key).
|
78
|
+
and_return(existing_shortened_url.unique_key, 'ABCDEF')
|
79
|
+
Shortener::ShortenedUrl.where(unique_key: 'ABCDEF').delete_all
|
80
|
+
end
|
81
|
+
it 'should try until it finds a non-dup key' do
|
82
|
+
short_url = Shortener::ShortenedUrl.generate!(Faker::Internet.url)
|
83
|
+
expect(short_url).not_to be_nil
|
84
|
+
expect(short_url.unique_key).to eq "ABCDEF"
|
85
|
+
end
|
86
|
+
end
|
54
87
|
end
|
88
|
+
end
|
55
89
|
|
56
|
-
|
90
|
+
describe '#generate' do
|
91
|
+
context 'cannot generate a unique key' do
|
57
92
|
before do
|
58
|
-
Shortener::ShortenedUrl.
|
59
|
-
and_return(@existing.unique_key, "ABCDEF")
|
93
|
+
expect(Shortener::ShortenedUrl).to receive(:generate!).and_raise(ActiveRecord::RecordNotUnique.new(nil))
|
60
94
|
end
|
61
|
-
it
|
62
|
-
|
63
|
-
short_url.should_not be_nil
|
64
|
-
short_url.unique_key.should == "ABCDEF"
|
95
|
+
it 'returns nil' do
|
96
|
+
expect(Shortener::ShortenedUrl.generate(Faker::Internet.url)).to eq nil
|
65
97
|
end
|
66
98
|
end
|
67
99
|
end
|
@@ -5,7 +5,7 @@ require 'mail'
|
|
5
5
|
describe Shortener::ShortenUrlInterceptor do
|
6
6
|
|
7
7
|
def create_email(body)
|
8
|
-
Mail.new(:
|
8
|
+
Mail.new(from: 'test@mbln.jp', to: 'test@mbln.jp', body: body).tap do |m|
|
9
9
|
m.encoded
|
10
10
|
Shortener::ShortenUrlInterceptor.new.delivering_email(m)
|
11
11
|
end
|
@@ -17,27 +17,27 @@ describe Shortener::ShortenUrlInterceptor do
|
|
17
17
|
"Test with URL: %{url}. hu!",
|
18
18
|
"Test with URL: <a href='%{url}'>test</a>",
|
19
19
|
"Test with URL: <a href=\"%{url}\">test</a>" ]
|
20
|
-
|
20
|
+
|
21
21
|
shared_examples_for "shortens URL in text" do |url|
|
22
22
|
TEXTS.each do |raw_email_body_text|
|
23
|
-
email_body_text = raw_email_body_text % {:url
|
23
|
+
email_body_text = raw_email_body_text % { url: url }
|
24
24
|
it("shortens for #{email_body_text}") do
|
25
25
|
email = create_email(email_body_text)
|
26
26
|
short_url = Shortener::ShortenedUrl.find_by_url(url)
|
27
|
-
short_url.
|
28
|
-
email.body.
|
27
|
+
expect(short_url).not_to be_nil
|
28
|
+
expect(email.body).to eq (raw_email_body_text % { url: "http://mbln.jp/#{short_url.unique_key}" })
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
shared_examples_for "does not shorten URL" do |url|
|
34
34
|
TEXTS.each do |raw_email_body_text|
|
35
|
-
email_body_text = raw_email_body_text % {:url
|
35
|
+
email_body_text = raw_email_body_text % { url: url }
|
36
36
|
it("keeps URL for #{email_body_text}") do
|
37
37
|
email = create_email(email_body_text)
|
38
38
|
short_url = Shortener::ShortenedUrl.find_by_url(url)
|
39
|
-
short_url.
|
40
|
-
email.body.
|
39
|
+
expect(short_url).to be_nil
|
40
|
+
expect(email.body).to eq email_body_text
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -57,6 +57,6 @@ describe Shortener::ShortenUrlInterceptor do
|
|
57
57
|
"http://d1dqic1fklzs1z.cloudfront.net/assets/doorkeeper_group_normal-3a3292fd09e39a70084c247aef60cba9.gif" # asset URL
|
58
58
|
].each do |url|
|
59
59
|
it_should_behave_like "does not shorten URL", url
|
60
|
-
end
|
60
|
+
end
|
61
61
|
|
62
62
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shortener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James P. McGrath
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-09-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -45,14 +45,14 @@ dependencies:
|
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
48
|
+
version: 3.3.0
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
55
|
+
version: 3.3.0
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: shoulda-matchers
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +67,34 @@ dependencies:
|
|
67
67
|
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: faker
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: byebug
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
70
98
|
description: Shortener is a Rails Engine Gem that makes it easy to create and interpret
|
71
99
|
shortened URLs on your own domain from within your Rails application. Once installed
|
72
100
|
Shortener will generate, store URLS and "unshorten" shortened URLs for your applications
|
@@ -147,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
175
|
version: 1.3.6
|
148
176
|
requirements: []
|
149
177
|
rubyforge_project: shortener
|
150
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.4.5.1
|
151
179
|
signing_key:
|
152
180
|
specification_version: 4
|
153
181
|
summary: Shortener is a Rails Engine that makes it easy to create shortened URLs for
|