garb-reporter 0.0.3 → 0.0.4
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/.gitignore +1 -0
- data/README.md +130 -0
- data/lib/garb-reporter.rb +2 -2
- data/lib/garb-reporter/version.rb +1 -1
- data/spec/garb_reporter_spec.rb +43 -1
- data/spec/spec_helper.rb +1 -1
- metadata +8 -8
- data/README +0 -1
- data/vcr_cassettes/garb_authentication.yml +0 -38
- data/vcr_cassettes/get_profile.yml +0 -40
data/.gitignore
CHANGED
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
Garb-Reporter
|
2
|
+
-------------
|
3
|
+
|
4
|
+
https://github.com/stuliston/garb-reporter
|
5
|
+
|
6
|
+
Description
|
7
|
+
-----------
|
8
|
+
|
9
|
+
Small wrapper to compliment the excellent Garb gem (http://github.com/vigetlabs/garb). Please have a glance over their documentation as it covers some imprtant Google Analytics stuff too.
|
10
|
+
|
11
|
+
Background
|
12
|
+
----------
|
13
|
+
|
14
|
+
Traditionally with Garb, you'll create a class for every report that you want. So a report that pulls back
|
15
|
+
visits might look like this:
|
16
|
+
|
17
|
+
class Visits
|
18
|
+
extend Garb::Model
|
19
|
+
|
20
|
+
metrics :visits
|
21
|
+
end
|
22
|
+
|
23
|
+
and one that gets visits and page views might look like this:
|
24
|
+
|
25
|
+
class VisitsAndPageViews
|
26
|
+
extend Garb::Model
|
27
|
+
|
28
|
+
metrics :visits, :pageviews
|
29
|
+
end
|
30
|
+
|
31
|
+
The you would use the report classes like this:
|
32
|
+
|
33
|
+
> Garb::Session.login(username, password) # this is only one option, please see Garb docs
|
34
|
+
> profile = Garb::Management::Profile.all.detect {|p| p.web_property_id == 'UA-XXXXXXX-X'}
|
35
|
+
> Visits.results(profile)
|
36
|
+
|
37
|
+
My idea was that, it would be nice to be able to avoid creating the report classes up-front by
|
38
|
+
utilising a common querying API (like a poor man's ActiveRecord API, if you will).
|
39
|
+
|
40
|
+
Usage
|
41
|
+
-----
|
42
|
+
|
43
|
+
So, when you have garb-reporter in your project, you no longer have to create those classes
|
44
|
+
(Visits or VisitsAndPageViews above) up-front.
|
45
|
+
|
46
|
+
The authentication and profile retrieval steps remain the same:
|
47
|
+
|
48
|
+
> Garb::Session.login(username, password) # this is only one option, please see Garb docs
|
49
|
+
> profile = Garb::Management::Profile.all.detect {|p| p.web_property_id == 'UA-XXXXXXX-X'}
|
50
|
+
|
51
|
+
But thereafter we just have to create a GarbReporter::Report instance with the profile:
|
52
|
+
|
53
|
+
> report = GarbReporter::Report.new(profile)
|
54
|
+
|
55
|
+
Then we can bust out some (albeit limit at this stage) querying awesomesauce:
|
56
|
+
|
57
|
+
> report.visits
|
58
|
+
> report.pageviews
|
59
|
+
> report.pageviews_and_visits
|
60
|
+
> report.pageviews_and_visits_by_date
|
61
|
+
> report.organicsearches
|
62
|
+
> report.organicsearches_by_source
|
63
|
+
|
64
|
+
You can probably see the pattern, but as long as you keep it legal with The Big G, a la:
|
65
|
+
|
66
|
+
http://code.google.com/apis/analytics/docs/gdata/dimsmets/dimsmets.html
|
67
|
+
|
68
|
+
...and format your methods like this:
|
69
|
+
|
70
|
+
> [metric]_and_[metric]_and_[metric]_by_[dimension]_and_[dimension]
|
71
|
+
|
72
|
+
you should be laughing.
|
73
|
+
|
74
|
+
|
75
|
+
TODOS
|
76
|
+
-----
|
77
|
+
|
78
|
+
* Implement respond_to on Report class to clean up validation
|
79
|
+
|
80
|
+
Run-time Requirements
|
81
|
+
---------------------
|
82
|
+
|
83
|
+
* Garb (tested against version 0.9.1)
|
84
|
+
|
85
|
+
Requirements for Testing
|
86
|
+
------------------------
|
87
|
+
|
88
|
+
* rspec
|
89
|
+
* i18n
|
90
|
+
* vcr
|
91
|
+
* fakeweb
|
92
|
+
|
93
|
+
Install
|
94
|
+
-------
|
95
|
+
|
96
|
+
gem install garb-reporter OR with bundler: gem 'garb-reporter' and `bundle install`
|
97
|
+
|
98
|
+
Contributors
|
99
|
+
------------
|
100
|
+
|
101
|
+
* Stu Liston (https://twitter.com/stuliston)
|
102
|
+
* Eric Harrison (https://twitter.com/gzminiz)
|
103
|
+
|
104
|
+
Thanks especially to the Garb core contributors. This tiny gem relies heavily on the great work they've produced
|
105
|
+
|
106
|
+
License
|
107
|
+
-------
|
108
|
+
|
109
|
+
(The MIT License)
|
110
|
+
|
111
|
+
Copyright (c) 2011 Stuart Liston
|
112
|
+
|
113
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
114
|
+
a copy of this software and associated documentation files (the
|
115
|
+
'Software'), to deal in the Software without restriction, including
|
116
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
117
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
118
|
+
permit persons to whom the Software is furnished to do so, subject to
|
119
|
+
the following conditions:
|
120
|
+
|
121
|
+
The above copyright notice and this permission notice shall be
|
122
|
+
included in all copies or substantial portions of the Software.
|
123
|
+
|
124
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
125
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
126
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
127
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
128
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
129
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
130
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/garb-reporter.rb
CHANGED
@@ -10,13 +10,13 @@ module GarbReporter
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def method_missing(method, *args)
|
13
|
-
|
14
13
|
method_name = method.to_s
|
14
|
+
|
15
15
|
super unless valid_method_name?(method_name)
|
16
16
|
|
17
17
|
class_name = build_class_name(method_name)
|
18
18
|
klass = existing_report_class(class_name) || build_new_report_class(method_name, class_name)
|
19
|
-
klass.results(@profile)
|
19
|
+
klass.results(@profile, *args)
|
20
20
|
end
|
21
21
|
|
22
22
|
private
|
data/spec/garb_reporter_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe GarbReporter do
|
4
4
|
|
5
|
-
before do
|
5
|
+
before(:all) do
|
6
6
|
|
7
7
|
# get VCR to serve us up a previously-canned http response for successful login
|
8
8
|
VCR.use_cassette('garb authentication') do
|
@@ -82,7 +82,49 @@ describe GarbReporter do
|
|
82
82
|
it 'should extract multiple dimensions' do
|
83
83
|
@report.send(:extract_dimensions, 'visits_by_date_and_office').should == [:date, :office]
|
84
84
|
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'build_new_report_class' do
|
88
|
+
|
89
|
+
before(:all) do
|
90
|
+
@klass = @report.send(:build_new_report_class, 'visits_by_date', 'VisitsByDate')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'adds the class so the GarbReporter module' do
|
94
|
+
@klass.to_s.should == 'GarbReporter::VisitsByDate'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should give the new class the public "results" method from Garb::Model module' do
|
98
|
+
@klass.respond_to?(:results, false).should be_true
|
99
|
+
end
|
85
100
|
|
101
|
+
it 'should apply the correct metrics' do
|
102
|
+
report_params = @klass.instance_variable_get(:@metrics)
|
103
|
+
report_params.instance_variable_get(:@elements).should == [ :visits ]
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should apply the correct dimensions' do
|
107
|
+
report_params = @klass.instance_variable_get(:@dimensions)
|
108
|
+
report_params.instance_variable_get(:@elements).should == [ :date ]
|
109
|
+
end
|
86
110
|
end
|
87
111
|
|
112
|
+
describe 'passing additional parameters to Garb' do
|
113
|
+
|
114
|
+
before(:all) do
|
115
|
+
@klass = GarbReporter.const_set('Exits', Class.new())
|
116
|
+
@stubbed_report = GarbReporter::Report.new(@profile)
|
117
|
+
@stubbed_report.stub!(:existing_report_class).and_return(@klass)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should pass no args when none are provided' do
|
121
|
+
@klass.should_receive(:results).once.with(@profile)
|
122
|
+
@stubbed_report.exits()
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should pass start and end dates when provided' do
|
126
|
+
@klass.should_receive(:results).with(@profile, :start_date => '2011-01-01', :end_date => '2011-12-31')
|
127
|
+
@stubbed_report.exits(:start_date => '2011-01-01', :end_date => '2011-12-31')
|
128
|
+
end
|
129
|
+
end
|
88
130
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: garb-reporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Stu Liston
|
@@ -15,7 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-12-02 00:00:00 +11:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: garb
|
@@ -111,7 +112,7 @@ files:
|
|
111
112
|
- .rspec
|
112
113
|
- .rvmrc
|
113
114
|
- Gemfile
|
114
|
-
- README
|
115
|
+
- README.md
|
115
116
|
- Rakefile
|
116
117
|
- config/vcr_setup.rb
|
117
118
|
- garb-reporter.gemspec
|
@@ -119,8 +120,7 @@ files:
|
|
119
120
|
- lib/garb-reporter/version.rb
|
120
121
|
- spec/garb_reporter_spec.rb
|
121
122
|
- spec/spec_helper.rb
|
122
|
-
|
123
|
-
- vcr_cassettes/get_profile.yml
|
123
|
+
has_rdoc: true
|
124
124
|
homepage: https://github.com/stuliston/garb-reporter
|
125
125
|
licenses: []
|
126
126
|
|
@@ -150,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
150
|
requirements: []
|
151
151
|
|
152
152
|
rubyforge_project: garb-reporter
|
153
|
-
rubygems_version: 1.
|
153
|
+
rubygems_version: 1.6.2
|
154
154
|
signing_key:
|
155
155
|
specification_version: 3
|
156
156
|
summary: Pimps out Garb by providing a report class with a standardised querying API
|
data/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Welcome to garb-reporter!
|
@@ -1,38 +0,0 @@
|
|
1
|
-
---
|
2
|
-
- !ruby/struct:VCR::HTTPInteraction
|
3
|
-
request: !ruby/struct:VCR::Request
|
4
|
-
method: :post
|
5
|
-
uri: https://www.google.com:443/accounts/ClientLogin
|
6
|
-
body: Passwd=password&service=analytics&accountType=HOSTED_OR_GOOGLE&Email=stuart%40example.com&source=vigetLabs-garb-001
|
7
|
-
headers:
|
8
|
-
content-type:
|
9
|
-
- application/x-www-form-urlencoded
|
10
|
-
response: !ruby/struct:VCR::Response
|
11
|
-
status: !ruby/struct:VCR::ResponseStatus
|
12
|
-
code: 200
|
13
|
-
message: OK
|
14
|
-
headers:
|
15
|
-
x-content-type-options:
|
16
|
-
- nosniff
|
17
|
-
expires:
|
18
|
-
- Mon, 01-Jan-1990 00:00:00 GMT
|
19
|
-
content-type:
|
20
|
-
- text/plain
|
21
|
-
server:
|
22
|
-
- GSE
|
23
|
-
x-xss-protection:
|
24
|
-
- 1; mode=block
|
25
|
-
date:
|
26
|
-
- Wed, 30 Nov 2011 02:58:23 GMT
|
27
|
-
content-length:
|
28
|
-
- "881"
|
29
|
-
cache-control:
|
30
|
-
- no-cache, no-store
|
31
|
-
pragma:
|
32
|
-
- no-cache
|
33
|
-
body: |
|
34
|
-
SID=DQAAAMEAAABEPGo2a2ewm6JsKoF18TB1W4NzG21XMZZoX4uS44RP0BhBnP7daTnL3ZPtLO8fgEr-Ym-nF5OByN29mkdOSdFBA90zSMSlGedGyzryY_NC93C3zMFRe0Sa8ia-snWqbp7U_ja4u7v6mC7t4We_eyGRujR3tRJeCJURzYmcFLJtAuNPmkNWA8sZ1g-libvB6Y9Q_iSVyKWVU1te0vVBOamN1HPQizwDcNpEX4nKACiuHyt-Uj1fn1kTnS4HDbNirlQy2yjlt2klvnzy5GMPVkZN
|
35
|
-
LSID=DQAAAMIAAAB-o-KXnRZiasADsE59dnSkvovrXlY0htPFyvyeGZKIKumNGpatwtMVTogWlnGlRa0uZP4C3yyyOIXizXaogiYKlwKo3kEj7eo0QtnWjwXurwktNrfqUtdcoxjl8UkV_cIJl77aFcg5J5aQUJgv7d96jriTI5JB1W6krd3RjhqyjYICp5abqrMKASsUqjOaCBxI__5WvH4DYGQD4n64BrdCUUMFaGXOFDnpiPATWM9YvjQf7qDt0q_UkQify2tvlIJl70gvA-5dV-Ps1agz7Fpp
|
36
|
-
Auth=DQAAAMIAAAB-o-KXnRZiasADsE59dnSkvovrXlY0htPFyvyeGZKIKumNGpatwtMVTogWlnGlRa29p1ILfFYTDmueKnj9Ds2SOVu0tx670XjlgrRvtbia1MJ7p0M4uB5aJr4UMqqrkMF4dsnA28Les-plij6icPJq9OxCwQ2og_1q3bCjs-wkC6CN9lEBvQPeLj5ipIiCNM8fap03Qxfj7-0vTVFt4nP-kpYuIpILZja05N0am1_EAItaUOXWzcjPe_tDqSkXGN_5Mm46v7Qs2dR35ssEitsT
|
37
|
-
|
38
|
-
http_version: "1.1"
|
@@ -1,40 +0,0 @@
|
|
1
|
-
---
|
2
|
-
- !ruby/struct:VCR::HTTPInteraction
|
3
|
-
request: !ruby/struct:VCR::Request
|
4
|
-
method: :get
|
5
|
-
uri: https://www.google.com:443/analytics/feeds/datasources/ga/accounts/~all/webproperties/~all/profiles
|
6
|
-
body:
|
7
|
-
headers:
|
8
|
-
authorization:
|
9
|
-
- GoogleLogin auth=DQAAAMIAAAB-o-KXnRZiasADsE59dnSkvovrXlY0htPFyvyeGZKIKumNGpatwtMVTogWlnGlRa29p1ILfFYTDmueKnj9Ds2SOVu0tx670XjlgrRvtbia1MJ7p0M4uB5aJr4UMqqrkMF4dsnA28Les-plij6icPJq9OxCwQ2og_1q3bCjs-wkC6CN9lEBvQPeLj5ipIiCNM8fap03Qxfj7-0vTVFt4nP-kpYuIpILZja05N0am1_EAItaUOXWzcjPe_tDqSkXGN_5Mm46v7Qs2dR35ssEitsT
|
10
|
-
gdata-version:
|
11
|
-
- "2"
|
12
|
-
response: !ruby/struct:VCR::Response
|
13
|
-
status: !ruby/struct:VCR::ResponseStatus
|
14
|
-
code: 200
|
15
|
-
message: OK
|
16
|
-
headers:
|
17
|
-
x-frame-options:
|
18
|
-
- SAMEORIGIN
|
19
|
-
x-content-type-options:
|
20
|
-
- nosniff
|
21
|
-
last-modified:
|
22
|
-
- Wed, 30 Nov 2011 02:58:25 GMT
|
23
|
-
expires:
|
24
|
-
- Wed, 30 Nov 2011 02:58:25 GMT
|
25
|
-
content-type:
|
26
|
-
- application/atom+xml; charset=UTF-8; type=feed
|
27
|
-
server:
|
28
|
-
- GSE
|
29
|
-
x-xss-protection:
|
30
|
-
- 1; mode=block
|
31
|
-
date:
|
32
|
-
- Wed, 30 Nov 2011 02:58:25 GMT
|
33
|
-
gdata-version:
|
34
|
-
- "2.1"
|
35
|
-
vary:
|
36
|
-
- Accept, X-GData-Authorization, GData-Version
|
37
|
-
cache-control:
|
38
|
-
- private, max-age=0, must-revalidate, no-transform
|
39
|
-
body: <?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:dxp="http://schemas.google.com/analytics/2009" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:gd="http://schemas.google.com/g/2005" gd:kind="analytics#profiles"> <id>https://www.google.com/analytics/feeds/datasources/ga/accounts/~all/webproperties/~all/profiles</id> <updated>2011-11-30T02:58:25.381Z</updated> <title>Google Analytics Profiles for stuart@example.com</title> <link rel="self" type="application/atom+xml" href="https://www.google.com/analytics/feeds/datasources/ga/accounts/~all/webproperties/~all/profiles"/> <author> <name>Google Analytics</name> </author> <generator version="1.0">Google Analytics</generator> <openSearch:totalResults>53</openSearch:totalResults> <openSearch:startIndex>1</openSearch:startIndex> <openSearch:itemsPerPage>1000</openSearch:itemsPerPage> <entry gd:etag="W/"C0cHSXw7fSp7I2A9WhRREUw."" gd:kind="analytics#profile"> <id>https://www.google.com/analytics/feeds/datasources/ga/accounts/12345678/webproperties/UA-12345678-1/profiles/67976579</id> <updated>2011-11-23T21:03:58.205-08:00</updated> <title>Google Analytics Profile TEST</title> <link rel="self" type="application/atom+xml" href="https://www.google.com/analytics/feeds/datasources/ga/accounts/12345678/webproperties/UA-12345678-1/profiles/67976579"/> <link rel="http://schemas.google.com/ga/2009#parent" type="application/atom+xml" href="https://www.google.com/analytics/feeds/datasources/ga/accounts/12345678/webproperties/UA-12345678-1" gd:targetKind="analytics#webproperty"/> <link rel="http://schemas.google.com/ga/2009#child" type="application/atom+xml" href="https://www.google.com/analytics/feeds/datasources/ga/accounts/12345678/webproperties/UA-12345678-1/profiles/67976579/goals" gd:targetKind="analytics#goals"/> <dxp:property name="ga:accountId" value="12345678"/> <dxp:property name="ga:webPropertyId" value="UA-12345678-1"/> <dxp:property name="ga:profileName" value="CAV UAT"/> <dxp:property name="ga:profileId" value="67976579"/> <dxp:property name="dxp:tableId" value="ga:67976579"/> <dxp:property name="ga:currency" value="USD"/> <dxp:property name="ga:timezone" value="America/Los_Angeles"/> </entry></feed>
|
40
|
-
http_version: "1.1"
|