guillotine 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,70 +1,68 @@
1
1
  require 'mongo'
2
2
 
3
3
  module Guillotine
4
- module Adapters
5
- class MongoAdapter < Adapter
6
- def initialize(collection)
7
- @collection = collection
8
- @collection.ensure_index([['url', Mongo::ASCENDING]])
4
+ class MongoAdapter < Adapter
5
+ def initialize(collection)
6
+ @collection = collection
7
+ @collection.ensure_index([['url', Mongo::ASCENDING]])
9
8
 
10
- # \m/
11
- @transformers = {
12
- :url => lambda { |doc| doc['url'] },
13
- :code => lambda { |doc| doc['_id'] }
14
- }
15
- end
16
-
17
- # Public: Stores the shortened version of a URL.
18
- #
19
- # url - The String URL to shorten and store.
20
- # code - Optional String code for the URL.
21
- #
22
- # Returns the unique String code for the URL. If the URL is added
23
- # multiple times, this should return the same code.
24
- def add(url, code = nil)
25
- code_for(url) || insert(url, code || shorten(url))
26
- end
9
+ # \m/
10
+ @transformers = {
11
+ :url => lambda { |doc| doc['url'] },
12
+ :code => lambda { |doc| doc['_id'] }
13
+ }
14
+ end
27
15
 
28
-
29
- # Public: Retrieves a URL from the code.
30
- #
31
- # code - The String code to lookup the URL.
32
- #
33
- # Returns the String URL, or nil if none is found.
34
- def find(code)
35
- select :url, :_id => code
36
- end
16
+ # Public: Stores the shortened version of a URL.
17
+ #
18
+ # url - The String URL to shorten and store.
19
+ # code - Optional String code for the URL.
20
+ #
21
+ # Returns the unique String code for the URL. If the URL is added
22
+ # multiple times, this should return the same code.
23
+ def add(url, code = nil)
24
+ code_for(url) || insert(url, code || shorten(url))
25
+ end
37
26
 
38
- # Public: Retrieves the code for a given URL.
39
- #
40
- # url - The String URL to lookup.
41
- #
42
- # Returns the String code, or nil if none is found.
43
- def code_for(url)
44
- select :code, :url => url
45
- end
46
27
 
47
- # Public: Removes the assigned short code for a URL.
48
- #
49
- # url - The String URL to remove.
50
- #
51
- # Returns nothing.
52
- def clear(url)
53
- @collection.remove(:url => url)
54
- end
28
+ # Public: Retrieves a URL from the code.
29
+ #
30
+ # code - The String code to lookup the URL.
31
+ #
32
+ # Returns the String URL, or nil if none is found.
33
+ def find(code)
34
+ select :url, :_id => code
35
+ end
55
36
 
56
- def select(field, query)
57
- @collection.find_one(query, {:transformer => @transformers[field]})
58
- end
59
-
60
- private
61
- def insert(url, code)
62
- if existing_url = find(code)
63
- raise DuplicateCodeError.new(existing_url, url, code) if url != existing_url
64
- end
65
- @collection.insert(:_id => code, :url => url)
66
- code
37
+ # Public: Retrieves the code for a given URL.
38
+ #
39
+ # url - The String URL to lookup.
40
+ #
41
+ # Returns the String code, or nil if none is found.
42
+ def code_for(url)
43
+ select :code, :url => url
44
+ end
45
+
46
+ # Public: Removes the assigned short code for a URL.
47
+ #
48
+ # url - The String URL to remove.
49
+ #
50
+ # Returns nothing.
51
+ def clear(url)
52
+ @collection.remove(:url => url)
53
+ end
54
+
55
+ def select(field, query)
56
+ @collection.find_one(query, {:transformer => @transformers[field]})
57
+ end
58
+
59
+ private
60
+ def insert(url, code)
61
+ if existing_url = find(code)
62
+ raise DuplicateCodeError.new(existing_url, url, code) if url != existing_url
67
63
  end
64
+ @collection.insert(:_id => code, :url => url)
65
+ code
68
66
  end
69
67
  end
70
68
  end
@@ -1,63 +1,69 @@
1
1
  module Guillotine
2
- module Adapters
3
- class RedisAdapter < Adapter
4
- # Public: Initialise the adapter with a Redis instance.
5
- #
6
- # redis - A Redis instance to persist urls and codes to.
7
- def initialize(redis)
8
- @redis = redis
9
- end
2
+ class RedisAdapter < Adapter
3
+ # Public: Initialise the adapter with a Redis instance.
4
+ #
5
+ # redis - A Redis instance to persist urls and codes to.
6
+ def initialize(redis)
7
+ @redis = redis
8
+ end
10
9
 
11
- # Public: Stores the shortened version of a URL.
12
- #
13
- # url - The String URL to shorten and store.
14
- # code - Optional String code for the URL.
15
- #
16
- # Returns the unique String code for the URL. If the URL is added
17
- # multiple times, this should return the same code.
18
- def add(url, code = nil)
19
- if existing_code = @redis.get("guillotine:urls:#{url}")
20
- existing_code
21
- else
22
- code ||= shorten(url)
23
- if existing_url = @redis.get("guillotine:hash:#{code}")
24
- raise DuplicateCodeError.new(existing_url, url, code) if url != existing_url
25
- end
26
- @redis.set "guillotine:hash:#{code}", url
27
- @redis.set "guillotine:urls:#{url}", code
28
- code
10
+ # Public: Stores the shortened version of a URL.
11
+ #
12
+ # url - The String URL to shorten and store.
13
+ # code - Optional String code for the URL.
14
+ #
15
+ # Returns the unique String code for the URL. If the URL is added
16
+ # multiple times, this should return the same code.
17
+ def add(url, code = nil)
18
+ if existing_code = @redis.get(url_key(url))
19
+ existing_code
20
+ else
21
+ code ||= shorten(url)
22
+ if existing_url = @redis.get(code_key(code))
23
+ raise DuplicateCodeError.new(existing_url, url, code) if url != existing_url
29
24
  end
25
+ @redis.set code_key(code), url
26
+ @redis.set url_key(url), code
27
+ code
30
28
  end
29
+ end
31
30
 
32
- # Public: Retrieves a URL from the code.
33
- #
34
- # code - The String code to lookup the URL.
35
- #
36
- # Returns the String URL, or nil if none is found.
37
- def find(code)
38
- @redis.get "guillotine:hash:#{code}"
39
- end
31
+ # Public: Retrieves a URL from the code.
32
+ #
33
+ # code - The String code to lookup the URL.
34
+ #
35
+ # Returns the String URL, or nil if none is found.
36
+ def find(code)
37
+ @redis.get code_key(code)
38
+ end
40
39
 
41
- # Public: Retrieves the code for a given URL.
42
- #
43
- # url - The String URL to lookup.
44
- #
45
- # Returns the String code, or nil if none is found.
46
- def code_for(url)
47
- @redis.get "guillotine:urls:#{url}"
48
- end
40
+ # Public: Retrieves the code for a given URL.
41
+ #
42
+ # url - The String URL to lookup.
43
+ #
44
+ # Returns the String code, or nil if none is found.
45
+ def code_for(url)
46
+ @redis.get url_key(url)
47
+ end
49
48
 
50
- # Public: Removes the assigned short code for a URL.
51
- #
52
- # url - The String URL to remove.
53
- #
54
- # Returns nothing.
55
- def clear(url)
56
- if code = @redis.get("guillotine:urls:#{url}")
57
- @redis.del "guillotine:urls:#{url}"
58
- @redis.del "guillotine:hash:#{code}"
59
- end
49
+ # Public: Removes the assigned short code for a URL.
50
+ #
51
+ # url - The String URL to remove.
52
+ #
53
+ # Returns nothing.
54
+ def clear(url)
55
+ if code = @redis.get(url_key(url))
56
+ @redis.del url_key(url)
57
+ @redis.del code_key(code)
60
58
  end
61
59
  end
60
+
61
+ def code_key(code)
62
+ "guillotine:hash:#{code}"
63
+ end
64
+
65
+ def url_key(url)
66
+ "guillotine:urls:#{url}"
67
+ end
62
68
  end
63
69
  end
@@ -1,134 +1,132 @@
1
1
  require 'digest/sha1'
2
2
 
3
3
  module Guillotine
4
- module Adapters
5
- # Stores shortened URLs in Riak. Totally scales.
6
- class RiakAdapter < Adapter
7
- PLAIN = 'text/plain'.freeze
8
- attr_reader :code_bucket, :url_bucket
4
+ # Stores shortened URLs in Riak. Totally scales.
5
+ class RiakAdapter < Adapter
6
+ PLAIN = 'text/plain'.freeze
7
+ attr_reader :code_bucket, :url_bucket
9
8
 
10
- # Initializes the adapter.
11
- #
12
- # code_bucket - The Riak::Bucket for all code keys.
13
- # url_bucket - The Riak::Bucket for all url keys. If this is not
14
- # given, the code bucket is used for all keys.
15
- def initialize(code_bucket, url_bucket = nil)
16
- @code_bucket = code_bucket
17
- @url_bucket = url_bucket || @code_bucket
9
+ # Initializes the adapter.
10
+ #
11
+ # code_bucket - The Riak::Bucket for all code keys.
12
+ # url_bucket - The Riak::Bucket for all url keys. If this is not
13
+ # given, the code bucket is used for all keys.
14
+ def initialize(code_bucket, url_bucket = nil)
15
+ @code_bucket = code_bucket
16
+ @url_bucket = url_bucket || @code_bucket
17
+ end
18
+
19
+ # Public: Stores the shortened version of a URL.
20
+ #
21
+ # url - The String URL to shorten and store.
22
+ # code - Optional String code for the URL.
23
+ #
24
+ # Returns the unique String code for the URL. If the URL is added
25
+ # multiple times, this should return the same code.
26
+ def add(url, code = nil)
27
+ sha = url_key url
28
+ url_obj = @url_bucket.get_or_new sha, :r => 1
29
+ if url_obj.raw_data
30
+ fix_url_object(url_obj)
31
+ code = url_obj.data
18
32
  end
19
33
 
20
- # Public: Stores the shortened version of a URL.
21
- #
22
- # url - The String URL to shorten and store.
23
- # code - Optional String code for the URL.
24
- #
25
- # Returns the unique String code for the URL. If the URL is added
26
- # multiple times, this should return the same code.
27
- def add(url, code = nil)
28
- sha = url_key url
29
- url_obj = @url_bucket.get_or_new sha, :r => 1
30
- if url_obj.raw_data
31
- fix_url_object(url_obj)
32
- code = url_obj.data
33
- end
34
+ code ||= shorten url
35
+ code_obj = @code_bucket.get_or_new code
36
+ code_obj.content_type = url_obj.content_type = PLAIN
34
37
 
35
- code ||= shorten url
36
- code_obj = @code_bucket.get_or_new code
37
- code_obj.content_type = url_obj.content_type = PLAIN
38
+ if existing_url = code_obj.data # key exists
39
+ raise DuplicateCodeError.new(existing_url, url, code) if url_key(existing_url) != sha
40
+ end
38
41
 
39
- if existing_url = code_obj.data # key exists
40
- raise DuplicateCodeError.new(existing_url, url, code) if url_key(existing_url) != sha
41
- end
42
+ if !url_obj.data # unsaved
43
+ url_obj.data = code
44
+ url_obj.store
45
+ end
42
46
 
43
- if !url_obj.data # unsaved
44
- url_obj.data = code
45
- url_obj.store
46
- end
47
+ code_obj.data = url
48
+ code_obj.store
49
+ code
50
+ end
47
51
 
48
- code_obj.data = url
49
- code_obj.store
50
- code
52
+ # Public: Retrieves a URL from the code.
53
+ #
54
+ # code - The String code to lookup the URL.
55
+ #
56
+ # Returns the String URL.
57
+ def find(code)
58
+ if obj = url_object(code)
59
+ obj.data
51
60
  end
61
+ end
52
62
 
53
- # Public: Retrieves a URL from the code.
54
- #
55
- # code - The String code to lookup the URL.
56
- #
57
- # Returns the String URL.
58
- def find(code)
59
- if obj = url_object(code)
60
- obj.data
61
- end
63
+ # Public: Retrieves the code for a given URL.
64
+ #
65
+ # url - The String URL to lookup.
66
+ #
67
+ # Returns the String code, or nil if none is found.
68
+ def code_for(url)
69
+ if obj = code_object(url)
70
+ obj.data
62
71
  end
72
+ end
63
73
 
64
- # Public: Retrieves the code for a given URL.
65
- #
66
- # url - The String URL to lookup.
67
- #
68
- # Returns the String code, or nil if none is found.
69
- def code_for(url)
70
- if obj = code_object(url)
71
- obj.data
72
- end
74
+ # Public: Removes the assigned short code for a URL.
75
+ #
76
+ # url - The String URL to remove.
77
+ #
78
+ # Returns nothing.
79
+ def clear(url)
80
+ if code_obj = code_object(url)
81
+ @url_bucket.delete code_obj.key
82
+ @code_bucket.delete code_obj.data
73
83
  end
84
+ end
74
85
 
75
- # Public: Removes the assigned short code for a URL.
76
- #
77
- # url - The String URL to remove.
78
- #
79
- # Returns nothing.
80
- def clear(url)
81
- if code_obj = code_object(url)
82
- @url_bucket.delete code_obj.key
83
- @code_bucket.delete code_obj.data
84
- end
85
- end
86
+ # Retrieves a URL riak value from the code.
87
+ #
88
+ # code - The String code to lookup the URL.
89
+ #
90
+ # Returns a Riak::RObject, or nil if none is found.
91
+ def url_object(code)
92
+ @code_bucket.get(code, :r => 1)
93
+ rescue Riak::FailedRequest => err
94
+ raise unless err.not_found?
95
+ end
86
96
 
87
- # Retrieves a URL riak value from the code.
88
- #
89
- # code - The String code to lookup the URL.
90
- #
91
- # Returns a Riak::RObject, or nil if none is found.
92
- def url_object(code)
93
- @code_bucket.get(code, :r => 1)
94
- rescue Riak::FailedRequest => err
95
- raise unless err.not_found?
97
+ # Retrieves the code riak value for a given URL.
98
+ #
99
+ # url - The String URL to lookup.
100
+ #
101
+ # Returns a Riak::RObject, or nil if none is found.
102
+ def code_object(url)
103
+ sha = url_key url
104
+ if o = @url_bucket.get(sha, :r => 1)
105
+ fix_url_object(o)
96
106
  end
107
+ rescue Riak::FailedRequest => err
108
+ raise unless err.not_found?
109
+ end
97
110
 
98
- # Retrieves the code riak value for a given URL.
99
- #
100
- # url - The String URL to lookup.
101
- #
102
- # Returns a Riak::RObject, or nil if none is found.
103
- def code_object(url)
104
- sha = url_key url
105
- if o = @url_bucket.get(sha, :r => 1)
106
- fix_url_object(o)
107
- end
108
- rescue Riak::FailedRequest => err
109
- raise unless err.not_found?
111
+ # Fixes a bug in Guillotine 1.0.2 where the content type on url objects
112
+ # was not being set. The ruby Riak::Client defaults to JSON, so
113
+ # strings were being saved as "somecode", which is unparseable by JSON.
114
+ def fix_url_object(obj, data = nil)
115
+ if data
116
+ obj.content_type = PLAIN
117
+ obj.data = data
118
+ obj.store
119
+ return obj
110
120
  end
111
-
112
- # Fixes a bug in Guillotine 1.0.2 where the content type on url objects
113
- # was not being set. The ruby Riak::Client defaults to JSON, so
114
- # strings were being saved as "somecode", which is unparseable by JSON.
115
- def fix_url_object(obj, data = nil)
116
- if data
117
- obj.content_type = PLAIN
118
- obj.data = data
119
- obj.store
120
- return obj
121
- end
122
- case obj.content_type
123
- when /json/ then fix_url_object(obj, JSON.parse(%({"data":#{obj.raw_data}}))['data'])
124
- when PLAIN then obj
125
- else fix_url_object(obj, obj.data) # old values had the right data but the content type was application/x-www-form-urlencoded
126
- end
121
+ case obj.content_type
122
+ when /json/ then fix_url_object(obj, JSON.parse(%({"data":#{obj.raw_data}}))['data'])
123
+ when PLAIN then obj
124
+ else fix_url_object(obj, obj.data) # old values had the right data but the content type was application/x-www-form-urlencoded
127
125
  end
126
+ end
128
127
 
129
- def url_key(url)
130
- Digest::SHA1.hexdigest url.downcase
131
- end
128
+ def url_key(url)
129
+ Digest::SHA1.hexdigest url.downcase
132
130
  end
133
131
  end
134
132
  end