chuyeow-longurl 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ doc
3
+ pkg
4
+ rdoc
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009, Fabien Jakimowicz <fabien@jakimowicz.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,13 @@
1
+ bin/longurl
2
+ ChangeLog
3
+ lib/longurl/constants.rb
4
+ lib/longurl/direct.rb
5
+ lib/longurl/exceptions.rb
6
+ lib/longurl/service.rb
7
+ lib/longurl.rb
8
+ LICENSE
9
+ longurl.gemspec
10
+ Manifest
11
+ Rakefile
12
+ README
13
+ TODO
@@ -0,0 +1,76 @@
1
+ = LongURL
2
+
3
+ == DESCRIPTION
4
+ LongURL expands short urls (tinyurl, is.gd, ...) to original ones, using on LongURL.org, internal resolution or direct resolution
5
+ First, expand will try to expand url using longurl.org service.
6
+ Then, it will try to direct follow redirections on the given url and returns final one.
7
+
8
+ == SYNOPSIS
9
+ === Options
10
+ * <tt>:cache</tt>: cache object to use, must implement [] and []= functions.
11
+ * <tt>:supported_services_only</tt>: If true, only attempts to expand URLs that are listed as supported by
12
+ LongURL.org's API. Defaults to false.
13
+
14
+ === Types
15
+ <tt>url</tt> is expected to be a String and returns a String with the url.
16
+
17
+
18
+ === Examples
19
+ # simple expands
20
+ LongURL.expand("http://tinyurl.com/1c2") # => "http://www.google.com"
21
+ LongURL.expand("http://tinyurl.com/blnhsg") # => "http://www.google.com/search?q=number+of+horns+on+a+unicorn&ie=UTF-8"
22
+ LongURL.expand("http://is.gd/iUKg") # => "http://fabien.jakimowicz.com"
23
+
24
+ # not expandable urls, without any http call
25
+ LongURL.expand("http://www.linuxfr.org") # => "http://www.linuxfr.org"
26
+
27
+ # Use MemCache
28
+ LongURL.expand("http://is.gd/iUKg", :cache => MemCache.new("localhost:11211", :namespace => "LongURL"))
29
+ # => "http://fabien.jakimowicz.com"
30
+
31
+ # Expander class
32
+ expander = LongURL::Expander.new
33
+ expander.expand("http://tinyurl.com/1c2") # => "http://www.google.com"
34
+ # not expandable urls, direct resolution only
35
+ expander.direct_resolution("http://www.linuxfr.org") # => "http://www.linuxfr.org/pub"
36
+ # not expandable urls, calling longurl.org only
37
+ expander.expand_with_service_only("http://www.linuxfr.org") # => "http://www.linuxfr.org/pub"
38
+ # ... with MemCache
39
+ expander = LongURL::Expander.new(:cache => MemCache.new("localhost:11211", :namespace => "LongURL"))
40
+ expander.expand("http://tinyurl.com/1c2") # => "http://www.google.com"
41
+
42
+ === Exceptions
43
+ * LongURL::InvalidURL : will occurs if given url is nil, empty or invalid
44
+ * LongURL::NetworkError : a network (timeout, host could be reached, ...) error occurs
45
+ * LongURL::UnknownError : an unknown error occurs
46
+
47
+ == REQUIREMENTS
48
+
49
+ * json gem
50
+
51
+ == INSTALL
52
+ gem install longurl
53
+
54
+ == LICENSE
55
+
56
+ (The MIT License)
57
+
58
+ Copyright (c) 2009, Fabien Jakimowicz <fabien@jakimowicz.com>
59
+
60
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
61
+ this software and associated documentation files (the "Software"), to deal in
62
+ the Software without restriction, including without limitation the rights to
63
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
64
+ of the Software, and to permit persons to whom the Software is furnished to do
65
+ so, subject to the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be included in all
68
+ copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
76
+ SOFTWARE.
@@ -0,0 +1,70 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "longurl"
7
+ s.summary = %q{LongURL expands shorten urls (tinyurl, is.gd, ...)}
8
+ s.homepage = "http://longurl.rubyforge.org"
9
+ s.description = %q{LongURL expands short urls (tinyurl, is.gd, ...) to original ones, using on LongURL.org, internal resolution or direct resolution}
10
+ s.authors = ["Fabien Jakimowicz"]
11
+ s.email = "fabien@jakimowicz.com"
12
+ s.rubyforge_project = 'longurl'
13
+
14
+ s.add_dependency 'json'
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
19
+
20
+ desc "build rdoc using hanna theme"
21
+ task :rdoc do
22
+ `rm -rf rdoc && rdoc -o rdoc --inline-source --format=html -T hanna README* lib/**/*.rb`
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib' << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |t|
35
+ t.libs << 'test'
36
+ t.test_files = FileList['test/**/*_test.rb']
37
+ t.verbose = true
38
+ end
39
+ rescue LoadError
40
+ puts "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+
43
+ # Rubyforge publishing
44
+ begin
45
+ require 'rake/contrib/sshpublisher'
46
+ namespace :rubyforge do
47
+
48
+ desc "Release gem and RDoc documentation to RubyForge"
49
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
50
+
51
+ namespace :release do
52
+ desc "Publish RDoc to RubyForge."
53
+ task :docs => [:rdoc] do
54
+ config = YAML.load(
55
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
56
+ )
57
+
58
+ host = "#{config['username']}@rubyforge.org"
59
+ remote_dir = "/var/www/gforge-projects/longurl/"
60
+ local_dir = 'rdoc'
61
+
62
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
63
+ end
64
+ end
65
+ end
66
+ rescue LoadError
67
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
68
+ end
69
+
70
+ task :default => :test
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ * add a cache to avoid multiple calls for same url
2
+ * cache could be : hash, memcache, ...
3
+ * handle http errors
4
+ * handle json parsing errors
5
+ * handle ServiceUnknown exception
6
+ * possible infinite loop in Direct::follow_redirections
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 5
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "longurl"
5
+
6
+ def usage
7
+ puts "Usage: #$0 <url>"
8
+ exit(-1)
9
+ end
10
+
11
+ if ARGV.size < 1
12
+ usage
13
+ end
14
+
15
+ puts LongURL.expand(ARGV[0])
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2009 by Fabien Jakimowicz (fabien@jakimowicz.com)
2
+ #
3
+ # Please see the LICENSE file for licensing.
4
+
5
+ require 'longurl/constants'
6
+ require 'longurl/exceptions'
7
+ require 'longurl/url'
8
+ require 'longurl/service'
9
+ require 'longurl/direct'
10
+ require 'longurl/expander'
11
+ require 'longurl/expand'
@@ -0,0 +1,9 @@
1
+ require "uri"
2
+
3
+ module LongURL
4
+ ShortURLMatchRegexp = /http:\/\/[\/\-_.a-z0-9]+/im
5
+
6
+ # Urls for longurl
7
+ EndPoint = URI.parse("http://api.longurl.org/v1/expand")
8
+ ServiceEndPoint = URI.parse("http://api.longurl.org/v1/services")
9
+ end
@@ -0,0 +1,26 @@
1
+ require "net/http"
2
+ require "longurl/url"
3
+ require "longurl/exceptions"
4
+
5
+ module LongURL
6
+ module Direct
7
+ # Will follow redirections given url <tt>orig</tt>.
8
+ # === Exceptions
9
+ # * LongURL::NetworkError in case of a network error (timeout, socket error, ...)
10
+ # * LongURL::InvalidURL in case of a bad url (nil, empty, not http scheme ...)
11
+ # * LongURL::TooManyRedirections if there are too many redirection for destination
12
+ def self.follow_redirections(orig, limit = 5)
13
+ raise LongURL::TooManyRedirections if limit == 0
14
+ uri = LongURL::URL.check(orig)
15
+ Net::HTTP.start(uri.host, uri.port) do |http|
16
+ answer = http.get(uri.path.empty? ? '/' : uri.path)
17
+ dest = answer['Location']
18
+ (dest && dest[0, 7] == 'http://' && follow_redirections(dest, limit - 1)) || orig
19
+ end
20
+ rescue Timeout::Error, Errno::ENETUNREACH, Errno::ETIMEDOUT, SocketError
21
+ raise LongURL::NetworkError
22
+ rescue
23
+ raise LongURL::UnknownError
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ module LongURL
2
+ # Raised by LongURL::Service class if longurl.org service returns unsupported service error.
3
+ class UnsupportedService < StandardError
4
+ end
5
+
6
+ # Raised by LongURL::Service class if longurl.org service returns a not supported answer.
7
+ class UnknownError < StandardError
8
+ end
9
+
10
+ # Raised by LongURL::Service if supplied url is invalid (nil, empty, ...)
11
+ class InvalidURL < StandardError
12
+ end
13
+
14
+ # Raised if a network error occurs : timeout, unreachable network, ...
15
+ class NetworkError < StandardError
16
+ end
17
+
18
+ # Raised if there are too many redirection in a direct resolution.
19
+ class TooManyRedirections < StandardError
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ require 'longurl/expander'
2
+
3
+ module LongURL
4
+
5
+ class << self
6
+
7
+ # Expand given <tt>:url</tt> to a longest one.
8
+ # First, expand will try to expand url using longurl.org service.
9
+ # Then, it will try to direct follow redirections on the given url and returns final one.
10
+ # === Options
11
+ # * <tt>:cache</tt> : cache object to use, must implement [] and []= functions.
12
+ # * <tt>:supported_services_only</tt>: If true, only attempts to expand URLs that are listed as supported by
13
+ # LongURL.org's API. Defaults to false.
14
+ # === Types
15
+ # <tt>url</tt> is expected to be a String and returns a String with the url.
16
+ # === Examples
17
+ # # simple expands
18
+ # LongURL.expand("http://tinyurl.com/1c2") # => "http://www.google.com"
19
+ # LongURL.expand("http://tinyurl.com/blnhsg") # => "http://www.google.com/search?q=number+of+horns+on+a+unicorn&ie=UTF-8"
20
+ # LongURL.expand("http://is.gd/iUKg") # => "http://fabien.jakimowicz.com"
21
+ #
22
+ # # not expandable urls
23
+ # LongURL.expand("http://www.linuxfr.org") # => "http://www.linuxfr.org"
24
+ #
25
+ # === Exceptions
26
+ # * LongURL::InvalidURL : will occurs if given url is nil, empty or invalid
27
+ # * LongURL::NetworkError : a network (timeout, host could be reached, ...) error occurs
28
+ # * LongURL::UnknownError : an unknown error occurs
29
+ def expand(url, options = {})
30
+ @@expander ||= Expander.new(
31
+ :cache => options[:cache],
32
+ :supported_services_only => options[:supported_services_only]
33
+ )
34
+ @@expander.expand(url)
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,98 @@
1
+ require "longurl/exceptions"
2
+ require "longurl/service"
3
+ require "longurl/direct"
4
+
5
+ module LongURL
6
+
7
+ # == URL Expander class.
8
+ # Will use Service and Direct classes to expand an url.
9
+ # Each call to external services is cached to save time and cache object is customizable.
10
+ # You can for example use MemCache for the cache. it will allow different instances of Expander and Service to share the same cache.
11
+ # === Examples
12
+ # # Simple usage
13
+ # e = LongURL::Expander.new
14
+ # e.expand("http://tinyurl.com/1c2") # => "http://www.google.com"
15
+ # e.expand("http://tinyurl.com/blnhsg") # => "http://www.google.com/search?q=number+of+horns+on+a+unicorn&ie=UTF-8"
16
+ # e.expand("http://is.gd/iUKg") # => "http://fabien.jakimowicz.com"
17
+ #
18
+ # # not expandable urls
19
+ # e.expand("http://www.linuxfr.org") # => "http://www.linuxfr.org"
20
+ #
21
+ # # not expandable urls, calling longurl.org only
22
+ # e.expand_with_service_only("http://www.linuxfr.org") # => "http://www.linuxfr.org/pub"
23
+ #
24
+ # # not expandable urls, direct resolution only
25
+ # e.direct_resolution("http://www.linuxfr.org") # => "http://www.linuxfr.org/pub"
26
+ #
27
+ # # MemCache as cache
28
+ # e = LongURL::Expander.new(:cache => MemCache.new("localhost:11211", :namespace => "LongURL"))
29
+ # e.expand("http://is.gd/iUKg") # => "http://fabien.jakimowicz.com"
30
+ # === Exceptions
31
+ # * LongURL::InvalidURL : will occurs if given url is nil, empty or invalid
32
+ # * LongURL::NetworkError : a network (timeout, host could be reached, ...) error occurs
33
+ # * LongURL::UnknownError : an unknown error occurs
34
+ class Expander
35
+
36
+ attr_accessor :supported_services_only
37
+
38
+ # Initialize a new Expander.
39
+ # === Options
40
+ # * <tt>:cache</tt>: define a cache which Expander can use.
41
+ # It must implement [] and []= methods. It can be disabled using false.
42
+ # * <tt>:supported_services_only</tt>: If true, only attempts to expand URLs that are listed as supported by
43
+ # LongURL.org's API. Defaults to false.
44
+ def initialize(options = {})
45
+ # OPTIMIZE : This code is a complete duplicate of cache handling in service.
46
+ if options[:cache].nil?
47
+ @@cache = Hash.new
48
+ elsif options[:cache] == false
49
+ @@cache = nil
50
+ else
51
+ @@cache = options[:cache]
52
+ end
53
+
54
+ @supported_services_only = options[:supported_services_only]
55
+
56
+ @@service = Service.new(:cache => @@cache)
57
+ end
58
+
59
+ # Expand given url using LongURL::Service.
60
+ # If it's not a supported URL, a direct_resolution is attempted unless supported_services_only is true.
61
+ def expand(url)
62
+ @@service.query_supported_service_only url
63
+ rescue UnsupportedService
64
+ supported_services_only ? url : direct_resolution(url)
65
+ end
66
+
67
+ # Try to directly resolve url using LongURL::Direct to get final redirection.
68
+ # This call is cached.
69
+ def direct_resolution(url)
70
+ # OPTIMIZE : this code is almost identical as the one in service for handling service retrieval.
71
+ if @@cache
72
+ @@cache[url] ||= Direct.follow_redirections(url)
73
+ else
74
+ Direct.follow_redirections(url)
75
+ end
76
+ end
77
+
78
+ # Expand all url in the given string, if an error occurs while expanding url, then the original url is used
79
+ def expand_each_in(text)
80
+ text.gsub(ShortURLMatchRegexp) do |shorturl|
81
+ begin
82
+ expand shorturl
83
+ rescue LongURL::InvalidURL,
84
+ LongURL::NetworkError,
85
+ LongURL::TooManyRedirections,
86
+ LongURL::UnknownError,
87
+ JSON::ParserError
88
+ shorturl
89
+ end
90
+ end
91
+ end
92
+
93
+ # Expand given url using LongURL::Service only. If given url is not a expandable url, it will still be given to Service.
94
+ def expand_with_service_only(url)
95
+ @@service.query url
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,115 @@
1
+ require "net/http"
2
+ require "cgi"
3
+ require "uri"
4
+ require "rubygems"
5
+ require "json"
6
+ require "longurl/constants"
7
+ require "longurl/exceptions"
8
+ require "longurl/url"
9
+
10
+ module LongURL
11
+
12
+ class Service
13
+
14
+ def initialize(params = {})
15
+ if params[:cache].nil?
16
+ @@cache = Hash.new
17
+ elsif params[:cache] == false
18
+ @@cache = nil
19
+ else
20
+ @@cache = params[:cache]
21
+ end
22
+ @@supported_services = cached_or_fetch_supported_services
23
+ end
24
+
25
+ def query_supported_service_only(url)
26
+ check url
27
+ raise LongURL::UnsupportedService unless service_supported?(url)
28
+ (@@cache && cached_query(url)) || query(url)
29
+ end
30
+
31
+ def cached_query(url)
32
+ @@cache[url] ||= query(url)
33
+ end
34
+
35
+ def query(url)
36
+ escaped_url = check_and_escape(url)
37
+ Net::HTTP.start(EndPoint.host, EndPoint.port) do |http|
38
+ handle_response http.get("#{EndPoint.path}?format=json&url=#{escaped_url}")
39
+ end
40
+ rescue Timeout::Error, Errno::ENETUNREACH, Errno::ETIMEDOUT, SocketError
41
+ raise LongURL::NetworkError
42
+ end
43
+
44
+ # Check among supported services by longurl.org if given <tt>url</tt> is supported.
45
+ # Returns true if supported, false otherwise.
46
+ def service_supported?(url)
47
+ @@supported_services.include? URI.parse(url).host.downcase
48
+ end
49
+
50
+ protected
51
+
52
+ # Returns a list of supported services.
53
+ # Use cache to get the list or fetch it if cache is empty.
54
+ def cached_or_fetch_supported_services
55
+ if @@cache
56
+ @@cache['supported_services'] ||= fetch_supported_services
57
+ else
58
+ fetch_supported_services
59
+ end
60
+ end
61
+
62
+ # Check given <tt>url</tt> using LongURL::URL.check
63
+ def check(url)
64
+ LongURL::URL.check url
65
+ end
66
+
67
+ # Check given url and escape it for http query argument passing.
68
+ def check_and_escape(url)
69
+ check url
70
+ CGI.escape url
71
+ end
72
+
73
+ # Fetch supported services from longurl.org api.
74
+ # Returns supported services in an Array.
75
+ # Raises LongURL::NetworkError in case of a network error (timeout, ...)
76
+ def fetch_supported_services
77
+ Net::HTTP.start(ServiceEndPoint.host, ServiceEndPoint.port) do |http|
78
+ response = http.get("#{ServiceEndPoint.path}?format=json")
79
+ parsed = JSON.parse(response.body)
80
+ parsed.values.flatten
81
+ end
82
+ rescue Timeout::Error, Errno::ENETUNREACH, Errno::ETIMEDOUT, SocketError
83
+ raise LongURL::NetworkError
84
+ rescue
85
+ raise LongURL::UnknownError
86
+ end
87
+
88
+ def handle_response(response)
89
+ parsed = JSON.parse(response.body)
90
+ parsed = parsed.first if parsed.is_a?(Array)
91
+ if parsed['long_url']
92
+ parsed['long_url']
93
+ elsif parsed['message'] # Error
94
+ raise exception_regarding_message(parsed['message'])
95
+ else
96
+ raise LongURL::UnknownError
97
+ end
98
+ end
99
+
100
+ def exception_class_regarding_message(message)
101
+ case message
102
+ when 'Unsupported service.'
103
+ LongURL::UnsupportedService
104
+ when 'Connection timeout'
105
+ LongURL::NetworkError
106
+ when 'Could not expand URL. Please check that you have submitted a valid URL.'
107
+ LongURL::InvalidURL
108
+ else
109
+ LongURL::UnknownError
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,18 @@
1
+ require 'uri'
2
+ require "longurl/exceptions"
3
+
4
+ module LongURL
5
+ module URL
6
+ # Check given <tt>url</tt>
7
+ # Raises LongURL::InvalidURL if <tt>url</tt> is invalid.
8
+ # Returns a parsed http uri object on success.
9
+ def self.check(url)
10
+ raise LongURL::InvalidURL if url.nil? or url.empty?
11
+ result = URI.parse(url)
12
+ raise LongURL::InvalidURL unless result.is_a?(URI::HTTP)
13
+ result
14
+ rescue URI::InvalidURIError
15
+ raise LongURL::InvalidURL
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,75 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{longurl}
5
+ s.version = "0.1.5"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Fabien Jakimowicz"]
9
+ s.date = %q{2009-06-13}
10
+ s.default_executable = %q{longurl}
11
+ s.description = %q{LongURL expands short urls (tinyurl, is.gd, ...) to original ones, using on LongURL.org, internal resolution or direct resolution}
12
+ s.email = %q{fabien@jakimowicz.com}
13
+ s.executables = ["longurl"]
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "LICENSE",
21
+ "Manifest",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "TODO",
25
+ "VERSION.yml",
26
+ "bin/longurl",
27
+ "lib/longurl.rb",
28
+ "lib/longurl/constants.rb",
29
+ "lib/longurl/direct.rb",
30
+ "lib/longurl/exceptions.rb",
31
+ "lib/longurl/expand.rb",
32
+ "lib/longurl/expander.rb",
33
+ "lib/longurl/service.rb",
34
+ "lib/longurl/url.rb",
35
+ "longurl.gemspec",
36
+ "test/cache_mock.rb",
37
+ "test/constants.rb",
38
+ "test/expander_test.rb",
39
+ "test/service/no_cache_service_test.rb",
40
+ "test/service/service_cache_test.rb",
41
+ "test/service/service_test.rb",
42
+ "test/service/supported_services_test.rb",
43
+ "test/url_test.rb"
44
+ ]
45
+ s.has_rdoc = true
46
+ s.homepage = %q{http://longurl.rubyforge.org}
47
+ s.rdoc_options = ["--charset=UTF-8"]
48
+ s.require_paths = ["lib"]
49
+ s.rubyforge_project = %q{longurl}
50
+ s.rubygems_version = %q{1.3.1}
51
+ s.summary = %q{LongURL expands shorten urls (tinyurl, is.gd, ...)}
52
+ s.test_files = [
53
+ "test/cache_mock.rb",
54
+ "test/constants.rb",
55
+ "test/expander_test.rb",
56
+ "test/service/no_cache_service_test.rb",
57
+ "test/service/service_cache_test.rb",
58
+ "test/service/service_test.rb",
59
+ "test/service/supported_services_test.rb",
60
+ "test/url_test.rb"
61
+ ]
62
+
63
+ if s.respond_to? :specification_version then
64
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
+ s.specification_version = 2
66
+
67
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
68
+ s.add_runtime_dependency(%q<json>, [">= 0"])
69
+ else
70
+ s.add_dependency(%q<json>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<json>, [">= 0"])
74
+ end
75
+ end
@@ -0,0 +1,20 @@
1
+ class CacheMock
2
+
3
+ attr_accessor :keys_stored, :keys_asked, :storage
4
+
5
+ def initialize(params = {})
6
+ @storage = {}
7
+ @keys_stored = []
8
+ @keys_asked = []
9
+ end
10
+
11
+ def [](key)
12
+ @keys_asked << key
13
+ @storage[key]
14
+ end
15
+
16
+ def []=(key, value)
17
+ @keys_stored << key
18
+ @storage[key] = value
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ ShortToLong = {
2
+ :tiny_url => {
3
+ "http://tinyurl.com/cnuw9a" => "http://fabien.jakimowicz.com",
4
+ "http://tinyurl.com/blnhsg" => "http://www.google.com/search?q=number+of+horns+on+a+unicorn&ie=UTF-8"
5
+ },
6
+ :is_gd => {
7
+ "http://is.gd/iUKg" => "http://fabien.jakimowicz.com",
8
+ "http://is.gd/iYCo" => "http://www.google.com/search?q=number+of+horns+on+a+unicorn&ie=UTF-8"
9
+ },
10
+ :friendfeed => {
11
+ "http://ff.im/-31OFh" => "http://en.wikipedia.org/wiki/Product_requirements_document",
12
+ "http://ff.im/-31MWm" => "http://www.infrasystems.com/how-to-write-an-mrd.html"
13
+ }
14
+ }
@@ -0,0 +1,46 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "longurl/expander"
6
+
7
+ gem 'mocha', '>= 0.9.5'
8
+ require 'mocha'
9
+
10
+ class TestExpander < Test::Unit::TestCase
11
+ def setup
12
+ @expander = LongURL::Expander.new
13
+ end
14
+
15
+ def test_expand_each_in_should_expand_friendfeed_urls
16
+ assert_equal "Product requirements document - Wikipedia, http://en.wikipedia.org/wiki/Product_requirements_document the free encyclopedia",
17
+ @expander.expand_each_in("Product requirements document - Wikipedia, http://ff.im/-31OFh the free encyclopedia")
18
+ end
19
+
20
+ def test_expand_each_in_should_not_change_strings_with_no_urls
21
+ assert_equal "i'm not to be changed !!!", @expander.expand_each_in("i'm not to be changed !!!")
22
+ end
23
+
24
+ def test_expand_each_in_should_be_able_to_expand_multiple_urls
25
+ assert_equal "Those websites are great: http://www.flickr.com/photos/jakimowicz & http://www.google.com/profiles/fabien.jakimowicz",
26
+ @expander.expand_each_in("Those websites are great: http://tinyurl.com/r9cm9p & http://is.gd/Bnxy")
27
+ end
28
+ end
29
+
30
+ class TestExpanderSupportedServicesOnly < Test::Unit::TestCase
31
+ def setup
32
+ @expander = LongURL::Expander.new(:supported_services_only => true)
33
+ end
34
+
35
+ def test_supported_services_only_defaults_to_falsy_value
36
+ expander = LongURL::Expander.new
37
+
38
+ assert !expander.supported_services_only
39
+ end
40
+
41
+ def test_expand_should_not_attempt_direct_resolution
42
+ @expander.expects(:direct_resolution).never
43
+
44
+ @expander.expand('http://is.gd/Bnxy')
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "constants"
6
+ require "longurl/exceptions"
7
+ require "longurl/service"
8
+
9
+ class TestNoCacheService < Test::Unit::TestCase
10
+ # OPTIMIZE : all these tests are a plain copy from service_test.rb, we can make something better.
11
+
12
+ def setup
13
+ @service = LongURL::Service.new(:cache => false)
14
+ end
15
+
16
+ def test_query_should_raise_invalid_url_if_url_is_nil
17
+ assert_raise(LongURL::InvalidURL) { @service.query(nil) }
18
+ end
19
+
20
+ def test_query_should_raise_invalid_url_if_url_is_empty
21
+ assert_raise(LongURL::InvalidURL) { @service.query('') }
22
+ end
23
+
24
+ def test_query_should_returns_given_url_if_not_shorten_url
25
+ assert_equal "http://www.google.com", @service.query("http://www.google.com")
26
+ end
27
+
28
+ def test_query_should_returns_expanded_url_for_supported_services
29
+ ShortToLong.each_value {|service| service.each {|short, long| assert_equal long, @service.query(short)}}
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "cache_mock"
6
+ require "constants"
7
+ require "longurl/exceptions"
8
+ require "longurl/service"
9
+
10
+ class TestServiceCache < Test::Unit::TestCase
11
+
12
+ def setup
13
+ @cache = CacheMock.new
14
+ @service = LongURL::Service.new(:cache => @cache)
15
+ end
16
+
17
+ def test_query_should_use_cache_before_external_fetch
18
+ url = ShortToLong[:is_gd].keys.first
19
+ @service.query_supported_service_only(url)
20
+ assert_equal ['supported_services', url], @cache.keys_asked
21
+ @service.query_supported_service_only(url)
22
+ assert_equal ['supported_services', url, url], @cache.keys_asked
23
+ end
24
+
25
+ def test_query_should_cache_results_from_supported_services
26
+ ShortToLong.each_value do |service|
27
+ service.each do |short, long|
28
+ @service.query_supported_service_only(short)
29
+ assert @cache.keys_stored.include?(short)
30
+ assert_equal long, @cache[short]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "longurl/exceptions"
6
+ require "longurl/service"
7
+
8
+ class TestService < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @service = LongURL::Service.new
12
+ end
13
+
14
+ def test_query_should_raise_invalid_url_if_url_is_nil
15
+ assert_raise(LongURL::InvalidURL) { @service.query(nil) }
16
+ end
17
+
18
+ def test_query_should_raise_invalid_url_if_url_is_empty
19
+ assert_raise(LongURL::InvalidURL) { @service.query('') }
20
+ end
21
+
22
+ def test_query_should_returns_given_url_if_not_shorten_url
23
+ assert_equal "http://www.google.com", @service.query("http://www.google.com")
24
+ end
25
+
26
+ def test_query_should_returns_expanded_url_for_supported_services
27
+ ShortToLong.each_value {|service| service.each {|short, long| assert_equal long, @service.query(short)}}
28
+ end
29
+ end
@@ -0,0 +1,41 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "cache_mock"
6
+ require "constants"
7
+ require "longurl/exceptions"
8
+ require "longurl/service"
9
+
10
+ class TestSupportedServices < Test::Unit::TestCase
11
+
12
+ def setup
13
+ @cache = CacheMock.new
14
+ end
15
+
16
+ def test_service_should_check_if_available_services_are_in_cache
17
+ assert_equal [], @cache.keys_asked
18
+ @service = LongURL::Service.new(:cache => @cache)
19
+ assert_equal ['supported_services'], @cache.keys_asked
20
+ end
21
+
22
+ def test_service_should_store_available_services_in_cache
23
+ assert_equal [], @cache.keys_stored
24
+ @service = LongURL::Service.new(:cache => @cache)
25
+ assert_equal ['supported_services'], @cache.keys_stored
26
+ end
27
+
28
+ def test_supported_services_stored_in_cache_should_be_a_flat_array_of_strings
29
+ @service = LongURL::Service.new(:cache => @cache)
30
+ assert_kind_of Array, @cache['supported_services']
31
+ assert @cache['supported_services'].all? {|object| object.is_a?(String)}
32
+ end
33
+
34
+ def test_service_should_use_supported_services_stored_in_cache_if_available
35
+ @cache['supported_services'] = ['bleh.com', 'bli.com']
36
+ @service = LongURL::Service.new(:cache => @cache)
37
+ assert_equal ['supported_services'], @cache.keys_asked
38
+ assert_equal ['supported_services'], @cache.keys_stored
39
+ assert_raise(LongURL::UnsupportedService) { @service.query_supported_service_only(ShortToLong[:is_gd].keys.first) }
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ $test_lib_dir = File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift($test_lib_dir)
3
+
4
+ require "test/unit"
5
+ require "uri"
6
+ require "longurl/exceptions"
7
+ require "longurl/url"
8
+
9
+ class TestURL < Test::Unit::TestCase
10
+
11
+ BadURLs = ["http:",
12
+ "http://",
13
+ "http://hoth.entp..."]
14
+
15
+ NotHTTPURLs = ["bleh",
16
+ "bleh://",
17
+ "bleh://asfd.com",
18
+ "ftp://asdf.com",
19
+ "google.com",
20
+ "asdf@toto.com",
21
+ "httpd://asdf.com"]
22
+
23
+ GoodURLs = ["http://www.google.com", "https://rubyonrails.org"]
24
+
25
+ def test_check_should_raise_invalid_url_if_url_is_nil
26
+ assert_raise(LongURL::InvalidURL) { LongURL::URL.check nil }
27
+ end
28
+
29
+ def test_check_should_raise_invalid_url_if_url_is_empty
30
+ assert_raise(LongURL::InvalidURL) { LongURL::URL.check "" }
31
+ end
32
+
33
+ def test_check_should_raise_invalid_url_if_url_is_invalid
34
+ BadURLs.each {|bad_url| assert_raise(LongURL::InvalidURL) { LongURL::URL.check bad_url } }
35
+ end
36
+
37
+ def test_check_should_raise_invalid_url_if_url_is_not_http
38
+ NotHTTPURLs.each {|bad_url| assert_raise(LongURL::InvalidURL) { LongURL::URL.check bad_url } }
39
+ end
40
+
41
+ def test_check_should_returns_parsed_url_on_success
42
+ GoodURLs.each {|good_url| assert_equal URI.parse(good_url), LongURL::URL.check(good_url)}
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chuyeow-longurl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Fabien Jakimowicz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-13 00:00:00 -07:00
13
+ default_executable: longurl
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: LongURL expands short urls (tinyurl, is.gd, ...) to original ones, using on LongURL.org, internal resolution or direct resolution
26
+ email: fabien@jakimowicz.com
27
+ executables:
28
+ - longurl
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .gitignore
36
+ - LICENSE
37
+ - Manifest
38
+ - README.rdoc
39
+ - Rakefile
40
+ - TODO
41
+ - VERSION.yml
42
+ - bin/longurl
43
+ - lib/longurl.rb
44
+ - lib/longurl/constants.rb
45
+ - lib/longurl/direct.rb
46
+ - lib/longurl/exceptions.rb
47
+ - lib/longurl/expand.rb
48
+ - lib/longurl/expander.rb
49
+ - lib/longurl/service.rb
50
+ - lib/longurl/url.rb
51
+ - longurl.gemspec
52
+ - test/cache_mock.rb
53
+ - test/constants.rb
54
+ - test/expander_test.rb
55
+ - test/service/no_cache_service_test.rb
56
+ - test/service/service_cache_test.rb
57
+ - test/service/service_test.rb
58
+ - test/service/supported_services_test.rb
59
+ - test/url_test.rb
60
+ has_rdoc: true
61
+ homepage: http://longurl.rubyforge.org
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project: longurl
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: LongURL expands shorten urls (tinyurl, is.gd, ...)
86
+ test_files:
87
+ - test/cache_mock.rb
88
+ - test/constants.rb
89
+ - test/expander_test.rb
90
+ - test/service/no_cache_service_test.rb
91
+ - test/service/service_cache_test.rb
92
+ - test/service/service_test.rb
93
+ - test/service/supported_services_test.rb
94
+ - test/url_test.rb