garb-reporter 0.0.1

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 ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ notes
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create ruby-1.8.7-p352@garb-reporter
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in garb-reporter.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1 @@
1
+ Welcome to garb-reporter!
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ require 'vcr'
2
+
3
+ VCR.config do |c|
4
+ c.cassette_library_dir = 'vcr_cassettes'
5
+ c.stub_with :fakeweb
6
+ c.default_cassette_options = { :record => :once }
7
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "garb-reporter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "garb-reporter"
7
+ s.version = GarbReporter::VERSION
8
+ s.authors = ["Stu Liston"]
9
+ s.email = ["stuart.liston@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Provides a reporter class for Garb}
12
+ s.description = %q{GarbReporter removes the need in Garb to create a new class for every report by offering a querying api that dynamically creates the Garb classes for you in the background.}
13
+
14
+ # Only running dependency is Garb (and its dependencies)
15
+ s.add_dependency "garb", "0.9.1"
16
+
17
+ # Development dependencies:
18
+ s.add_development_dependency "rspec", ">= 2.7.0"
19
+ s.add_development_dependency "i18n"
20
+ s.add_development_dependency "vcr"
21
+ s.add_development_dependency "fakeweb"
22
+
23
+ s.rubyforge_project = "garb-reporter"
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.require_paths = ["lib"]
29
+
30
+ # specify any dependencies here; for example:
31
+ # s.add_development_dependency "rspec"
32
+ # s.add_runtime_dependency "rest-client"
33
+ end
@@ -0,0 +1,3 @@
1
+ module GarbReporter
2
+ VERSION = "0.0.1"
3
+ end
data/lib/report.rb ADDED
@@ -0,0 +1,64 @@
1
+ require "garb-reporter/version"
2
+
3
+ module GarbReporter
4
+
5
+ class Report
6
+
7
+ def initialize(profile)
8
+ @profile = profile
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+
13
+ method_name = method.to_s
14
+ super unless valid_method_name?(method_name)
15
+
16
+ class_name = build_class_name(method_name)
17
+ klass = existing_report_class(class_name) || build_new_report_class(method_name, class_name)
18
+ klass.results(@profile)
19
+ end
20
+
21
+ private
22
+
23
+ def valid_method_name?(method_name)
24
+ (!method_name.empty? && method_name.scan('_by_').count <= 1 && !method_name.start_with?('_', 'by_', 'and_') && !method_name.end_with?('_', '_by', '_and'))
25
+ end
26
+
27
+ def existing_report_class(class_name)
28
+ class_exists?(class_name) ? GarbReporter.const_get(class_name) : nil
29
+ end
30
+
31
+ def class_exists?(class_name)
32
+ GarbReporter.const_defined?(class_name)
33
+ rescue NameError
34
+ return false
35
+ end
36
+
37
+ def build_new_report_class(method_name, class_name)
38
+ klass = GarbReporter.const_set(class_name, Class.new())
39
+ klass.extend Garb::Model
40
+ klass.metrics << extract_metrics(method_name)
41
+ klass.dimensions << extract_dimensions(method_name)
42
+ return klass
43
+ end
44
+
45
+ def build_class_name(method_name)
46
+ method_name.split('_').collect { |w| w.capitalize! }.join
47
+ end
48
+
49
+ def extract_metrics(method_name)
50
+ build_metrics_and_dimensions(method_name).first || []
51
+ end
52
+
53
+ def extract_dimensions(method_name)
54
+ return [] unless method_name.include?('_by_')
55
+
56
+ build_metrics_and_dimensions(method_name).last || []
57
+ end
58
+
59
+ def build_metrics_and_dimensions(method_name)
60
+ (metrics, dimensions) = method_name.split('_by_').collect { |part| part.split('_and_').collect(&:to_sym) }
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe GarbReporter do
4
+
5
+ before do
6
+
7
+ # get VCR to serve us up a previously-canned http response for successful login
8
+ VCR.use_cassette('garb authentication') do
9
+ Garb::Session.login('stuart@example.com', 'password')
10
+ end
11
+
12
+ # get VCR to serve us up a previously-canned http response for fetching profiles
13
+ VCR.use_cassette('get profile') do
14
+ @profile = Garb::Management::Profile.all.detect { |p| p.web_property_id == 'UA-12345678-1' }
15
+ end
16
+
17
+ @report = GarbReporter::Report.new(@profile)
18
+ end
19
+
20
+ describe 'build_class_name' do
21
+
22
+ it 'should capitalise the string' do
23
+ @report.send(:build_class_name, 'visits').should == 'Visits'
24
+ end
25
+
26
+ it 'should strip out underscores' do
27
+ @report.send(:build_class_name, 'visits_by_office').should_not match(/_/)
28
+ end
29
+
30
+ it 'should handle really long strings' do
31
+ @report.send(:build_class_name, 'visits_and_pageviews_and_clicks_by_date_and_office').should == 'VisitsAndPageviewsAndClicksByDateAndOffice'
32
+ end
33
+ end
34
+
35
+ describe 'valid_method_name' do
36
+
37
+ it 'should not allow a blank string' do
38
+ @report.send(:valid_method_name?, '').should be_false
39
+ end
40
+
41
+ it 'should not allow more than one instance of "_by_"' do
42
+ @report.send(:valid_method_name?, 'visits_by_office_by_date').should be_false
43
+ end
44
+
45
+ it 'should not start or end with "_by_" or "_and_' do
46
+ @report.send(:valid_method_name?, '_by_date').should be_false
47
+ @report.send(:valid_method_name?, 'visits_by_').should be_false
48
+ @report.send(:valid_method_name?, '_and_date').should be_false
49
+ @report.send(:valid_method_name?, 'visits_and_').should be_false
50
+ end
51
+ end
52
+
53
+ describe 'extract_metrics' do
54
+
55
+ it 'should extract a single metric' do
56
+ @report.send(:extract_metrics, 'visits').should == [:visits]
57
+ end
58
+
59
+ it 'should extract multiple metrics' do
60
+ @report.send(:extract_metrics, 'visits_and_clicks_and_foo_and_bar').should == [:visits, :clicks, :foo, :bar]
61
+ end
62
+
63
+ it 'should ignore a dimension' do
64
+ @report.send(:extract_metrics, 'visits_and_clicks_by_date').should == [:visits, :clicks]
65
+ end
66
+
67
+ it 'should ignore multiple dimensions' do
68
+ @report.send(:extract_metrics, 'visits_and_clicks_by_date_and_office').should == [:visits, :clicks]
69
+ end
70
+ end
71
+
72
+ describe 'dimensions' do
73
+
74
+ it 'should know when there are no dimensions' do
75
+ @report.send(:extract_dimensions, 'visits').should == []
76
+ end
77
+
78
+ it 'should extract a single dimension' do
79
+ @report.send(:extract_dimensions, 'visits_by_date').should == [:date]
80
+ end
81
+
82
+ it 'should extract multiple dimensions' do
83
+ @report.send(:extract_dimensions, 'visits_by_date_and_office').should == [:date, :office]
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,7 @@
1
+ require "config/vcr_setup"
2
+ require "garb"
3
+ require "report"
4
+
5
+ RSpec.configure do |config|
6
+ # some (optional) config here
7
+ end
@@ -0,0 +1,38 @@
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"
@@ -0,0 +1,40 @@
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/&quot;C0cHSXw7fSp7I2A9WhRREUw.&quot;" 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"
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: garb-reporter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Stu Liston
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-30 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: garb
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 57
29
+ segments:
30
+ - 0
31
+ - 9
32
+ - 1
33
+ version: 0.9.1
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 19
45
+ segments:
46
+ - 2
47
+ - 7
48
+ - 0
49
+ version: 2.7.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: i18n
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ type: :development
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: vcr
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ type: :development
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: fakeweb
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ type: :development
93
+ version_requirements: *id005
94
+ description: GarbReporter removes the need in Garb to create a new class for every report by offering a querying api that dynamically creates the Garb classes for you in the background.
95
+ email:
96
+ - stuart.liston@gmail.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files: []
102
+
103
+ files:
104
+ - .gitignore
105
+ - .rspec
106
+ - .rvmrc
107
+ - Gemfile
108
+ - README
109
+ - Rakefile
110
+ - config/vcr_setup.rb
111
+ - garb-reporter.gemspec
112
+ - lib/garb-reporter/version.rb
113
+ - lib/report.rb
114
+ - spec/garb_reporter_spec.rb
115
+ - spec/spec_helper.rb
116
+ - vcr_cassettes/garb_authentication.yml
117
+ - vcr_cassettes/get_profile.yml
118
+ homepage: ""
119
+ licenses: []
120
+
121
+ post_install_message:
122
+ rdoc_options: []
123
+
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirements: []
145
+
146
+ rubyforge_project: garb-reporter
147
+ rubygems_version: 1.8.10
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: Provides a reporter class for Garb
151
+ test_files:
152
+ - spec/garb_reporter_spec.rb
153
+ - spec/spec_helper.rb