garb-authsub 0.7.0
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 +250 -0
- data/Rakefile +56 -0
- data/lib/garb.rb +38 -0
- data/lib/garb/account.rb +29 -0
- data/lib/garb/authentication_request.rb +53 -0
- data/lib/garb/data_request.rb +51 -0
- data/lib/garb/filter_parameters.rb +37 -0
- data/lib/garb/profile.rb +57 -0
- data/lib/garb/profile_reports.rb +15 -0
- data/lib/garb/report.rb +26 -0
- data/lib/garb/report_parameter.rb +25 -0
- data/lib/garb/report_response.rb +62 -0
- data/lib/garb/reports.rb +5 -0
- data/lib/garb/reports/bounces.rb +5 -0
- data/lib/garb/reports/exits.rb +5 -0
- data/lib/garb/reports/pageviews.rb +5 -0
- data/lib/garb/reports/unique_pageviews.rb +5 -0
- data/lib/garb/reports/visits.rb +5 -0
- data/lib/garb/resource.rb +92 -0
- data/lib/garb/session.rb +29 -0
- data/lib/garb/version.rb +13 -0
- data/lib/support.rb +39 -0
- data/test/fixtures/cacert.pem +67 -0
- data/test/fixtures/profile_feed.xml +40 -0
- data/test/fixtures/report_feed.xml +46 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/garb/account_test.rb +53 -0
- data/test/unit/garb/authentication_request_test.rb +121 -0
- data/test/unit/garb/data_request_test.rb +106 -0
- data/test/unit/garb/filter_parameters_test.rb +57 -0
- data/test/unit/garb/oauth_session_test.rb +11 -0
- data/test/unit/garb/profile_reports_test.rb +29 -0
- data/test/unit/garb/profile_test.rb +87 -0
- data/test/unit/garb/report_parameter_test.rb +43 -0
- data/test/unit/garb/report_response_test.rb +29 -0
- data/test/unit/garb/report_test.rb +91 -0
- data/test/unit/garb/resource_test.rb +38 -0
- data/test/unit/garb/session_test.rb +84 -0
- data/test/unit/garb_test.rb +14 -0
- data/test/unit/symbol_operator_test.rb +37 -0
- metadata +131 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Garb
|
2
|
+
class FilterParameters
|
3
|
+
def self.define_operators(*methods)
|
4
|
+
methods.each do |method|
|
5
|
+
class_eval <<-CODE
|
6
|
+
def #{method}(field, value)
|
7
|
+
self.parameters << {SymbolOperator.new(field, :#{method}) => value}
|
8
|
+
end
|
9
|
+
CODE
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
define_operators :eql, :not_eql, :gt, :gte, :lt, :lte, :matches,
|
14
|
+
:does_not_match, :contains, :does_not_contain, :substring, :not_substring
|
15
|
+
|
16
|
+
attr_accessor :parameters
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
self.parameters = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def filters(&block)
|
23
|
+
instance_eval &block
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_params
|
27
|
+
value = self.parameters.map do |param|
|
28
|
+
param.map do |k,v|
|
29
|
+
next unless k.is_a?(SymbolOperator)
|
30
|
+
"#{URI.encode(k.to_google_analytics, /[=<>]/)}#{CGI::escape(v.to_s)}"
|
31
|
+
end.join(',') # Hash AND
|
32
|
+
end.join(';') # Array OR
|
33
|
+
|
34
|
+
value.empty? ? {} : {'filters' => value}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/garb/profile.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Garb
|
2
|
+
class Profile
|
3
|
+
|
4
|
+
include ProfileReports
|
5
|
+
|
6
|
+
attr_reader :session, :table_id, :title, :account_name, :account_id, :web_property_id
|
7
|
+
|
8
|
+
class Property
|
9
|
+
include HappyMapper
|
10
|
+
|
11
|
+
tag 'property'
|
12
|
+
namespace 'http://schemas.google.com/analytics/2009'
|
13
|
+
|
14
|
+
attribute :name, String
|
15
|
+
attribute :value, String
|
16
|
+
|
17
|
+
def instance_name
|
18
|
+
Garb.from_google_analytics(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Entry
|
23
|
+
include HappyMapper
|
24
|
+
|
25
|
+
tag 'entry'
|
26
|
+
|
27
|
+
element :title, String
|
28
|
+
element :tableId, String, :namespace => 'http://schemas.google.com/analytics/2009'
|
29
|
+
|
30
|
+
has_many :properties, Property
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(entry, session)
|
34
|
+
@session = session
|
35
|
+
@title = entry.title
|
36
|
+
@table_id = entry.tableId
|
37
|
+
|
38
|
+
entry.properties.each do |p|
|
39
|
+
instance_variable_set :"@#{p.instance_name}", p.value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def id
|
44
|
+
Garb.from_google_analytics(@table_id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.all(session = Session)
|
48
|
+
url = "https://www.google.com/analytics/feeds/accounts/default"
|
49
|
+
response = DataRequest.new(session, url).send_request
|
50
|
+
Entry.parse(response.body).map {|entry| new(entry, session)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.first(id, session = Session)
|
54
|
+
all(session).detect {|profile| profile.id == id || profile.web_property_id == id }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Garb
|
2
|
+
module ProfileReports
|
3
|
+
def self.add_report_method(klass)
|
4
|
+
# demodulize leaves potential to redefine
|
5
|
+
# these methods given different namespaces
|
6
|
+
method_name = klass.to_s.demodulize.underscore
|
7
|
+
|
8
|
+
class_eval <<-CODE
|
9
|
+
def #{method_name}(opts = {}, &block)
|
10
|
+
#{klass}.results(self, opts, &block)
|
11
|
+
end
|
12
|
+
CODE
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/garb/report.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Garb
|
2
|
+
class Report
|
3
|
+
include Resource
|
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
|
+
metrics opts.fetch(:metrics, [])
|
17
|
+
dimensions opts.fetch(:dimensions, [])
|
18
|
+
sort opts.fetch(:sort, [])
|
19
|
+
end
|
20
|
+
|
21
|
+
def results
|
22
|
+
ReportResponse.new(send_request_for_body).results
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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
|
+
value = self.elements.map{|param| Garb.to_google_analytics(param)}.join(',')
|
22
|
+
value.empty? ? {} : {self.name => value}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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\:/,'').underscore
|
17
|
+
hash.merge!({name => m.value})
|
18
|
+
end
|
19
|
+
|
20
|
+
entry.dimensions.each do |d|
|
21
|
+
name = d.name.sub(/^ga\:/,'').underscore
|
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 'http://schemas.google.com/analytics/2009'
|
38
|
+
|
39
|
+
attribute :name, String
|
40
|
+
attribute :value, String
|
41
|
+
end
|
42
|
+
|
43
|
+
class Dimension
|
44
|
+
include HappyMapper
|
45
|
+
|
46
|
+
tag 'dimension'
|
47
|
+
namespace 'http://schemas.google.com/analytics/2009'
|
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
|
data/lib/garb/reports.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Garb
|
2
|
+
module Resource
|
3
|
+
MONTH = 2592000
|
4
|
+
URL = "https://www.google.com/analytics/feeds/data"
|
5
|
+
|
6
|
+
def self.extended(base)
|
7
|
+
# define a method on a module that gets included into profile
|
8
|
+
# Exits would make:
|
9
|
+
# to enable profile.exits(options_hash, &block)
|
10
|
+
# returns Exits.results(self, options_hash, &block)
|
11
|
+
# every class defined which extends Resource will add to the module
|
12
|
+
ProfileReports.add_report_method(base)
|
13
|
+
end
|
14
|
+
|
15
|
+
%w(metrics dimensions sort).each do |parameter|
|
16
|
+
class_eval <<-CODE
|
17
|
+
def #{parameter}(*fields)
|
18
|
+
@#{parameter} ||= ReportParameter.new(:#{parameter})
|
19
|
+
@#{parameter} << fields
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear_#{parameter}
|
23
|
+
@#{parameter} = ReportParameter.new(:#{parameter})
|
24
|
+
end
|
25
|
+
CODE
|
26
|
+
end
|
27
|
+
|
28
|
+
def filters(*hashes, &block)
|
29
|
+
@filter_parameters ||= FilterParameters.new
|
30
|
+
|
31
|
+
hashes.each do |hash|
|
32
|
+
@filter_parameters.parameters << hash
|
33
|
+
end
|
34
|
+
|
35
|
+
@filter_parameters.filters(&block) if block_given?
|
36
|
+
@filter_parameters
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear_filters
|
40
|
+
@filter_parameters = FilterParameters.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def results(profile, opts = {}, &block)
|
44
|
+
@profile = profile.is_a?(Profile) ? profile : Profile.first(profile, opts.fetch(:session, Session))
|
45
|
+
|
46
|
+
if @profile
|
47
|
+
@start_date = opts.fetch(:start_date, Time.now - MONTH)
|
48
|
+
@end_date = opts.fetch(:end_date, Time.now)
|
49
|
+
@limit = opts.fetch(:limit, nil)
|
50
|
+
@offset = opts.fetch(:offset, nil)
|
51
|
+
|
52
|
+
instance_eval(&block) if block_given?
|
53
|
+
|
54
|
+
ReportResponse.new(send_request_for_body).results
|
55
|
+
else
|
56
|
+
[]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def page_params
|
61
|
+
{'max-results' => @limit, 'start-index' => @offset}.reject{|k,v| v.nil?}
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_params
|
65
|
+
{'ids' => @profile.table_id,
|
66
|
+
'start-date' => format_time(@start_date),
|
67
|
+
'end-date' => format_time(@end_date)}
|
68
|
+
end
|
69
|
+
|
70
|
+
def params
|
71
|
+
[
|
72
|
+
metrics.to_params,
|
73
|
+
dimensions.to_params,
|
74
|
+
sort.to_params,
|
75
|
+
filters.to_params,
|
76
|
+
page_params
|
77
|
+
].inject(default_params) do |p, i|
|
78
|
+
p.merge(i)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def format_time(t)
|
83
|
+
t.strftime('%Y-%m-%d')
|
84
|
+
end
|
85
|
+
|
86
|
+
def send_request_for_body
|
87
|
+
request = DataRequest.new(@profile.session, URL, params)
|
88
|
+
response = request.send_request
|
89
|
+
response.body
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/garb/session.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Garb
|
2
|
+
class Session
|
3
|
+
module Methods
|
4
|
+
attr_accessor :auth_token, :access_token, :authsub_token, :email
|
5
|
+
|
6
|
+
# use only for single user authentication
|
7
|
+
def login(email, password, opts={})
|
8
|
+
self.email = email
|
9
|
+
auth_request = AuthenticationRequest.new(email, password, opts)
|
10
|
+
self.auth_token = auth_request.auth_token(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def single_user?
|
14
|
+
auth_token && auth_token.is_a?(String)
|
15
|
+
end
|
16
|
+
|
17
|
+
def oauth_user?
|
18
|
+
!access_token.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
def authsub_user?
|
22
|
+
!authsub_token.nil?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include Methods
|
27
|
+
extend Methods
|
28
|
+
end
|
29
|
+
end
|
data/lib/garb/version.rb
ADDED
data/lib/support.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class SymbolOperator
|
2
|
+
def initialize(field, operator)
|
3
|
+
@field, @operator = field, operator
|
4
|
+
end unless method_defined?(:initialize)
|
5
|
+
|
6
|
+
def to_google_analytics
|
7
|
+
operators = {
|
8
|
+
:eql => '==',
|
9
|
+
:not_eql => '!=',
|
10
|
+
:gt => '>',
|
11
|
+
:gte => '>=',
|
12
|
+
:lt => '<',
|
13
|
+
:lte => '<=',
|
14
|
+
:matches => '==',
|
15
|
+
:does_not_match => '!=',
|
16
|
+
:contains => '=~',
|
17
|
+
:does_not_contain => '!~',
|
18
|
+
:substring => '=@',
|
19
|
+
:not_substring => '!@',
|
20
|
+
:desc => '-'
|
21
|
+
}
|
22
|
+
|
23
|
+
target = Garb.to_google_analytics(@field)
|
24
|
+
operator = operators[@operator]
|
25
|
+
|
26
|
+
@operator == :desc ? "#{operator}#{target}" : "#{target}#{operator}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Symbol
|
31
|
+
[:eql, :not_eql, :gt, :gte, :lt, :lte, :desc,
|
32
|
+
:matches, :does_not_match, :contains, :does_not_contain,
|
33
|
+
:substring, :not_substring].each do |operator|
|
34
|
+
|
35
|
+
define_method(operator) do
|
36
|
+
SymbolOperator.new(self, operator)
|
37
|
+
end unless method_defined?(operator)
|
38
|
+
end
|
39
|
+
end
|