guillotine 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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