garb 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ module Garb
2
+ class DataRequest
3
+
4
+ def initialize(base_url, parameters={})
5
+ @base_url = base_url
6
+ @parameters = parameters
7
+ end
8
+
9
+ def query_string
10
+ parameter_list = @parameters.map {|k,v| "#{k}=#{v}" }
11
+ parameter_list.empty? ? '' : "?#{parameter_list.join('&')}"
12
+ end
13
+
14
+ def uri
15
+ URI.parse(@base_url)
16
+ end
17
+
18
+ def send_request
19
+ http = Net::HTTP.new(uri.host, uri.port)
20
+ http.use_ssl = true
21
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
22
+ response = http.get("#{uri.path}#{query_string}", 'Authorization' => "GoogleLogin auth=#{Session.auth_token}")
23
+ raise response.body.inspect unless response.is_a?(Net::HTTPOK)
24
+ response
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ module Garb
2
+ class OAuthSession
3
+ attr_accessor :access_token
4
+
5
+ OAuthGetRequestToken = "https://www.google.com/accounts/OAuthGetRequestToken"
6
+ OAuthAuthorizeToken = "https://www.google.com/accounts/OAuthAuthorizeToken"
7
+ OAuthGetAccessToken = "https://www.google.com/accounts/OAuthGetAccessToken"
8
+
9
+ def get_request_token
10
+
11
+ end
12
+
13
+ def authorization_request
14
+
15
+ end
16
+
17
+ def get_access_token
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ module Garb
2
+ class Profile
3
+
4
+ attr_reader :table_id, :title, :account_name
5
+
6
+ class Property
7
+ include HappyMapper
8
+
9
+ tag 'property'
10
+ namespace 'dxp'
11
+
12
+ attribute :name, String
13
+ attribute :value, String
14
+ end
15
+
16
+ class Entry
17
+ include HappyMapper
18
+
19
+ tag 'entry'
20
+
21
+ element :id, Integer
22
+ element :title, String
23
+ element :tableId, String, :namespace => 'dxp'
24
+
25
+ # has_one :table_id, TableId
26
+ has_many :properties, Property
27
+ end
28
+
29
+ def initialize(entry)
30
+ @title = entry.title
31
+ @table_id = entry.tableId
32
+ @account_name = entry.properties.detect{|p| p.name == 'ga:accountName'}.value
33
+ end
34
+
35
+ def id
36
+ @table_id.sub(/^ga:/, '')
37
+ end
38
+
39
+ def self.all
40
+ url = "https://www.google.com/analytics/feeds/accounts/#{Session.email}"
41
+ response = DataRequest.new(url).send_request
42
+ Entry.parse(response.body).map {|e| Garb::Profile.new(e)}
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ module Garb
2
+ class Report
3
+ include Resource::ResourceMethods
4
+
5
+ MONTH = 2592000
6
+ URL = "https://www.google.com/analytics/feeds/data"
7
+
8
+ def initialize(profile, opts={})
9
+ @profile = profile
10
+
11
+ @start_date = opts.fetch(:start_date, Time.now - MONTH)
12
+ @end_date = opts.fetch(:end_date, Time.now)
13
+ @limit = opts.fetch(:limit, nil)
14
+ @offset = opts.fetch(:offset, nil)
15
+
16
+ # clear filters and sort
17
+ @filters = ReportParameter.new(:filters)
18
+ @sorts = ReportParameter.new(:sort)
19
+
20
+ metrics opts.fetch(:metrics, [])
21
+ dimensions opts.fetch(:dimensions, [])
22
+ filter opts.fetch(:filter, [])
23
+ sort opts.fetch(:sort, [])
24
+ end
25
+
26
+ def results
27
+ ReportResponse.new(send_request_for_body).results
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ module Garb
2
+ class ReportParameter
3
+
4
+ attr_reader :elements
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @elements = []
9
+ end
10
+
11
+ def name
12
+ @name.to_s
13
+ end
14
+
15
+ def <<(element)
16
+ (@elements += [element].flatten).compact!
17
+ self
18
+ end
19
+
20
+ def to_params
21
+ params = self.elements.map do |elem|
22
+ case elem
23
+ when Hash
24
+ elem.collect do |k,v|
25
+ next unless k.is_a?(Operator)
26
+ "#{k.target}#{URI.encode(k.operator.to_s, /[=<>]/)}#{CGI::escape(v.to_s)}"
27
+ end.join(';')
28
+ else
29
+ elem.to_ga
30
+ end
31
+ end.join(',')
32
+
33
+ params.empty? ? {} : {self.name => params}
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ module Garb
2
+ class ReportResponse
3
+ # include Enumerable
4
+
5
+ def initialize(response_body)
6
+ @xml = response_body
7
+ end
8
+
9
+ def parse
10
+ entries = Entry.parse(@xml)
11
+
12
+ @results = entries.collect do |entry|
13
+ hash = {}
14
+
15
+ entry.metrics.each do |m|
16
+ name = m.name.sub(/^ga\:/,'').underscored
17
+ hash.merge!({name => m.value})
18
+ end
19
+
20
+ entry.dimensions.each do |d|
21
+ name = d.name.sub(/^ga\:/,'').underscored
22
+ hash.merge!({name => d.value})
23
+ end
24
+
25
+ OpenStruct.new(hash)
26
+ end
27
+ end
28
+
29
+ def results
30
+ @results || parse
31
+ end
32
+
33
+ class Metric
34
+ include HappyMapper
35
+
36
+ tag 'metric'
37
+ namespace 'dxp'
38
+
39
+ attribute :name, String
40
+ attribute :value, String
41
+ end
42
+
43
+ class Dimension
44
+ include HappyMapper
45
+
46
+ tag 'dimension'
47
+ namespace 'dxp'
48
+
49
+ attribute :name, String
50
+ attribute :value, String
51
+ end
52
+
53
+ class Entry
54
+ include HappyMapper
55
+
56
+ tag 'entry'
57
+
58
+ has_many :metrics, Metric
59
+ has_many :dimensions, Dimension
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,89 @@
1
+ module Garb
2
+ module Resource
3
+ MONTH = 2592000
4
+ URL = "https://www.google.com/analytics/feeds/data"
5
+
6
+ def self.included(report)
7
+ report.extend(ResourceMethods)
8
+ end
9
+
10
+ module ResourceMethods
11
+
12
+ def metrics(*fields)
13
+ @metrics ||= ReportParameter.new(:metrics)
14
+ @metrics << fields
15
+ end
16
+
17
+ def dimensions(*fields)
18
+ @dimensions ||= ReportParameter.new(:dimensions)
19
+ @dimensions << fields
20
+ end
21
+
22
+ def filter(*hash)
23
+ @filters << hash
24
+ end
25
+
26
+ def filters
27
+ @filters ||= ReportParameter.new(:filters)
28
+ end
29
+
30
+ def sort(*fields)
31
+ @sorts << fields
32
+ end
33
+
34
+ def sorts
35
+ @sorts ||= ReportParameter.new(:sort)
36
+ end
37
+
38
+ def results(profile, opts = {}, &block)
39
+ @profile = profile
40
+
41
+ # clear filters and sort
42
+ @filters = ReportParameter.new(:filters)
43
+ @sorts = ReportParameter.new(:sort)
44
+
45
+ @start_date = opts.fetch(:start_date, Time.now - MONTH)
46
+ @end_date = opts.fetch(:end_date, Time.now)
47
+ @limit = opts.fetch(:limit, nil)
48
+ @offset = opts.fetch(:offset, nil)
49
+
50
+ instance_eval(&block) if block_given?
51
+
52
+ ReportResponse.new(send_request_for_body).results
53
+ end
54
+
55
+ def page_params
56
+ {'max-results' => @limit, 'start-index' => @offset}.reject{|k,v| v.nil?}
57
+ end
58
+
59
+ def default_params
60
+ {'ids' => @profile.table_id,
61
+ 'start-date' => format_time(@start_date),
62
+ 'end-date' => format_time(@end_date)}
63
+ end
64
+
65
+ def params
66
+ [
67
+ metrics.to_params,
68
+ dimensions.to_params,
69
+ sorts.to_params,
70
+ filters.to_params,
71
+ page_params
72
+ ].inject(default_params) do |p, i|
73
+ p.merge(i)
74
+ end
75
+ end
76
+
77
+ def format_time(t)
78
+ t.strftime('%Y-%m-%d')
79
+ end
80
+
81
+ def send_request_for_body
82
+ request = DataRequest.new(URL, params)
83
+ response = request.send_request
84
+ response.body
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,19 @@
1
+ module Garb
2
+ class Session
3
+
4
+ def self.login(email, password)
5
+ @email = email
6
+ auth_request = AuthenticationRequest.new(email, password)
7
+ @auth_token = auth_request.auth_token
8
+ end
9
+
10
+ def self.auth_token
11
+ @auth_token
12
+ end
13
+
14
+ def self.email
15
+ @email
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Garb
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 2
6
+ TINY = 1
7
+
8
+ def self.to_s # :nodoc:
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:dxp='http://schemas.google.com/analytics/2009'>
3
+ <id>http://www.google.com/analytics/feeds/accounts/email@example.com</id>
4
+ <updated>2009-03-27T08:14:28.000-07:00</updated>
5
+ <title type='text'>Profile list for email@example.com</title>
6
+ <link rel='self' type='application/atom+xml' href='http://www.google.com/analytics/feeds/accounts/email@example.com'/>
7
+ <author><name>Google Analytics</name></author>
8
+ <generator version='1.0'>Google Analytics</generator>
9
+ <openSearch:totalResults>2</openSearch:totalResults>
10
+ <openSearch:startIndex>1</openSearch:startIndex>
11
+ <openSearch:itemsPerPage>2</openSearch:itemsPerPage>
12
+ <entry>
13
+ <id>http://www.google.com/analytics/feeds/accounts/ga:12345</id>
14
+ <updated>2008-07-21T14:05:57.000-07:00</updated>
15
+ <title type='text'>Historical</title>
16
+ <dxp:tableId>ga:12345</dxp:tableId>
17
+ <dxp:property name='ga:accountId' value='1111'/>
18
+ <dxp:property name='ga:accountName' value='Blog Beta'/>
19
+ <dxp:property name='ga:profileId' value='1212'/>
20
+ <dxp:property name='ga:webPropertyId' value='UA-1111-1'/>
21
+ </entry>
22
+ <entry>
23
+ <id>http://www.google.com/analytics/feeds/accounts/ga:12346</id>
24
+ <updated>2008-11-24T11:51:07.000-08:00</updated>
25
+ <title type='text'>Presently</title>
26
+ <dxp:tableId>ga:12346</dxp:tableId>
27
+ <dxp:property name='ga:accountId' value='1111'/>
28
+ <dxp:property name='ga:accountName' value='Blog Beta'/>
29
+ <dxp:property name='ga:profileId' value='1213'/>
30
+ <dxp:property name='ga:webPropertyId' value='UA-1111-2'/>
31
+ </entry>
32
+ </feed>
33
+
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns='http://www.w3.org/2005/Atom'
3
+ xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
4
+ xmlns:dxp='http://schemas.google.com/dataexport/2009'
5
+ xmlns:ga='http://schemas.google.com/analytics/2008'>
6
+ <id>http://www.google.com/analytics/feeds/data?ids=ga:983247&amp;dimensions=ga:country,ga:city&amp;metrics=ga:pageViews&amp;start-date=2008-01-01&amp;end-date=2008-01-02</id>
7
+ <updated>2008-01-02T15:59:59.999-08:00 </updated>
8
+ <title type="text">Google Analytics Data for Profile 983247</title>
9
+ <link href="http://www.google.com/analytics/feeds/data" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
10
+ <link href="http://www.google.com/analytics/feeds/data?end-date=2008-01-02&amp;start-date=2008-01-01&amp;metrics=ga%3ApageViews&amp;ids=ga%3A983247&amp;dimensions=ga%3Acountry%2Cga%3Acity" rel="self" type="application/atom+xml"/>
11
+ <link href="http://www.google.com/analytics/feeds/data?start-index=1001&amp;max-results=1000&amp;end-date=2008-01-02&amp;start-date=2008-01-01&amp;metrics=ga%3ApageViews&amp;ids=ga%3A983247&amp;dimensions=ga%3Acountry%2Cga%3Acity" rel="next" type="application/atom+xml"/>
12
+ <author>
13
+ <name>Google Analytics</name>
14
+ </author>
15
+ <openSearch:startIndex>3</openSearch:startIndex>
16
+ <openSearch:itemsPerPage>4</openSearch:itemsPerPage>
17
+ <ga:webPropertyID>UA-983247-67</ga:webPropertyID>
18
+ <ga:start-date>2008-01-01</ga:start-date>
19
+ <ga:end-date>2008-01-02</ga:end-date>
20
+
21
+ <entry>
22
+ <id> http://www.google.com/analytics/feeds/data?ids=ga:1174&amp;ga:country=%28not%20set%29&amp;ga:city=%28not%20set%29&amp;start-date=2008-01-01&amp;end-date=2008-01-02 </id>
23
+ <updated> 2008-01-01T16:00:00.001-08:00 </updated>
24
+ <title type="text"> ga:country=(not set) | ga:city=(not set) </title>
25
+ <link href="http://www.google.com/analytics/feeds/data" rel="self" type="application/atom+xml"/>
26
+ <dxp:dimension name="ga:country" value="(not set)" />
27
+ <dxp:dimension name="ga:city" value="(not set)" />
28
+ <dxp:metric name="ga:pageviews" value="33" />
29
+ </entry>
30
+ <entry>
31
+ <id> http://www.google.com/analytics/feeds/data?ids=ga:1174&amp;ga:country=Afghanistan&amp;ga:city=Kabul&amp;start-date=2008-01-01&amp;end-date=2008-01-02 </id>
32
+ <updated> 2008-01-01T16:00:00.001-08:00 </updated>
33
+ <title type="text"> ga:country=Afghanistan | ga:city=Kabul </title>
34
+ <dxp:dimension name="ga:country" value="Afghanistan" />
35
+ <dxp:dimension name="ga:city" value="Kabul" />
36
+ <dxp:metric name="ga:pageviews" value="2" />
37
+ </entry>
38
+ <entry>
39
+ <id> http://www.google.com/analytics/feeds/data?ids=ga:1174&amp;ga:country=Albania&amp;ga:city=Tirana&amp;start-date=2008-01-01&amp;end-date=2008-01-02 </id>
40
+ <updated> 2008-01-01T16:00:00.001-08:00 </updated>
41
+ <title type="text"> ga:country=Albania | ga:city=Tirana </title>
42
+ <dxp:dimension name="ga:country" value="Albania" />
43
+ <dxp:dimension name="ga:city" value="Tirana" />
44
+ <dxp:metric name="ga:pageviews" value="1" />
45
+ </entry>
46
+ </feed>
@@ -0,0 +1,16 @@
1
+ $:.reject! { |e| e.include? 'TextMate' }
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'shoulda'
6
+ require 'mocha'
7
+
8
+ require File.dirname(__FILE__) + '/../lib/garb'
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ def read_fixture(filename)
13
+ File.read(File.dirname(__FILE__) + "/fixtures/#{filename}")
14
+ end
15
+
16
+ end