rmoriz-alexa 0.0.4.1

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Wojciech Wnętrzak
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ = Alexa Web Information Service
2
+
3
+ == Usage
4
+ Alexa.url_info(:access_key_id => 'key', :secret_access_key => 'secret', :host => 'site.com')
5
+ # also you can specify option :response_group => 'Rank,ContactInfo' or any other valid group,
6
+ # see: http://docs.amazonwebservices.com/AlexaWebInfoService/2005-07-11/
7
+ # default response group takes all the available options
8
+
9
+ returns object with methods:
10
+ :xml_response, :rank, :data_url, :site_title, :site_description, :language_locale, :language_encoding,
11
+ :links_in_count, :keywords, :related_links, :speed_median_load_time, :speed_percentile,
12
+ :rank_by_country, :rank_by_city, :usage_statistics
13
+
14
+ == Copyright
15
+
16
+ Copyright (c) 2009 Wojciech Wnętrzak. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'rake'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "alexa"
9
+ gem.summary = %Q{Alexa Web Information Service library}
10
+ gem.email = "w.wnetrzak@gmail.com"
11
+ gem.homepage = "http://github.com/morgoth/alexa"
12
+ gem.authors = ["Wojciech Wnętrzak"]
13
+ gem.add_dependency('xml-simple')
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION.yml')
47
+ config = YAML.load(File.read('VERSION.yml'))
48
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
49
+ else
50
+ version = ""
51
+ end
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "alexa #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
58
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
data/alexa.gemspec ADDED
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{alexa}
5
+ s.version = "0.0.4.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Wojciech Wnętrzak"]
9
+ s.date = %q{2009-07-07}
10
+ s.email = %q{w.wnetrzak@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".document",
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README.rdoc",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "alexa.gemspec",
23
+ "lib/alexa.rb",
24
+ "lib/alexa/url_info.rb",
25
+ "test/alexa_test.rb",
26
+ "test/fixtures/empty.xml",
27
+ "test/fixtures/polsl.xml",
28
+ "test/fixtures/polsl_small.xml",
29
+ "test/test_helper.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/morgoth/alexa}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.4}
35
+ s.summary = %q{Alexa Web Information Service library}
36
+ s.test_files = [
37
+ "test/alexa_test.rb",
38
+ "test/test_helper.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<xml-simple>, [">= 0"])
47
+ else
48
+ s.add_dependency(%q<xml-simple>, [">= 0"])
49
+ end
50
+ else
51
+ s.add_dependency(%q<xml-simple>, [">= 0"])
52
+ end
53
+ end
@@ -0,0 +1,95 @@
1
+ module Alexa
2
+ class UrlInfo
3
+ RESPONSE_GROUP = "Rank,ContactInfo,AdultContent,Speed,Language,Keywords,OwnedDomains,LinksInCount,SiteData,RelatedLinks,RankByCountry,RankByCity,UsageStats"
4
+ attr_accessor :access_key_id, :secret_access_key, :host, :response_group, :xml_response,
5
+ :rank, :data_url, :site_title, :site_description, :language_locale, :language_encoding,
6
+ :links_in_count, :keywords, :related_links, :speed_median_load_time, :speed_percentile,
7
+ :rank_by_country, :rank_by_city, :usage_statistics
8
+
9
+ def initialize(options = {} )
10
+ @access_key_id = options[:access_key_id] or raise ArgumentError.new("you must specify access_key_id")
11
+ @secret_access_key = options[:secret_access_key] or raise ArgumentError.new("you must specify secret_access_key")
12
+ @host = options[:host] or raise ArgumentError.new("you must specify host")
13
+ @response_group = options[:response_group] || RESPONSE_GROUP
14
+ end
15
+
16
+ def connect
17
+ action = "UrlInfo"
18
+ timestamp = ( Time::now ).utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
19
+ signature = generate_signature(secret_access_key, action, timestamp)
20
+ url = generate_url(action, access_key_id, signature, timestamp, response_group, host)
21
+ response = Net::HTTP.start(url.host) do |http|
22
+ http.get url.request_uri
23
+ end
24
+ @xml_response = handle_response(response).body
25
+ end
26
+
27
+ def parse_xml(xml)
28
+ xml = XmlSimple.xml_in(force_encoding(xml), 'ForceArray' => false)
29
+ group = response_group.split(',')
30
+ alexa = xml['Response']['UrlInfoResult']['Alexa']
31
+ @rank = alexa['TrafficData']['Rank'].to_i if group.include?('Rank') and !alexa['TrafficData']['Rank'].empty?
32
+ @data_url = alexa['TrafficData']['DataUrl']['content'] if group.include?('Rank')
33
+ @rank_by_country = alexa['TrafficData']['RankByCountry']['Country'] if group.include?('RankByCountry')
34
+ @rank_by_city = alexa['TrafficData']['RankByCity']['City'] if group.include?('RankByCity')
35
+ @usage_statistics = alexa['TrafficData']['UsageStatistics']["UsageStatistic"] if group.include?('UsageStats') and !alexa['TrafficData']['UsageStatistics'].nil?
36
+
37
+ @site_title = alexa['ContentData']['SiteData']['Title'] if group.include?('SiteData')
38
+ @site_description = alexa['ContentData']['SiteData']['Description'] if group.include?('SiteData')
39
+ @language_locale = alexa['ContentData']['Language']['Locale'] if group.include?('Language')
40
+ @language_encoding = alexa['ContentData']['Language']['Encoding'] if group.include?('Language')
41
+ @links_in_count = alexa['ContentData']['LinksInCount'].to_i if group.include?('LinksInCount') and !alexa['ContentData']['LinksInCount'].empty?
42
+ @keywords = alexa['ContentData']['Keywords']['Keyword'] if group.include?('Keywords')
43
+ @speed_median_load_time = alexa['ContentData']['Speed']['MedianLoadTime'].to_i if group.include?('Speed') and !alexa['ContentData']['Speed']['MedianLoadTime'].empty?
44
+ @speed_percentile = alexa['ContentData']['Speed']['Percentile'].to_i if group.include?('Speed') and !alexa['ContentData']['Speed']['Percentile'].empty?
45
+
46
+ @related_links = alexa['Related']['RelatedLinks']['RelatedLink'] if group.include?('RelatedLinks')
47
+ end
48
+
49
+ private
50
+
51
+ def force_encoding(xml)
52
+ if RUBY_VERSION >= '1.9'
53
+ xml.force_encoding(Encoding::UTF_8)
54
+ else
55
+ xml
56
+ end
57
+ end
58
+
59
+ def handle_response(response)
60
+ case response.code.to_i
61
+ when 200...300
62
+ response
63
+ when 300...600
64
+ if response.body.nil?
65
+ raise StandardError.new(response)
66
+ else
67
+ @xml_response = response.body
68
+ xml = XmlSimple.xml_in(response.body, 'ForceArray' => false)
69
+ message = xml['Errors']['Error']['Message']
70
+ raise StandardError.new(message)
71
+ end
72
+ else
73
+ raise StandardError.new("Unknown code: #{respnse.code}")
74
+ end
75
+ end
76
+
77
+ def generate_signature(secret_acces_key, action, timestamp)
78
+ Base64.encode64( OpenSSL::HMAC.digest( OpenSSL::Digest::Digest.new( "sha1" ), secret_access_key, action + timestamp)).strip
79
+ end
80
+
81
+ def generate_url(action, access_key_id, signature, timestamp, response_group, host)
82
+ url = URI.parse(
83
+ "http://awis.amazonaws.com/?" +
84
+ {
85
+ "Action" => action,
86
+ "AWSAccessKeyId" => access_key_id,
87
+ "Signature" => signature,
88
+ "Timestamp" => timestamp,
89
+ "ResponseGroup" => response_group,
90
+ "Url" => host
91
+ }.to_a.collect{|item| item.first + "=" + CGI::escape(item.last) }.join("&") # Put key value pairs into http GET format
92
+ )
93
+ end
94
+ end
95
+ end
data/lib/alexa.rb ADDED
@@ -0,0 +1,21 @@
1
+ #/usr/bin/ruby
2
+ require "cgi"
3
+ require "base64"
4
+ require "openssl"
5
+ require "digest/sha1"
6
+ require "uri"
7
+ require "net/https"
8
+ require "xmlsimple"
9
+ require "time"
10
+
11
+ require 'alexa/url_info'
12
+
13
+ module Alexa
14
+ def self.url_info(options = {})
15
+ url_info = Alexa::UrlInfo.new(options)
16
+ xml = url_info.connect
17
+ url_info.parse_xml(xml)
18
+ url_info
19
+ end
20
+ end
21
+
@@ -0,0 +1,224 @@
1
+ require 'test_helper'
2
+
3
+ class AlexaTest < Test::Unit::TestCase
4
+ context "Alexa::UrlInfo" do
5
+ setup do
6
+ @alexa = Alexa::UrlInfo.new(
7
+ :access_key_id => "12345678901234567890",
8
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF",
9
+ :host => "some.host"
10
+ )
11
+ end
12
+
13
+ should "Generate signature" do
14
+ signature = @alexa.send :generate_signature, @alexa.secret_access_key, "UrlInfo", '2009-07-03T07:22:24.000Z'
15
+ assert_equal "I1mPdBy+flhhzqqUaamNq9gq190=", signature
16
+ end
17
+
18
+ should "Generate url" do
19
+ url = @alexa.send( :generate_url,
20
+ "UrlInfo",
21
+ @alexa.access_key_id,
22
+ "I1mPdBy+flhhzqqUaamNq9gq190=",
23
+ '2009-07-03T07:22:24.000Z',
24
+ "Rank,ContactInfo,AdultContent,Speed,Language,Keywords,OwnedDomains,LinksInCount,SiteData,RelatedLinks",
25
+ "heroku.com"
26
+ )
27
+ if RUBY_VERSION >= '1.9'
28
+ expected_uri = "/?Action=UrlInfo&AWSAccessKeyId=12345678901234567890&Signature=I1mPdBy%2BflhhzqqUaamNq9gq190%3D&Timestamp=2009-07-03T07%3A22%3A24.000Z&ResponseGroup=Rank%2CContactInfo%2CAdultContent%2CSpeed%2CLanguage%2CKeywords%2COwnedDomains%2CLinksInCount%2CSiteData%2CRelatedLinks&Url=heroku.com"
29
+ else
30
+ expected_uri = "/?Action=UrlInfo&Signature=I1mPdBy%2BflhhzqqUaamNq9gq190%3D&AWSAccessKeyId=12345678901234567890&Url=heroku.com&Timestamp=2009-07-03T07%3A22%3A24.000Z&ResponseGroup=Rank%2CContactInfo%2CAdultContent%2CSpeed%2CLanguage%2CKeywords%2COwnedDomains%2CLinksInCount%2CSiteData%2CRelatedLinks"
31
+ assert_equal expected_uri, url.request_uri
32
+ end
33
+ assert_equal "awis.amazonaws.com", url.host
34
+ end
35
+
36
+ context "should parse xml return by options LinksInCount,SiteData and" do
37
+ setup do
38
+ @alexa.response_group = "Rank,LinksInCount,SiteData"
39
+ xml = fixture_file('polsl_small.xml')
40
+ @alexa.parse_xml(xml)
41
+ end
42
+
43
+ should "return rank" do
44
+ assert_equal 86020, @alexa.rank
45
+ end
46
+
47
+ should "return data url" do
48
+ assert_equal "polsl.pl/", @alexa.data_url
49
+ end
50
+
51
+ should "return site title" do
52
+ assert_equal "Silesian University of Technology", @alexa.site_title
53
+ end
54
+
55
+ should "return site description" do
56
+ assert_equal "About the university, studies, faculties and departments, photo gallery.", @alexa.site_description
57
+ end
58
+
59
+ should "not crash" do
60
+ assert_nothing_raised do
61
+ @alexa.language_locale
62
+ end
63
+ assert_nil @alexa.language_locale
64
+ end
65
+ end
66
+
67
+ context "should parse xml with all options and" do
68
+ setup do
69
+ xml = fixture_file('polsl.xml')
70
+ @alexa.parse_xml(xml)
71
+ end
72
+
73
+ should "return rank" do
74
+ assert_equal 86020, @alexa.rank
75
+ end
76
+
77
+ should "return data url" do
78
+ assert_equal "polsl.pl", @alexa.data_url
79
+ end
80
+
81
+ should "return site title" do
82
+ assert_equal "Silesian University of Technology", @alexa.site_title
83
+ end
84
+
85
+ should "return site description" do
86
+ assert_equal "About the university, studies, faculties and departments, photo gallery.", @alexa.site_description
87
+ end
88
+
89
+ should "return language locale" do
90
+ assert_equal "pl-PL", @alexa.language_locale
91
+ end
92
+
93
+ should "return language encoding" do
94
+ assert_equal "iso-8859-2", @alexa.language_encoding
95
+ end
96
+
97
+ should "return links in count" do
98
+ assert_equal 281, @alexa.links_in_count
99
+ end
100
+
101
+ should "return keywords" do
102
+ assert_equal ["Polska", "Regionalne", "Gliwice"], @alexa.keywords
103
+ end
104
+
105
+ should "return related links" do
106
+ assert_equal 10, @alexa.related_links.count
107
+ end
108
+
109
+ should "return speed_median load time" do
110
+ assert_equal 266, @alexa.speed_median_load_time
111
+ end
112
+
113
+ should "return speed percentile" do
114
+ assert_equal 98, @alexa.speed_percentile
115
+ end
116
+
117
+ should "return rank by country" do
118
+ assert_equal 3, @alexa.rank_by_country.count
119
+ end
120
+
121
+ should "return rank by city" do
122
+ assert_equal 68, @alexa.rank_by_city.count
123
+ end
124
+
125
+ should "return usage statistics" do
126
+ assert_equal 4, @alexa.usage_statistics.count
127
+ end
128
+
129
+ end
130
+
131
+ context "should not crash when parsing empty xml response and" do
132
+ setup do
133
+ xml = fixture_file('empty.xml')
134
+ @alexa.parse_xml(xml)
135
+ end
136
+
137
+ should "return nil" do
138
+ assert_nil @alexa.rank
139
+ end
140
+
141
+ should "return nil" do
142
+ assert_nil @alexa.data_url
143
+ end
144
+
145
+ should "return nil" do
146
+ assert_nil @alexa.site_title
147
+ end
148
+
149
+ should "return nil" do
150
+ assert_nil @alexa.site_description
151
+ end
152
+
153
+ should "return nil" do
154
+ assert_nil @alexa.language_locale
155
+ end
156
+
157
+ should "return nil" do
158
+ assert_nil @alexa.language_encoding
159
+ end
160
+
161
+ should "return nil" do
162
+ assert_nil @alexa.links_in_count
163
+ end
164
+
165
+ should "return nil" do
166
+ assert_nil @alexa.keywords
167
+ end
168
+
169
+ should "return nil" do
170
+ assert_nil @alexa.related_links
171
+ end
172
+
173
+ should "return nil" do
174
+ assert_nil @alexa.speed_median_load_time
175
+ end
176
+
177
+ should "return nil" do
178
+ assert_nil @alexa.speed_percentile
179
+ end
180
+
181
+ should "return nil" do
182
+ assert_nil @alexa.rank_by_country
183
+ end
184
+
185
+ should "return nil" do
186
+ assert_nil @alexa.rank_by_city
187
+ end
188
+
189
+ should "return nil" do
190
+ assert_nil @alexa.usage_statistics
191
+ end
192
+
193
+ end
194
+
195
+ should "not raise error when response is OK" do
196
+ assert_nothing_raised do
197
+ @alexa.send :handle_response, Net::HTTPOK.new("1.1", "200", "OK")
198
+ end
199
+ end
200
+ end
201
+
202
+ should "Raise argumment error if keys or host are not present" do
203
+ assert_raise ArgumentError do
204
+ Alexa::UrlInfo.new(
205
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF",
206
+ :host => "some.host"
207
+ )
208
+ end
209
+
210
+ assert_raise ArgumentError do
211
+ Alexa::UrlInfo.new(
212
+ :access_key_id => "12345678901234567890",
213
+ :host => "some.host"
214
+ )
215
+ end
216
+
217
+ assert_raise ArgumentError do
218
+ Alexa::UrlInfo.new(
219
+ :access_key_id => "12345678901234567890",
220
+ :secret_access_key => "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDF"
221
+ )
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0"?>
2
+ <aws:UrlInfoResponse xmlns:aws="http://alexa.amazonaws.com/doc/2005-10-05/"><aws:Response xmlns:aws="http://awis.amazonaws.com/doc/2005-07-11"><aws:OperationRequest><aws:RequestId>6a12c8f4-056f-4fce-95cd-2f9d2a353236</aws:RequestId></aws:OperationRequest><aws:UrlInfoResult><aws:Alexa>
3
+
4
+ <aws:ContactInfo>
5
+ <aws:DataUrl type="canonical">404</aws:DataUrl>
6
+ <aws:PhoneNumbers>
7
+ <aws:PhoneNumber/>
8
+ </aws:PhoneNumbers>
9
+ <aws:OwnerName/>
10
+ <aws:Email/>
11
+ <aws:PhysicalAddress/>
12
+ <aws:CompanyStockTicker/>
13
+ </aws:ContactInfo>
14
+ <aws:ContentData>
15
+ <aws:DataUrl type="canonical">404</aws:DataUrl>
16
+ <aws:SiteData>
17
+ <aws:Title>404</aws:Title>
18
+ </aws:SiteData>
19
+ <aws:Speed>
20
+ <aws:MedianLoadTime/>
21
+ <aws:Percentile/>
22
+ </aws:Speed>
23
+ <aws:AdultContent/>
24
+ <aws:Language/>
25
+ <aws:LinksInCount/>
26
+ <aws:Keywords/>
27
+ <aws:OwnedDomains/>
28
+ </aws:ContentData>
29
+ <aws:Related>
30
+ <aws:DataUrl type="canonical">404</aws:DataUrl>
31
+ <aws:RelatedLinks/>
32
+ </aws:Related>
33
+ <aws:TrafficData>
34
+ <aws:DataUrl type="canonical">404</aws:DataUrl>
35
+ <aws:Rank/>
36
+ <aws:RankByCountry/>
37
+ <aws:RankByCity/>
38
+ </aws:TrafficData>
39
+ </aws:Alexa></aws:UrlInfoResult><aws:ResponseStatus xmlns:aws="http://alexa.amazonaws.com/doc/2005-10-05/"><aws:StatusCode>Success</aws:StatusCode></aws:ResponseStatus></aws:Response></aws:UrlInfoResponse>