alexa 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.travis.yml +4 -5
  2. data/Gemfile +1 -0
  3. data/README.md +76 -21
  4. data/alexa.gemspec +1 -9
  5. data/lib/alexa.rb +11 -22
  6. data/lib/alexa/api/category_browse.rb +62 -0
  7. data/lib/alexa/api/category_listings.rb +66 -0
  8. data/lib/alexa/api/sites_linking_in.rb +41 -0
  9. data/lib/alexa/api/traffic_history.rb +45 -0
  10. data/lib/alexa/api/url_info.rb +108 -0
  11. data/lib/alexa/client.rb +30 -0
  12. data/lib/alexa/connection.rb +86 -0
  13. data/lib/alexa/exceptions.rb +17 -0
  14. data/lib/alexa/utils.rb +19 -0
  15. data/lib/alexa/version.rb +1 -1
  16. data/test/api/category_browse_test.rb +27 -0
  17. data/test/api/category_listings_test.rb +19 -0
  18. data/test/api/sites_linking_in_test.rb +23 -0
  19. data/test/api/traffic_history_test.rb +24 -0
  20. data/test/api/url_info_test.rb +112 -0
  21. data/test/client_test.rb +65 -0
  22. data/test/connection_test.rb +37 -0
  23. data/test/fixtures/bad_request.txt +8 -0
  24. data/test/fixtures/category_browse/card_games.txt +480 -0
  25. data/test/fixtures/category_listings/card_games.txt +138 -0
  26. data/test/fixtures/sites_linking_in/github_count_3.txt +24 -0
  27. data/test/fixtures/traffic_history/alexa_example.txt +37 -0
  28. data/test/fixtures/traffic_history/github_range_2.txt +8 -0
  29. data/test/fixtures/{custom-response-group.txt → url_info/custom-response-group.txt} +0 -0
  30. data/test/fixtures/{empty_group.txt → url_info/empty_group.txt} +0 -0
  31. data/test/fixtures/{github_full.txt → url_info/github_full.txt} +0 -0
  32. data/test/fixtures/{github_rank.txt → url_info/github_rank.txt} +0 -0
  33. data/test/helper.rb +6 -8
  34. data/test/utils_test.rb +54 -0
  35. metadata +33 -23
  36. data/lib/alexa/url_info.rb +0 -109
  37. data/test/config_test.rb +0 -35
  38. data/test/url_info_test.rb +0 -152
data/.travis.yml CHANGED
@@ -2,11 +2,10 @@ notifications:
2
2
  disabled: true
3
3
  rvm:
4
4
  - ree
5
- - 1.9.2
6
5
  - 1.9.3
7
6
  env:
8
- - ALEXA_XML_PARSER=rexml
9
- - ALEXA_XML_PARSER=nokogiri
10
- - ALEXA_XML_PARSER=libxml
7
+ - XML_PARSER=rexml
8
+ - XML_PARSER=nokogiri
9
+ - XML_PARSER=libxml
11
10
  # does not work yet
12
- # - ALEXA_XML_PARSER=ox
11
+ # - XML_PARSER=ox
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "minitest", :platform => :ruby_18
4
+ gem "debugger", :platform => :ruby_19
4
5
  gem "rake"
5
6
 
6
7
  # xml parsers
data/README.md CHANGED
@@ -10,52 +10,107 @@ gem install alexa
10
10
 
11
11
  ## Usage
12
12
 
13
+ ### Url Info
14
+
13
15
  ``` ruby
14
- Alexa.url_info(:access_key_id => "key", :secret_access_key => "secret", :host => "site.com")
16
+ client = Alexa::Client.new(access_key_id: "key", secret_access_key: "secret")
17
+ url_info = client.url_info(url: "site.com")
15
18
 
16
19
  returns object with methods:
17
- :xml_response, :rank, :data_url, :site_title, :site_description, :language_locale, :language_encoding,
20
+ :rank, :data_url, :site_title, :site_description, :language_locale, :language_encoding,
18
21
  :links_in_count, :keywords, :related_links, :speed_median_load_time, :speed_percentile,
19
22
  :rank_by_country, :rank_by_city, :usage_statistics
20
23
  ```
21
24
 
22
- NOTE: You can specify option `:response_group => "Rank,ContactInfo"` or any other valid group.
25
+ NOTE: You can specify option `response_group: ["rank", "contact_info"]` or any other valid group.
23
26
  See: [Docs](http://docs.amazonwebservices.com/AlexaWebInfoService/latest/)
24
27
  Default response group takes all the available options.
25
28
 
26
- You can set configuration in block like this:
29
+ ### Sites Linking In
27
30
 
28
31
  ``` ruby
29
- Alexa.configure do |config|
30
- config.access_key_id = "key"
31
- config.secret_access_key = "secret"
32
- end
32
+ client = Alexa::Client.new(access_key_id: "key", secret_access_key: "secret")
33
+ sites_linking_in = client.sites_linking_in(url: "site.com")
34
+
35
+ # returns object with `sites` method
33
36
  ```
34
37
 
35
- alexa is using `multi_xml` to parse XML documents. Tested with:
38
+ NOTE: You can specify options:
36
39
 
37
- * rexml
38
- * nokogiri
39
- * libxml
40
+ * count (how many results to retrieve - default to max value 20)
41
+ * start (offset of results - default to 0)
42
+
43
+ ### Traffic History
44
+
45
+ ``` ruby
46
+ client = Alexa::Client.new(access_key_id: "key", secret_access_key: "secret")
47
+ traffic_history = client.traffic_history(url: "site.com")
48
+
49
+ # returns object with `data` method
50
+ ```
51
+
52
+ NOTE: You can specify options:
53
+
54
+ * range (how many days to retrieve - default to max value 31)
55
+ * start (start date - default to range days ago)
56
+
57
+ ### Category Browse
58
+
59
+ ``` ruby
60
+ client = Alexa::Client.new(access_key_id: "key", secret_access_key: "secret")
61
+ category_browse = client.category_browse(path: "Top/Games/Card_Games")
62
+
63
+ # returns object with `categories`, `language_categories`, `related_categories`, `letter_bars` methods.
64
+ ```
40
65
 
41
- Currently alexa wont work with `ox` gem
66
+ NOTE:
42
67
 
43
- ## TODO
68
+ You can find valid paths on [dmoz](http://www.dmoz.org/) site
44
69
 
45
- Support following:
70
+ You can specify options:
46
71
 
47
- * Traffic History
48
- * Category Browse
49
- * Category Listings
50
- * Sites Linking In
72
+ * response_group (any of: categories, related_categories, language_categories, letter_bars)
73
+ * descriptions (include descriptions - boolean, true by default)
74
+
75
+ ### Category Listings
76
+
77
+ ``` ruby
78
+ client = Alexa::Client.new(access_key_id: "key", secret_access_key: "secret")
79
+ category_listings = client.category_listings(path: "Top/Games/Card_Games")
80
+
81
+ # returns object with `recursive_count`, `listings` methods.
82
+ ```
83
+
84
+ NOTE:
85
+
86
+ You can find valid paths on [dmoz](http://www.dmoz.org/) site
87
+
88
+ You can specify options:
89
+
90
+ * sort_by (sort results by one of: popularity, title, average_review)
91
+ * recursive (results for the given category only, or including subcategories - boolean, true by default)
92
+ * count (how many results to retrieve - default to max value 20)
93
+ * start (offset of results - default to 0)
94
+ * descriptions (include descriptions - boolean, true by default)
95
+
96
+ ## Caveats
97
+
98
+ Alexa is using `multi_xml` to parse XML documents. Tested with:
99
+
100
+ * rexml
101
+ * nokogiri
102
+ * libxml
103
+
104
+ Currently alexa will not work with `ox` gem
51
105
 
52
106
  ## Contributors
53
107
 
54
108
  * [rmoriz](https://github.com/rmoriz)
55
109
 
56
110
  ## Continuous Integration
57
- [![Build Status](https://secure.travis-ci.org/morgoth/alexa.png)](http://travis-ci.org/morgoth/alexa)
111
+
112
+ [![Build Status](https://secure.travis-ci.org/morgoth/alexa.png?branch=master)](http://travis-ci.org/morgoth/alexa)
58
113
 
59
114
  ## Copyright
60
115
 
61
- Copyright (c) 2012 Wojciech Wnętrzak. See LICENSE for details.
116
+ Copyright (c) Wojciech Wnętrzak. See LICENSE for details.
data/alexa.gemspec CHANGED
@@ -18,13 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency "multi_xml", ">= 0.5.0"
19
19
 
20
20
  gem.add_development_dependency "mocha"
21
- gem.add_development_dependency "fakeweb"
22
-
23
- gem.post_install_message = %{
24
-
25
- Gem syntax of 0.4 version of this gem will change with backward incompatibilities.
26
- If you don't want to update your code, please specify in your Gemfile:
27
- gem "alexa", "~> 0.3.0"
28
-
29
- }
21
+ gem.add_development_dependency "webmock"
30
22
  end
data/lib/alexa.rb CHANGED
@@ -1,28 +1,17 @@
1
- require "cgi"
2
- require "base64"
3
- require "openssl"
4
- require "digest/sha1"
5
- require "net/https"
6
- require "time"
7
-
8
1
  require "multi_xml"
9
2
 
10
3
  require "alexa/version"
11
- require "alexa/url_info"
4
+ require "alexa/utils"
5
+ require "alexa/exceptions"
6
+ require "alexa/connection"
7
+ require "alexa/client"
8
+ require "alexa/api/category_browse"
9
+ require "alexa/api/category_listings"
10
+ require "alexa/api/sites_linking_in"
11
+ require "alexa/api/traffic_history"
12
+ require "alexa/api/url_info"
12
13
 
13
14
  module Alexa
14
- class << self
15
- attr_accessor :access_key_id, :secret_access_key
16
-
17
- def configure
18
- yield self
19
- end
20
-
21
- def url_info(options = {})
22
- url_info = Alexa::UrlInfo.new(options)
23
- xml = url_info.connect
24
- url_info.parse_xml(xml)
25
- url_info
26
- end
27
- end
15
+ API_VERSION = "2005-07-11"
16
+ API_HOST = "awis.amazonaws.com"
28
17
  end
@@ -0,0 +1,62 @@
1
+ module Alexa::API
2
+ class CategoryBrowse
3
+ include Alexa::Utils
4
+
5
+ DEFAULT_RESPONSE_GROUP = ["categories", "related_categories", "language_categories", "letter_bars"]
6
+
7
+ attr_reader :response_group, :path, :descriptions, :response_body
8
+
9
+ def initialize(credentials)
10
+ @credentials = credentials
11
+ end
12
+
13
+ def fetch(arguments = {})
14
+ @path = arguments[:path] || raise(ArgumentError.new("You must specify path"))
15
+ @response_group = Array(arguments.fetch(:response_group, DEFAULT_RESPONSE_GROUP))
16
+ @descriptions = arguments.fetch(:descriptions, true)
17
+ @response_body = Alexa::Connection.new(@credentials).get(params)
18
+ self
19
+ end
20
+
21
+ # Attributes
22
+
23
+ def categories
24
+ @categories ||= safe_retrieve(parsed_body, "CategoryBrowseResponse", "Response", "CategoryBrowseResult", "Alexa", "CategoryBrowse", "Categories", "Category")
25
+ end
26
+
27
+ def language_categories
28
+ @language_categories ||= safe_retrieve(parsed_body, "CategoryBrowseResponse", "Response", "CategoryBrowseResult", "Alexa", "CategoryBrowse", "LanguageCategories", "Category")
29
+ end
30
+
31
+ def related_categories
32
+ @related_categories ||= safe_retrieve(parsed_body, "CategoryBrowseResponse", "Response", "CategoryBrowseResult", "Alexa", "CategoryBrowse", "RelatedCategories", "Category")
33
+ end
34
+
35
+ def letter_bars
36
+ @letter_bars ||= safe_retrieve(parsed_body, "CategoryBrowseResponse", "Response", "CategoryBrowseResult", "Alexa", "CategoryBrowse", "LetterBars", "Category")
37
+ end
38
+
39
+ private
40
+
41
+ def params
42
+ {
43
+ "Action" => "CategoryBrowse",
44
+ "ResponseGroup" => response_group_param,
45
+ "Path" => path,
46
+ "Descriptions" => descriptions_param
47
+ }
48
+ end
49
+
50
+ def response_group_param
51
+ response_group.sort.map { |group| camelize(group) }.join(",")
52
+ end
53
+
54
+ def descriptions_param
55
+ descriptions.to_s.capitalize
56
+ end
57
+
58
+ def parsed_body
59
+ @parsed_body ||= MultiXml.parse(response_body)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,66 @@
1
+ module Alexa::API
2
+ class CategoryListings
3
+ include Alexa::Utils
4
+
5
+ attr_reader :path, :sort_by, :recursive, :start, :count, :descriptions, :response_body
6
+
7
+ def initialize(credentials)
8
+ @credentials = credentials
9
+ end
10
+
11
+ def fetch(arguments = {})
12
+ @path = arguments[:path] || raise(ArgumentError.new("You must specify path"))
13
+ @sort_by = arguments.fetch(:sort_by, "popularity")
14
+ @recursive = arguments.fetch(:recursive, true)
15
+ @start = arguments.fetch(:start, 0)
16
+ @count = arguments.fetch(:count, 20)
17
+ @descriptions = arguments.fetch(:descriptions, true)
18
+ @response_body = Alexa::Connection.new(@credentials).get(params)
19
+ self
20
+ end
21
+
22
+ # Attributes
23
+
24
+ def recursive_count
25
+ return @recursive_count if defined?(@recursive_count)
26
+ if recursive_count = safe_retrieve(parsed_body, "CategoryListingsResponse", "Response", "CategoryListingsResult", "Alexa", "CategoryListings", "RecursiveCount")
27
+ @recursive_count = recursive_count.to_i
28
+ end
29
+ end
30
+
31
+ def listings
32
+ @listings ||= safe_retrieve(parsed_body, "CategoryListingsResponse", "Response", "CategoryListingsResult", "Alexa", "CategoryListings", "Listings", "Listing")
33
+ end
34
+
35
+ private
36
+
37
+ def params
38
+ {
39
+ "Action" => "CategoryListings",
40
+ "ResponseGroup" => "Listings",
41
+ "Path" => path,
42
+ "Recursive" => recursive_param,
43
+ "Descriptions" => descriptions_param,
44
+ "SortBy" => sort_by_param,
45
+ "Count" => count,
46
+ "Start" => start,
47
+ }
48
+ end
49
+
50
+ def recursive_param
51
+ recursive.to_s.capitalize
52
+ end
53
+
54
+ def descriptions_param
55
+ descriptions.to_s.capitalize
56
+ end
57
+
58
+ def sort_by_param
59
+ camelize(sort_by)
60
+ end
61
+
62
+ def parsed_body
63
+ @parsed_body ||= MultiXml.parse(response_body)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,41 @@
1
+ module Alexa::API
2
+ class SitesLinkingIn
3
+ include Alexa::Utils
4
+
5
+ attr_reader :url, :count, :start, :response_body
6
+
7
+ def initialize(credentials)
8
+ @credentials = credentials
9
+ end
10
+
11
+ def fetch(arguments = {})
12
+ @url = arguments[:url] || raise(ArgumentError.new("You must specify url"))
13
+ @count = arguments.fetch(:count, 20)
14
+ @start = arguments.fetch(:start, 0)
15
+ @response_body = Alexa::Connection.new(@credentials).get(params)
16
+ self
17
+ end
18
+
19
+ # Attributes
20
+
21
+ def sites
22
+ @sites ||= safe_retrieve(parsed_body, "SitesLinkingInResponse", "Response", "SitesLinkingInResult", "Alexa", "SitesLinkingIn", "Site")
23
+ end
24
+
25
+ private
26
+
27
+ def params
28
+ {
29
+ "Action" => "SitesLinkingIn",
30
+ "ResponseGroup" => "SitesLinkingIn",
31
+ "Count" => count,
32
+ "Start" => start,
33
+ "Url" => url
34
+ }
35
+ end
36
+
37
+ def parsed_body
38
+ @parsed_body ||= MultiXml.parse(response_body)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ module Alexa::API
2
+ class TrafficHistory
3
+ include Alexa::Utils
4
+
5
+ attr_reader :url, :range, :start, :response_body
6
+
7
+ def initialize(credentials)
8
+ @credentials = credentials
9
+ end
10
+
11
+ def fetch(arguments = {})
12
+ @url = arguments[:url] || raise(ArgumentError.new("You must specify url"))
13
+ @range = arguments.fetch(:range, 31)
14
+ @start = arguments.fetch(:start) { Time.now - (3600 * 24 * range.to_i) }
15
+ @response_body = Alexa::Connection.new(@credentials).get(params)
16
+ self
17
+ end
18
+
19
+ # Attributes
20
+
21
+ def data
22
+ @data ||= safe_retrieve(parsed_body, "TrafficHistoryResponse", "Response", "TrafficHistoryResult", "Alexa", "TrafficHistory", "HistoricalData", "Data")
23
+ end
24
+
25
+ private
26
+
27
+ def params
28
+ {
29
+ "Action" => "TrafficHistory",
30
+ "ResponseGroup" => "History",
31
+ "Range" => range,
32
+ "Start" => start_param,
33
+ "Url" => url
34
+ }
35
+ end
36
+
37
+ def start_param
38
+ start.respond_to?(:strftime) ? start.strftime("%Y%m%d") : start
39
+ end
40
+
41
+ def parsed_body
42
+ @parsed_body ||= MultiXml.parse(response_body)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,108 @@
1
+ module Alexa::API
2
+ class UrlInfo
3
+ include Alexa::Utils
4
+
5
+ DEFAULT_RESPONSE_GROUP = ["adult_content", "contact_info", "keywords", "language", "links_in_count", "owned_domains", "rank", "rank_by_city", "rank_by_country", "related_links", "site_data", "speed", "usage_stats"]
6
+
7
+ attr_reader :url, :response_group, :response_body
8
+
9
+ def initialize(credentials)
10
+ @credentials = credentials
11
+ end
12
+
13
+ def fetch(arguments = {})
14
+ @url = arguments[:url] || raise(ArgumentError.new("You must specify url"))
15
+ @response_group = Array(arguments.fetch(:response_group, DEFAULT_RESPONSE_GROUP))
16
+ @response_body = Alexa::Connection.new(@credentials).get(params)
17
+ self
18
+ end
19
+
20
+ # attributes
21
+
22
+ def rank
23
+ return @rank if defined?(@rank)
24
+ if rank = safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "TrafficData", "Rank")
25
+ @rank = rank.to_i
26
+ end
27
+ end
28
+
29
+ def rank_by_country
30
+ @rank_by_country ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "TrafficData", "RankByCountry", "Country")
31
+ end
32
+
33
+ def rank_by_city
34
+ @rank_by_city ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "TrafficData", "RankByCity", "City")
35
+ end
36
+
37
+ def data_url
38
+ @data_url ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "TrafficData", "DataUrl", "__content__")
39
+ end
40
+
41
+ def usage_statistics
42
+ @usage_statistics ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "TrafficData", "UsageStatistics", "UsageStatistic")
43
+ end
44
+
45
+ def site_title
46
+ @site_title ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "SiteData", "Title")
47
+ end
48
+
49
+ def site_description
50
+ @site_description ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "SiteData", "Description")
51
+ end
52
+
53
+ def language_locale
54
+ @language_locale ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "Language", "Locale")
55
+ end
56
+
57
+ def language_encoding
58
+ @language_encoding ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "Language", "Encoding")
59
+ end
60
+
61
+ def links_in_count
62
+ return @links_in_count if defined?(@links_in_count)
63
+ if links_in_count = safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "LinksInCount")
64
+ @links_in_count = links_in_count.to_i
65
+ end
66
+ end
67
+
68
+ def keywords
69
+ @keywords ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "Keywords", "Keyword")
70
+ end
71
+
72
+ def speed_median_load_time
73
+ return @speed_median_load_time if defined?(@speed_median_load_time)
74
+ if speed_median_load_time = safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "Speed", "MedianLoadTime")
75
+ @speed_median_load_time = speed_median_load_time.to_i
76
+ end
77
+ end
78
+
79
+ def speed_percentile
80
+ return @speed_percentile if defined?(@speed_percentile)
81
+ if speed_percentile = safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "ContentData", "Speed", "Percentile")
82
+ @speed_percentile = speed_percentile.to_i
83
+ end
84
+ end
85
+
86
+ def related_links
87
+ @related_links ||= safe_retrieve(parsed_body, "UrlInfoResponse", "Response", "UrlInfoResult", "Alexa", "Related", "RelatedLinks", "RelatedLink")
88
+ end
89
+
90
+ private
91
+
92
+ def params
93
+ {
94
+ "Action" => "UrlInfo",
95
+ "ResponseGroup" => response_group_param,
96
+ "Url" => url
97
+ }
98
+ end
99
+
100
+ def response_group_param
101
+ response_group.sort.map { |group| camelize(group) }.join(",")
102
+ end
103
+
104
+ def parsed_body
105
+ @parsed_body ||= MultiXml.parse(response_body)
106
+ end
107
+ end
108
+ end