ralexa 0.0.2 → 0.0.3

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/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