ralexa 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -41,19 +41,20 @@ session = Ralexa.session("aws_access_key_id", "aws_secret_access_key")
41
41
 
42
42
  # all countries
43
43
  countries = session.top_sites.list_countries
44
+ p countries.map(&:name)
44
45
 
45
- # global top sites
46
- global = session.top_sites.global
46
+ # global top 250 sites
47
+ global = session.top_sites.global(250)
47
48
 
48
49
  # per-country top sites
49
50
  first_by_country = {}
50
51
  countries.each do |c|
51
- first_by_country[c.name] = session.top_sites.country(c.code).first.url
52
+ first_by_country[c.name] = session.top_sites.country(c.code, 1).first.url
52
53
  end
53
54
 
54
55
  # individual country lookup
55
- puts "Top Australian Sites"
56
- session.top_sites.country("AU").each do |s|
56
+ puts "Top Ten Australian Sites"
57
+ session.top_sites.country("AU", 10).each do |s|
57
58
  puts "#{s.url} (#{s.page_views} pageviews)"
58
59
  end
59
60
 
@@ -0,0 +1,41 @@
1
+ module Ralexa
2
+ class AbstractService
3
+
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ private
9
+
10
+ # A lazy collection which fetches records on demand.
11
+ def collection(*params, &parser)
12
+ LazyCollection.new(
13
+ @client,
14
+ host,
15
+ path,
16
+ merged_params(*params),
17
+ &parser
18
+ )
19
+ end
20
+
21
+ def paginating_collection(limit, per_page, *params, &parser)
22
+ PaginatingCollection.new(
23
+ @client,
24
+ host,
25
+ path,
26
+ merged_params(*params),
27
+ limit,
28
+ per_page,
29
+ &parser
30
+ )
31
+ end
32
+
33
+ # A hash of the provided params hashes merged into the default_params.
34
+ def merged_params(*params)
35
+ params.reduce(default_params) do |merged, params|
36
+ merged.merge(params)
37
+ end
38
+ end
39
+
40
+ end
41
+ end
data/lib/ralexa/client.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require "addressable/uri"
2
2
  require "net/http"
3
3
 
4
- require "ralexa/uri_signer"
5
-
6
4
  module Ralexa
7
5
  class Client
8
6
 
@@ -0,0 +1,35 @@
1
+ require "nokogiri"
2
+
3
+ module Ralexa
4
+ class LazyCollection
5
+
6
+ include Enumerable
7
+
8
+ def initialize(client, host, path, parameters, &parser)
9
+ @client = client
10
+ @host = host
11
+ @path = path
12
+ @parameters = parameters
13
+ @parser = parser
14
+ end
15
+
16
+ def each
17
+ parse(fetch(@parameters)).each do |item|
18
+ yield item
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def fetch(parameters)
25
+ @client.get(@host, @path, parameters)
26
+ end
27
+
28
+ def parse(response_body)
29
+ @parser.call(
30
+ Nokogiri::XML.parse(response_body).remove_namespaces!
31
+ )
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ module Ralexa
2
+ class PaginatingCollection < LazyCollection
3
+
4
+ def initialize(client, host, path, parameters, limit, per_page, &parser)
5
+ validate_parameters(parameters)
6
+ super(client, host, path, parameters, &parser)
7
+ @limit = limit
8
+ @per_page = per_page
9
+ end
10
+
11
+ def each
12
+ Paginator.new(@per_page, @limit).pages.each do |page|
13
+ parse(fetch(parameters(page))).each do |item|
14
+ yield item
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def parameters(page)
22
+ @parameters.merge("Start" => page.start, "Count" => page.count)
23
+ end
24
+
25
+ def validate_parameters(parameters)
26
+ parameters.keys.each do |k|
27
+ if %w{start count}.include?(k.to_s.downcase)
28
+ raise Error,
29
+ "Limit & Count must not be specified for PaginatingCollection"
30
+ end
31
+ end
32
+ end
33
+
34
+ Error = Class.new(StandardError)
35
+ end
36
+ end
@@ -0,0 +1,57 @@
1
+ module Ralexa
2
+ class Paginator
3
+
4
+ def initialize(per_page, items)
5
+ @per_page = per_page
6
+ @items = items
7
+ end
8
+
9
+ def pages
10
+ page_count.times.map do |i|
11
+ Page.new(page_count, @per_page, @items, i)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def page_count
18
+ Rational(@items, @per_page).ceil
19
+ end
20
+
21
+ class Page
22
+
23
+ def initialize(page_count, per_page, items, index)
24
+ @page_count = page_count
25
+ @per_page = per_page
26
+ @items = items
27
+ @index = index
28
+ end
29
+
30
+ def number
31
+ @index + 1
32
+ end
33
+
34
+ def start
35
+ (@index * @per_page) + 1
36
+ end
37
+
38
+ def finish
39
+ start + count - 1
40
+ end
41
+
42
+ def count
43
+ if full? then @per_page else @items % @per_page end
44
+ end
45
+
46
+ def full?
47
+ number < @page_count || @items % @per_page == 0
48
+ end
49
+
50
+ def partial?
51
+ !full?
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -1,6 +1,3 @@
1
- require "ralexa/client"
2
- require "ralexa/top_sites"
3
-
4
1
  module Ralexa
5
2
  class Session
6
3
 
@@ -1,37 +1,43 @@
1
- require "ralexa/abstract_xml_service"
2
-
3
1
  module Ralexa
4
- class TopSites < AbstractXmlService
2
+ class TopSites < AbstractService
3
+
4
+ PER_PAGE = 100
5
5
 
6
6
  # A global list of top sites.
7
- def global(params = {})
8
- top_sites_from_document(dispatch(
7
+ def global(limit, params = {})
8
+ paginating_collection(
9
+ limit,
10
+ PER_PAGE,
9
11
  {"ResponseGroup" => "Country"},
10
- params
11
- ))
12
+ params,
13
+ &top_sites_parser
14
+ )
12
15
  end
13
16
 
14
17
  # Top sites for the specified two letter country code.
15
- def country(code, params = {})
16
- top_sites_from_document(dispatch(
18
+ def country(code, limit, params = {})
19
+ paginating_collection(
20
+ limit,
21
+ PER_PAGE,
17
22
  {"ResponseGroup" => "Country", "CountryCode" => code.to_s.upcase},
18
- params
19
- ))
23
+ params,
24
+ &top_sites_parser
25
+ )
20
26
  end
21
27
 
22
28
  # All countries that have Alexa top sites.
23
29
  def list_countries(params = {})
24
- dispatch(
25
- {"ResponseGroup" => "ListCountries"},
26
- params
27
- ).at("//TopSitesResult/Alexa/TopSites/Countries").elements.map do |node|
28
- Country.new(
29
- node.at("Name").text,
30
- node.at("Code").text,
31
- node.at("TotalSites").text.to_i,
32
- node.at("PageViews").text.to_f * 1_000_000,
33
- node.at("Users").text.to_f * 1_000_000,
34
- )
30
+ collection({"ResponseGroup" => "ListCountries"}, params) do |document|
31
+ path = "//TopSitesResult/Alexa/TopSites/Countries"
32
+ document.at(path).elements.map do |node|
33
+ Country.new(
34
+ node.at("Name").text,
35
+ node.at("Code").text,
36
+ node.at("TotalSites").text.to_i,
37
+ node.at("PageViews").text.to_f * 1_000_000,
38
+ node.at("Users").text.to_f * 1_000_000,
39
+ )
40
+ end
35
41
  end
36
42
  end
37
43
 
@@ -41,16 +47,18 @@ module Ralexa
41
47
  def path; "/" end
42
48
  def default_params; {"Action" => "TopSites"} end
43
49
 
44
- def top_sites_from_document(document)
45
- document.at("//TopSites/Country/Sites").elements.map do |node|
46
- Site.new(
47
- node.at("DataUrl").text,
48
- node.at("Country/Rank").text.to_i,
49
- node.at("Country/Reach/PerMillion").text.to_i * 1_000_000,
50
- (node.at("Country/PageViews/PerMillion").text.to_f * 1_000_000).to_i,
51
- node.at("Country/PageViews/PerUser").text.to_f
52
- )
53
- end
50
+ def top_sites_parser
51
+ ->(document){
52
+ document.at("//TopSites/Country/Sites").elements.map do |node|
53
+ Site.new(
54
+ node.at("DataUrl").text,
55
+ node.at("Country/Rank").text.to_i,
56
+ node.at("Country/Reach/PerMillion").text.to_i * 1_000_000,
57
+ (node.at("Country/PageViews/PerMillion").text.to_f * 1_000_000).to_i,
58
+ node.at("Country/PageViews/PerUser").text.to_f
59
+ )
60
+ end
61
+ }
54
62
  end
55
63
 
56
64
  Country = Struct.new(:name, :code, :total_sites, :page_views, :users)
@@ -2,8 +2,6 @@ require "base64"
2
2
  require "digest/sha2"
3
3
  require "openssl"
4
4
 
5
- require "ralexa/canonicalized_query_string"
6
-
7
5
  module Ralexa
8
6
  class UriSigner
9
7
 
@@ -1,3 +1,3 @@
1
1
  module Ralexa
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/ralexa.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  %w{
2
- abstract_xml_service
2
+ abstract_service
3
3
  canonicalized_query_string
4
4
  client
5
+ lazy_collection
6
+ paginating_collection
7
+ paginator
5
8
  session
6
9
  top_sites
7
10
  uri_signer
@@ -2,8 +2,6 @@
2
2
 
3
3
  require_relative "spec_helper"
4
4
 
5
- require "ralexa/canonicalized_query_string"
6
-
7
5
  module Ralexa
8
6
  describe CanonicalizedQueryString do
9
7
 
data/spec/client_spec.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  require_relative "spec_helper"
2
2
 
3
- require "ralexa/client"
4
-
5
3
  module Ralexa
6
4
  describe Client do
7
5