shortener 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b5132743f6f7bf1ccab83e28c3ae18f822b277a
4
- data.tar.gz: 58d20decd09055a4a76a21548e66010acac00da5
3
+ metadata.gz: 0f710d548cc2a095e643ed04c786691a723f1449
4
+ data.tar.gz: e3fc832851d5e4f72750883844cc6eaee97c5e65
5
5
  SHA512:
6
- metadata.gz: 1f307fff4f9bdb34387849e33c424c109606f1a0abd8c55b769c4b96da08dedbc1da3380748cb8b5ef2ff4c58603878a2c372ce9054a4052dd25d563c7619326
7
- data.tar.gz: 0c682ae7f3f3ef7fd99020e8ee31e69124f4f1d6bb825962c6eca853afa6db11f1c6027778f4a13f555cae91951977718022bfd3aa2156e12d907f68e78e131a
6
+ metadata.gz: e89866e4b81029b37adcadbe79e42cca296b57a60fb1c6fd4e50860258b2837d9c8250e2e4924f9d56f3026f1ac76b35b54a45ffdb87f43b72c55a44139c371d
7
+ data.tar.gz: 3b79ef1a1fbf5b9145431bc239f1ab7aac331d37188cb37516f13a92415b48bac1a6601abb7190526cf14b19c86816c44b1eb3d0c9eb6925081f987d2007d8bd
@@ -1,4 +1,4 @@
1
- {<img src="https://secure.travis-ci.org/jpmcgrath/shortener.png?branch=master" alt="Build Status" />}[http://travis-ci.org/jpmcgrath/shortener]
1
+ {<img src="https://secure.travis-ci.org/jpmcgrath/shortener.png?branch=master" alt="Build Status" />}[http://travis-ci.org/jpmcgrath/shortener] {<img src="https://codeclimate.com/github/jpmcgrath/shortener/badges/gpa.svg" />}[https://codeclimate.com/github/jpmcgrath/shortener]
2
2
 
3
3
  = Shortener
4
4
 
@@ -52,7 +52,6 @@ migration:
52
52
  * There has not been an attempt to remove ambiguous characters (i.e. 1 l and capital i, or 0 and O etc.) from the unique key generated for the link. This means people might copy the link incorrectly if copying the link by hand;
53
53
  * The system could pre-generate unique keys in advance, avoiding the database penalty when checking that a newly generated key is unique;
54
54
  * The system could store the shortened URL if the url is to be continually rendered;
55
- * Some implementations might want duplicate links to be generated each time a user request a shortened link.
56
55
 
57
56
  == Installation
58
57
 
@@ -102,7 +101,7 @@ To generate and display a shortened URL in your application use the helper metho
102
101
 
103
102
  Pass in subdomain, protocol and other options that the UrlHelper url_for accepts:
104
103
 
105
- short_url("http://example.com", url_options: { subdomain: 'foo', host: 'bar, protocol: 'https' } )
104
+ short_url("http://example.com", url_options: { subdomain: 'foo', host: 'bar', protocol: 'https' } )
106
105
 
107
106
  This will generate a shortened URL. store it to the db and return a string representing the shortened URL.
108
107
 
@@ -159,12 +158,30 @@ In rails you can put next line into config/initializers/shortener.rb
159
158
 
160
159
  Shortener.forbidden_keys.concat %w(terms promo)
161
160
 
162
- === Helper Parameters
161
+ === Ignoring Robots
162
+
163
+ By default Shortener will count all visits to a shortened url, including any crawler
164
+ robots like the Google Web Crawler, or Twitter's link unshortening bot. To ignore
165
+ these visits, Shortener makes use of the excellent voight_kampff gem to identify
166
+ web robots. This feature is disabled by default. To enable add the following to
167
+ your shortener configuration:
168
+
169
+ Shortener.ignore_robots = true
170
+
171
+ === URL Parameters
163
172
 
164
173
  Parameters are passed though from the shortened url, to the destination URL. If the destination
165
174
  URL has the same parameters as the destination URL, the parameters on the shortened url take
166
175
  precedence over those on the destination URL.
167
176
 
177
+ For example, if we have an orginal URL of:
178
+ > http://destination.com?test=yes&happy=defo (idenfified with token ABCDEF)
179
+ Which is shortened into:
180
+ > http://coolapp.io/s/ABCDEF?test=no&why=not
181
+ Then, the resulting URL will be:
182
+ >http://destination.com?test=no&happy=defo&why=not
183
+ Note how the test parameter takes the value given on the short URL.
184
+
168
185
  === Shorten URLs in generated emails
169
186
 
170
187
  You can register the included mail interceptor to shorten all links in the emails generated by your Rails app. For example, add to your mailer:
@@ -181,6 +198,26 @@ This will replace all long URLs in the emails generated by MyMailer with shorten
181
198
 
182
199
  The interceptor supports a few more arguments, see the implementation for details.
183
200
 
201
+ === Logging, stats and other tricks
202
+
203
+ If you want more things to happen when a user accesses one of your short urls, you can create your own `show` action as follows:
204
+
205
+ def show
206
+ token = ::Shortener::ShortenedUrl.extract_token(params[:id])
207
+ url = ::Shortener::ShortenedUrl.fetch_with_token(token: token, additional_params: params)
208
+ # do some logging, store some stats
209
+ redirect_to url[:url], status: :moved_permanently
210
+ end
211
+
212
+ === Fetch with Token
213
+ The `::Shortener::ShortenedUrl.fetch_with_token(token: token, additional_params: params)` does the following:
214
+ 1. finds the ShortenedUrl for the supplied token
215
+ 2. increments the use_count for the retrieved ShortenedURL
216
+ 3. combines the additional parameters with the URL in the retrieved ShortenedURL
217
+ 4. returns a hash of the format `{url: <the original url>, shortened_url: <the retrieved ShortenedURL>}
218
+
219
+ *note:* If no shortened URL is found, the url will be `default_redirect` or `/`
220
+
184
221
  == Origins
185
222
 
186
223
  For a bit of backstory to Shortener see this {blog post}[http://jamespmcgrath.com/a-simple-link-shortener-in-rails/].
@@ -189,7 +226,8 @@ For a bit of backstory to Shortener see this {blog post}[http://jamespmcgrath.co
189
226
 
190
227
  Shortener is used in a number of production systems, including, but not limited to:
191
228
 
192
- {Doorkeeper - An Event Management Tool}[http://www.doorkeeperhq.com/]
229
+ - {Doorkeeper - An Event Management Tool}[http://www.doorkeeperhq.com/]
230
+ - {1001tweets - Repost your tweets to get more clicks}[http://www.1001tweets.com/]
193
231
 
194
232
  If you are using Shortener in your project and would like to be added to this list, please get in touch!
195
233
 
@@ -1,41 +1,12 @@
1
+ require 'voight_kampff'
2
+
1
3
  class Shortener::ShortenedUrlsController < ActionController::Base
4
+ include Shortener
2
5
 
3
- # find the real link for the shortened link key and redirect
4
6
  def show
5
- # only use the leading valid characters
6
- token = /^([#{Shortener.key_chars.join}]*).*/.match(params[:id])[1]
7
-
8
- # pull the link out of the db
9
- sl = ::Shortener::ShortenedUrl.unexpired.where(unique_key: token).first
10
-
11
- if sl
12
- # don't want to wait for the increment to happen, make it snappy!
13
- # this is the place to enhance the metrics captured
14
- # for the system. You could log the request origin
15
- # browser type, ip address etc.
16
- Thread.new do
17
- sl.increment!(:use_count)
18
- ActiveRecord::Base.connection.close
19
- end
20
-
21
- params.except! *[:id, :action, :controller]
22
- url = sl.url
23
-
24
- if params.present?
25
- uri = URI.parse(sl.url)
26
- existing_params = Rack::Utils.parse_nested_query(uri.query)
27
- merged_params = existing_params.merge(params)
28
- uri.query = merged_params.to_query
29
- url = uri.to_s
30
- end
31
-
32
- # do a 301 redirect to the destination url
33
- redirect_to url, status: :moved_permanently
34
- else
35
- # if we don't find the shortened link, redirect to the root
36
- # make this configurable in future versions
37
- redirect_to Shortener.default_redirect
38
- end
7
+ token = ::Shortener::ShortenedUrl.extract_token(params[:id])
8
+ track = Shortener.ignore_robots.blank? || request.human?
9
+ url = ::Shortener::ShortenedUrl.fetch_with_token(token: token, additional_params: params, track: track)
10
+ redirect_to url[:url], status: :moved_permanently
39
11
  end
40
-
41
12
  end
@@ -10,7 +10,7 @@ module Shortener::ShortenerHelper
10
10
  )
11
11
 
12
12
  if short_url
13
- options = { controller: :"shortener/shortened_urls", action: :show, id: short_url.unique_key, only_path: false }.merge(url_options)
13
+ options = { controller: :"/shortener/shortened_urls", action: :show, id: short_url.unique_key, only_path: false }.merge(url_options)
14
14
  url_for(options)
15
15
  else
16
16
  url
@@ -10,6 +10,8 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
10
10
  # exclude records in which expiration time is set and expiration time is greater than current time
11
11
  scope :unexpired, -> { where(arel_table[:expires_at].eq(nil).or(arel_table[:expires_at].gt(::Time.current.to_s(:db)))) }
12
12
 
13
+ attr_accessor :custom_key
14
+
13
15
  # ensure the url starts with it protocol and is normalized
14
16
  def self.clean_url(url)
15
17
 
@@ -26,11 +28,11 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
26
28
  def self.generate!(destination_url, owner: nil, custom_key: nil, expires_at: nil, fresh: false)
27
29
  # if we get a shortened_url object with a different owner, generate
28
30
  # new one for the new owner. Otherwise return same object
29
- if destination_url.is_a? Shortener::ShortenedUrl
31
+ result = if destination_url.is_a? Shortener::ShortenedUrl
30
32
  if destination_url.owner == owner
31
- result = destination_url
33
+ destination_url
32
34
  else
33
- result = generate!(destination_url.url,
35
+ generate!(destination_url.url,
34
36
  owner: owner,
35
37
  custom_key: custom_key,
36
38
  expires_at: expires_at,
@@ -39,12 +41,8 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
39
41
  end
40
42
  else
41
43
  scope = owner ? owner.shortened_urls : self
42
-
43
- if fresh
44
- result = scope.where(url: clean_url(destination_url)).create(unique_key: custom_key, expires_at: expires_at)
45
- else
46
- result = scope.where(url: clean_url(destination_url)).first_or_create(unique_key: custom_key, expires_at: expires_at)
47
- end
44
+ creation_method = fresh ? 'create' : 'first_or_create'
45
+ scope.where(url: clean_url(destination_url)).send(creation_method, unique_key: custom_key, custom_key: custom_key, expires_at: expires_at)
48
46
  end
49
47
 
50
48
  result
@@ -60,14 +58,61 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
60
58
  end
61
59
  end
62
60
 
61
+ def self.extract_token(token_str)
62
+ # only use the leading valid characters
63
+ # escape to ensure custom charsets with protected chars do not fail
64
+ /^([#{Regexp.escape(Shortener.key_chars.join)}]*).*/.match(token_str)[1]
65
+ end
66
+
67
+ def self.fetch_with_token(token: nil, additional_params: {}, track: true)
68
+ shortened_url = ::Shortener::ShortenedUrl.unexpired.where(unique_key: token).first
69
+
70
+ url = if shortened_url
71
+ shortened_url.increment_usage_count if track
72
+ merge_params_to_url(url: shortened_url.url, params: additional_params)
73
+ else
74
+ Shortener.default_redirect || '/'
75
+ end
76
+
77
+ { url: url, shortened_url: shortened_url }
78
+ end
79
+
80
+ def self.merge_params_to_url(url: nil, params: {})
81
+ params.try(:except!, *[:id, :action, :controller])
82
+
83
+ if params.present?
84
+ uri = URI.parse(url)
85
+ existing_params = Rack::Utils.parse_nested_query(uri.query)
86
+ uri.query = existing_params.symbolize_keys.merge(params).to_query
87
+ url = uri.to_s
88
+ end
89
+
90
+ url
91
+ end
92
+
93
+ def increment_usage_count
94
+ Thread.new do
95
+ ActiveRecord::Base.connection_pool.with_connection do |conn|
96
+ increment!(:use_count)
97
+ end
98
+ end
99
+ end
100
+
101
+ def to_param
102
+ unique_key
103
+ end
104
+
63
105
  private
64
106
 
65
107
  # the create method changed in rails 4...
66
108
  CREATE_METHOD_NAME =
67
- if Rails::VERSION::MAJOR >= 4
109
+ if Rails::VERSION::MAJOR >= 5
110
+ "_create_record"
111
+ elsif Rails::VERSION::MAJOR == 4
68
112
  # And again in 4.0.6/4.1.2
69
- if ((Rails::VERSION::MINOR == 0) && (Rails::VERSION::TINY < 6)) ||
70
- ((Rails::VERSION::MINOR == 1) && (Rails::VERSION::TINY < 2))
113
+ if Rails::VERSION::MAJOR == 4 && (
114
+ ((Rails::VERSION::MINOR == 0) && (Rails::VERSION::TINY < 6)) ||
115
+ ((Rails::VERSION::MINOR == 1) && (Rails::VERSION::TINY < 2)))
71
116
  "create_record"
72
117
  else
73
118
  "_create_record"
@@ -81,9 +126,11 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
81
126
  define_method CREATE_METHOD_NAME do
82
127
  count = 0
83
128
  begin
84
- self.unique_key = generate_unique_key
129
+ self.unique_key = custom_key || generate_unique_key
85
130
  super()
86
131
  rescue ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid => err
132
+ logger.info("Failed to generate ShortenedUrl with unique_key: #{unique_key}")
133
+ self.unique_key = nil
87
134
  if (count +=1) < 5
88
135
  logger.info("retrying with different unique key")
89
136
  retry
@@ -28,6 +28,11 @@ module Shortener
28
28
  mattr_accessor :forbidden_keys
29
29
  self.forbidden_keys = []
30
30
 
31
+ # ignore_robots - set to true to not count visits by identified webcrawlers
32
+ mattr_accessor :ignore_robots
33
+ self.ignore_robots = false
34
+
35
+
31
36
  def self.key_chars
32
37
  CHARSETS[charset]
33
38
  end
@@ -1,3 +1,3 @@
1
1
  module Shortener
2
- VERSION = '0.5.5'
2
+ VERSION = '0.5.6'
3
3
  end
@@ -15,6 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.rubyforge_project = "shortener"
16
16
  s.required_rubygems_version = "> 1.3.6"
17
17
  s.add_dependency "rails", ">= 3.0.7"
18
+ s.add_dependency "voight_kampff", '~>1.0.2'
18
19
  s.add_development_dependency "sqlite3"
19
20
  s.add_development_dependency "rspec-rails", '~> 3.3.0'
20
21
  s.add_development_dependency "shoulda-matchers", '~> 3'
@@ -18,6 +18,26 @@ describe Shortener::ShortenedUrlsController, type: :controller do
18
18
  it 'redirects to the destination url' do
19
19
  expect(response).to redirect_to destination
20
20
  end
21
+
22
+ context "when request is not from an human" do
23
+ before do
24
+ allow_any_instance_of(Rack::Request).to receive(:human?).and_return(false)
25
+ end
26
+ context 'Shortener.ignore_robots == true' do
27
+ it "calls fetch with token with track argument as false" do
28
+ Shortener.ignore_robots = true
29
+ expect(Shortener::ShortenedUrl).to receive(:fetch_with_token).with(hash_including(track: false)).and_call_original
30
+ get :show, { id: key }
31
+ end
32
+ end
33
+ context 'Shortener.ignore_robots == false (default)' do
34
+ it "calls fetch with token with track argument as true" do
35
+ Shortener.ignore_robots = false
36
+ expect(Shortener::ShortenedUrl).to receive(:fetch_with_token).with(hash_including(track: true)).and_call_original
37
+ get :show, { id: key }
38
+ end
39
+ end
40
+ end
21
41
  end
22
42
 
23
43
  context 'real key with trailing characters' do
@@ -154,4 +154,114 @@ describe Shortener::ShortenedUrl, type: :model do
154
154
  expect(unexpired_scope).not_to include(expired_url)
155
155
  end
156
156
  end
157
+
158
+ describe '#increment_usage_count' do
159
+ let(:url) { 'https://example.com'}
160
+ let(:short_url) { Shortener::ShortenedUrl.generate!(url) }
161
+ it 'increments the use_count on the shortenedLink' do
162
+ original_count = short_url.use_count
163
+ short_url.increment_usage_count
164
+ sleep 0.001
165
+ expect(short_url.use_count).to eq (original_count + 1)
166
+ end
167
+ end
168
+
169
+ describe '#merge_params_to_url' do
170
+ context 'without params on original url' do
171
+ let(:url) { 'https://example.com'}
172
+
173
+ context 'no additional params' do
174
+ let(:params) { nil }
175
+
176
+ it 'returns the original url' do
177
+ expect(Shortener::ShortenedUrl.merge_params_to_url(url: url, params: params)).to eq 'https://example.com'
178
+ end
179
+ end
180
+
181
+ context 'additional params' do
182
+ let(:params) { {foo: 'bar', hello: 'world' } }
183
+
184
+ it 'merges the params to create a new url' do
185
+ expect(Shortener::ShortenedUrl.merge_params_to_url(url: url, params: params)).to eq 'https://example.com?foo=bar&hello=world'
186
+ end
187
+ end
188
+ end
189
+
190
+ context 'with params on original url' do
191
+ let(:url) { 'http://example.com/pathname?different=yes&foo=test'}
192
+
193
+ context 'no additional params' do
194
+ let(:params) { nil }
195
+
196
+ it 'returns the original url' do
197
+ expect(Shortener::ShortenedUrl.merge_params_to_url(url: url, params: params)).to eq 'http://example.com/pathname?different=yes&foo=test'
198
+ end
199
+ end
200
+
201
+ context 'additional params' do
202
+ let(:params) { {foo: 'manchoo', hello: 'world' } }
203
+
204
+ it 'merges the params to create a new url with the new params taking preceedence' do
205
+ expect(Shortener::ShortenedUrl.merge_params_to_url(url: url, params: params)).to eq 'http://example.com/pathname?different=yes&foo=manchoo&hello=world'
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ describe '#fetch_with_token' do
212
+ shared_examples_for 'invalid token supplied' do
213
+ context 'default_path set' do
214
+ it 'returns the default_redirect url, but no shortened url' do
215
+ Shortener.default_redirect = "/default_path"
216
+ result = Shortener::ShortenedUrl.fetch_with_token(token: nil)
217
+ expect(result[:url]).to eq '/default_path'
218
+ expect(result[:shortened_url]).to eq nil
219
+ end
220
+ end
221
+ context 'no default_path set' do
222
+ it 'returns the root path, but no shortened url' do
223
+ Shortener.default_redirect = nil
224
+ result = Shortener::ShortenedUrl.fetch_with_token(token: nil)
225
+ expect(result[:url]).to eq '/'
226
+ expect(result[:shortened_url]).to eq nil
227
+ end
228
+ end
229
+ end
230
+
231
+ context 'invalid token' do
232
+ it_should_behave_like 'invalid token supplied' do
233
+ let(:token) { 'invalid_token'}
234
+ end
235
+ end
236
+
237
+ context 'valid token' do
238
+ let(:url) { Faker::Internet.url }
239
+
240
+ context 'non expired short url' do
241
+ let(:short_url) { Shortener::ShortenedUrl.generate!(url) }
242
+ it 'returns both the url and the shortened url' do
243
+ result = Shortener::ShortenedUrl.fetch_with_token(token: short_url.unique_key)
244
+ expect(result[:url]).to eq url
245
+ expect(result[:shortened_url]).to eq short_url
246
+ end
247
+ it "increments use count" do
248
+ expect_any_instance_of(Shortener::ShortenedUrl).to receive(:increment_usage_count)
249
+ Shortener::ShortenedUrl.fetch_with_token(token: short_url.unique_key)
250
+ end
251
+ context "with track set to false" do
252
+ it "does not increment use count" do
253
+ expect_any_instance_of(Shortener::ShortenedUrl).not_to receive(:increment_usage_count)
254
+ Shortener::ShortenedUrl.fetch_with_token(token: short_url.unique_key, track: false)
255
+ end
256
+ end
257
+ end
258
+
259
+ context 'expired short url' do
260
+ let(:short_url) { Shortener::ShortenedUrl.generate!(url, expires_at: 1.second.ago) }
261
+ it_should_behave_like 'invalid token supplied' do
262
+ let(:token) { short_url.unique_key }
263
+ end
264
+ end
265
+ end
266
+ end
157
267
  end
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.5.5
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - James P. McGrath
@@ -9,90 +9,104 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-08 00:00:00.000000000 Z
12
+ date: 2016-11-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 3.0.7
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 3.0.7
28
+ - !ruby/object:Gem::Dependency
29
+ name: voight_kampff
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.2
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 1.0.2
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: sqlite3
30
44
  requirement: !ruby/object:Gem::Requirement
31
45
  requirements:
32
- - - '>='
46
+ - - ">="
33
47
  - !ruby/object:Gem::Version
34
48
  version: '0'
35
49
  type: :development
36
50
  prerelease: false
37
51
  version_requirements: !ruby/object:Gem::Requirement
38
52
  requirements:
39
- - - '>='
53
+ - - ">="
40
54
  - !ruby/object:Gem::Version
41
55
  version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: rspec-rails
44
58
  requirement: !ruby/object:Gem::Requirement
45
59
  requirements:
46
- - - ~>
60
+ - - "~>"
47
61
  - !ruby/object:Gem::Version
48
62
  version: 3.3.0
49
63
  type: :development
50
64
  prerelease: false
51
65
  version_requirements: !ruby/object:Gem::Requirement
52
66
  requirements:
53
- - - ~>
67
+ - - "~>"
54
68
  - !ruby/object:Gem::Version
55
69
  version: 3.3.0
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: shoulda-matchers
58
72
  requirement: !ruby/object:Gem::Requirement
59
73
  requirements:
60
- - - ~>
74
+ - - "~>"
61
75
  - !ruby/object:Gem::Version
62
76
  version: '3'
63
77
  type: :development
64
78
  prerelease: false
65
79
  version_requirements: !ruby/object:Gem::Requirement
66
80
  requirements:
67
- - - ~>
81
+ - - "~>"
68
82
  - !ruby/object:Gem::Version
69
83
  version: '3'
70
84
  - !ruby/object:Gem::Dependency
71
85
  name: faker
72
86
  requirement: !ruby/object:Gem::Requirement
73
87
  requirements:
74
- - - '>='
88
+ - - ">="
75
89
  - !ruby/object:Gem::Version
76
90
  version: '0'
77
91
  type: :development
78
92
  prerelease: false
79
93
  version_requirements: !ruby/object:Gem::Requirement
80
94
  requirements:
81
- - - '>='
95
+ - - ">="
82
96
  - !ruby/object:Gem::Version
83
97
  version: '0'
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: byebug
86
100
  requirement: !ruby/object:Gem::Requirement
87
101
  requirements:
88
- - - '>='
102
+ - - ">="
89
103
  - !ruby/object:Gem::Version
90
104
  version: '0'
91
105
  type: :development
92
106
  prerelease: false
93
107
  version_requirements: !ruby/object:Gem::Requirement
94
108
  requirements:
95
- - - '>='
109
+ - - ">="
96
110
  - !ruby/object:Gem::Version
97
111
  version: '0'
98
112
  description: Shortener is a Rails Engine Gem that makes it easy to create and interpret
@@ -106,8 +120,8 @@ executables: []
106
120
  extensions: []
107
121
  extra_rdoc_files: []
108
122
  files:
109
- - .gitignore
110
- - .travis.yml
123
+ - ".gitignore"
124
+ - ".travis.yml"
111
125
  - Gemfile
112
126
  - MIT-LICENSE
113
127
  - README.rdoc
@@ -167,17 +181,17 @@ require_paths:
167
181
  - lib
168
182
  required_ruby_version: !ruby/object:Gem::Requirement
169
183
  requirements:
170
- - - '>='
184
+ - - ">="
171
185
  - !ruby/object:Gem::Version
172
186
  version: '0'
173
187
  required_rubygems_version: !ruby/object:Gem::Requirement
174
188
  requirements:
175
- - - '>'
189
+ - - ">"
176
190
  - !ruby/object:Gem::Version
177
191
  version: 1.3.6
178
192
  requirements: []
179
193
  rubyforge_project: shortener
180
- rubygems_version: 2.0.2
194
+ rubygems_version: 2.5.1
181
195
  signing_key:
182
196
  specification_version: 4
183
197
  summary: Shortener is a Rails Engine that makes it easy to create shortened URLs for