jonuts-garb 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,47 @@
1
+ module Garb
2
+ class Profile
3
+
4
+ attr_reader :table_id, :title, :account_name, :email
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, email=nil)
30
+ @email = Session.email(email)
31
+ @title = entry.title
32
+ @table_id = entry.tableId
33
+ @account_name = entry.properties.detect{|p| p.name == 'ga:accountName'}.value
34
+ end
35
+
36
+ def id
37
+ @table_id.sub(/^ga:/, '')
38
+ end
39
+
40
+ def self.all(email=nil)
41
+ email = Session.email(email)
42
+ url = "https://www.google.com/analytics/feeds/accounts/#{email}"
43
+ response = DataRequest.new(url).send_request(email)
44
+ Entry.parse(response.body).map {|e| Garb::Profile.new(e, email)}
45
+ end
46
+ end
47
+ 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(@profile.email)).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(profile.email)).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(email)
82
+ request = DataRequest.new(URL, params)
83
+ response = request.send_request(email)
84
+ response.body
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,51 @@
1
+ module Garb
2
+ class Session
3
+ class << self; attr_reader :sessions end
4
+
5
+ @sessions ||= []
6
+
7
+ def self.login(email, password, opts={})
8
+ auth_request = AuthenticationRequest.new(email, password)
9
+ creds = { :email => email, :auth_token => auth_request.auth_token(opts) }
10
+ update_or_create(creds)
11
+ end
12
+
13
+ def self.auth_token(email=nil)
14
+ email ? find_session(email).auth_token : default.auth_token
15
+ end
16
+
17
+ def self.email(email=nil)
18
+ email || default.email
19
+ end
20
+
21
+ def self.find_session(email)
22
+ @sessions.find {|session| session.email == email}
23
+ end
24
+
25
+ def self.default
26
+ @sessions.first
27
+ end
28
+
29
+ def self.update_or_create(creds)
30
+ if session = find_session(creds[:email])
31
+ session.auth_token = creds[:auth_token]
32
+ else
33
+ @sessions << session = new(creds)
34
+ end
35
+ session
36
+ end
37
+
38
+ def initialize(creds={})
39
+ @email = creds[:email]
40
+ @auth_token = creds[:auth_token]
41
+ end
42
+
43
+ attr_accessor :auth_token
44
+ attr_reader :email
45
+
46
+ def profiles
47
+ Profile.all(@email)
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ module Garb
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 2
6
+ TINY = 3
7
+
8
+ def self.to_s # :nodoc:
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
data/lib/garb.rb ADDED
@@ -0,0 +1,70 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'rubygems'
6
+ require 'cgi'
7
+ require 'ostruct'
8
+ require 'happymapper'
9
+
10
+ require 'garb/version'
11
+ require 'garb/authentication_request'
12
+ require 'garb/data_request'
13
+ require 'garb/session'
14
+ require 'garb/profile'
15
+ require 'garb/report_parameter'
16
+ require 'garb/report_response'
17
+ require 'garb/resource'
18
+ require 'garb/report'
19
+
20
+ require 'extensions/string'
21
+ require 'extensions/operator'
22
+ require 'extensions/symbol'
23
+ require 'extensions/happymapper'
24
+
25
+ module Garb
26
+ # :stopdoc:
27
+ GA = "http://schemas.google.com/analytics/2008"
28
+
29
+ VERSION = '0.1.2'
30
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
31
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
32
+ # :startdoc:
33
+
34
+ # Returns the version string for the library.
35
+ #
36
+ def self.version
37
+ VERSION
38
+ end
39
+
40
+ # Returns the library path for the module. If any arguments are given,
41
+ # they will be joined to the end of the libray path using
42
+ # <tt>File.join</tt>.
43
+ #
44
+ def self.libpath( *args )
45
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
46
+ end
47
+
48
+ # Returns the lpath for the module. If any arguments are given,
49
+ # they will be joined to the end of the path using
50
+ # <tt>File.join</tt>.
51
+ #
52
+ def self.path( *args )
53
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
54
+ end
55
+
56
+ # Utility method used to rquire all files ending in .rb that lie in the
57
+ # directory below this file that has the same name as the filename passed
58
+ # in. Optionally, a specific _directory_ name can be passed in such that
59
+ # the _filename_ does not have to be equivalent to the directory.
60
+ #
61
+ def self.require_all_libs_relative_to( fname, dir = nil )
62
+ dir ||= ::File.basename(fname, '.*')
63
+ search_me = ::File.expand_path(
64
+ ::File.join(::File.dirname(fname), dir, '*', '*.rb'))
65
+
66
+ Dir.glob(search_me).sort.each {|rb| require rb}
67
+ end
68
+ end # module Garb
69
+
70
+ # EOF
@@ -0,0 +1,67 @@
1
+ ##
2
+ ## cacert.pem-foo -- Bundle of CA Root Certificates
3
+ ##
4
+ ## Converted at: Thu Mar 26 21:23:06 2009 UTC
5
+ ##
6
+ ## This is a bundle of X.509 certificates of public Certificate Authorities
7
+ ## (CA). These were automatically extracted from Mozilla's root certificates
8
+ ## file (certdata.txt). This file can be found in the mozilla source tree:
9
+ ## '/mozilla/security/nss/lib/ckfw/builtins/certdata.txt'
10
+ ##
11
+ ## It contains the certificates in PEM format and therefore
12
+ ## can be directly used with curl / libcurl / php_curl, or with
13
+ ## an Apache+mod_ssl webserver for SSL client authentication.
14
+ ## Just configure this file as the SSLCACertificateFile.
15
+ ##
16
+
17
+ # ***** BEGIN LICENSE BLOCK *****
18
+ # Version: MPL 1.1/GPL 2.0/LGPL 2.1
19
+ #
20
+ # The contents of this file are subject to the Mozilla Public License Version
21
+ # 1.1 (the "License"); you may not use this file except in compliance with
22
+ # the License. You may obtain a copy of the License at
23
+ # http://www.mozilla.org/MPL/
24
+ #
25
+ # Software distributed under the License is distributed on an "AS IS" basis,
26
+ # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
27
+ # for the specific language governing rights and limitations under the
28
+ # License.
29
+ #
30
+ # The Original Code is the Netscape security libraries.
31
+ #
32
+ # The Initial Developer of the Original Code is
33
+ # Netscape Communications Corporation.
34
+ # Portions created by the Initial Developer are Copyright (C) 1994-2000
35
+ # the Initial Developer. All Rights Reserved.
36
+ #
37
+ # Contributor(s):
38
+ #
39
+ # Alternatively, the contents of this file may be used under the terms of
40
+ # either the GNU General Public License Version 2 or later (the "GPL"), or
41
+ # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
42
+ # in which case the provisions of the GPL or the LGPL are applicable instead
43
+ # of those above. If you wish to allow use of your version of this file only
44
+ # under the terms of either the GPL or the LGPL, and not to allow others to
45
+ # use your version of this file under the terms of the MPL, indicate your
46
+ # decision by deleting the provisions above and replace them with the notice
47
+ # and other provisions required by the GPL or the LGPL. If you do not delete
48
+ # the provisions above, a recipient may use your version of this file under
49
+ # the terms of any one of the MPL, the GPL or the LGPL.
50
+ #
51
+ # ***** END LICENSE BLOCK *****
52
+ # @(#) $RCSfile: certdata.txt,v $ $Revision: 1.51 $ $Date: 2009/01/15 22:35:15 $
53
+
54
+ Verisign/RSA Secure Server CA
55
+ =============================
56
+ -----BEGIN CERTIFICATE-----
57
+ MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
58
+ IDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy
59
+ IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVow
60
+ XzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQL
61
+ EyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUA
62
+ A4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1Xp
63
+ sSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJ
64
+ VCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw4jrg7HFG
65
+ mhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2
66
+ qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
67
+ -----END CERTIFICATE-----