garb 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -48,7 +48,7 @@ Accounts, WebProperties, Profiles, and Goals
48
48
  Profiles for a UA- Number (a WebProperty)
49
49
  --------
50
50
 
51
- > profile = profile = Garb::Management::Profile.all.detect {|p| p.web_property_id == 'UA-XXXXXXX-X'}
51
+ > profile = Garb::Management::Profile.all.detect {|p| p.web_property_id == 'UA-XXXXXXX-X'}
52
52
 
53
53
  Define a Report Class
54
54
  ---------------------
@@ -82,14 +82,13 @@ Other Parameters
82
82
  Metrics & Dimensions
83
83
  --------------------
84
84
 
85
- **Metrics and Dimensions are very complex because of the ways in which the can and cannot be combined.**
85
+ **Metrics and Dimensions are very complex because of the ways in which they can and cannot be combined.**
86
86
 
87
87
  I suggest reading the google documentation to familiarize yourself with this.
88
88
 
89
89
  http://code.google.com/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html#bounceRate
90
90
 
91
- When you've returned, you can pass the appropriate combinations (up to 50 metrics and 2 dimenstions)
92
- to garb, as an array, of symbols. Or you can simply push a symbol into the array.
91
+ When you've returned, you can pass the appropriate combinations to Garb, as symbols.
93
92
 
94
93
  Filtering
95
94
  ---------
@@ -98,11 +97,8 @@ Filtering
98
97
 
99
98
  http://code.google.com/apis/analytics/docs/gdata/gdataReference.html#filtering
100
99
 
101
- We handle filtering as an array of hashes that you can push into,
102
- which will be joined together (AND'd)
103
-
104
100
  Here is what we can do currently:
105
- (the operator is a method on a symbol metric or dimension)
101
+ (the operator is a method on a symbol for the appropriate metric or dimension)
106
102
 
107
103
  Operators on metrics:
108
104
 
@@ -122,7 +118,7 @@ Filtering
122
118
  substring => '=@',
123
119
  not_substring => '!@'
124
120
 
125
- Given the previous Exits example report, we can add an options for filter:
121
+ Given the previous Exits example report in shorthand, we can add an option for filter:
126
122
 
127
123
  profile.exits(:filters => {:page_path.eql => '/extend/effectively-using-git-with-subversion/')
128
124
 
@@ -25,6 +25,7 @@ require 'garb/profile'
25
25
  require 'garb/account'
26
26
  require 'garb/filter_parameters'
27
27
  require 'garb/report_parameter'
28
+ require 'garb/result_set'
28
29
  require 'garb/report_response'
29
30
  require 'garb/resource'
30
31
  require 'garb/report'
@@ -31,7 +31,8 @@ module Garb
31
31
  value = self.parameters.map do |param|
32
32
  param.map do |k,v|
33
33
  next unless k.is_a?(SymbolOperator)
34
- "#{URI.encode(k.to_google_analytics, /[=<>]/)}#{CGI::escape(v.to_s)}"
34
+ escaped_v = v.to_s.gsub(/([,;\\])/) {|c| '\\'+c}
35
+ "#{URI.encode(k.to_google_analytics, /[=<>]/)}#{CGI::escape(escaped_v)}"
35
36
  end.join('%3B') # Hash AND (no duplicate keys), escape char for ';' fixes oauth
36
37
  end.join(',') # Array OR
37
38
 
@@ -15,7 +15,7 @@ module Garb
15
15
 
16
16
  def entries
17
17
  # possible to have nil entries, yuck
18
- parsed_response ? Array(parsed_response['feed']['entry']).flatten.compact : []
18
+ parsed_response ? [parsed_response['feed']['entry']].flatten.compact : []
19
19
  end
20
20
 
21
21
  def response
@@ -26,7 +26,9 @@ module Garb
26
26
  end
27
27
 
28
28
  def results(profile, options = {})
29
- default_params = build_default_params(profile)
29
+ start_date = options.fetch(:start_date, Time.now - MONTH)
30
+ end_date = options.fetch(:end_date, Time.now)
31
+ default_params = build_default_params(profile, start_date, end_date)
30
32
 
31
33
  param_set = [
32
34
  default_params,
@@ -70,11 +72,11 @@ module Garb
70
72
  sort
71
73
  end
72
74
 
73
- def build_default_params(profile)
75
+ def build_default_params(profile, start_date, end_date)
74
76
  {
75
77
  'ids' => Garb.to_ga(profile.id),
76
- 'start-date' => format_time(Time.now - Model::MONTH),
77
- 'end-date' => format_time(Time.now)
78
+ 'start-date' => format_time(start_date),
79
+ 'end-date' => format_time(end_date)
78
80
  }
79
81
  end
80
82
 
@@ -8,7 +8,16 @@ module Garb
8
8
  end
9
9
 
10
10
  def results
11
- @results ||= parse
11
+ if @results.nil?
12
+ @results = ResultSet.new(parse)
13
+ @results.total_results = parse_total_results
14
+ @results.sampled = parse_sampled_flag
15
+ end
16
+
17
+ @results
18
+ end
19
+
20
+ def sampled?
12
21
  end
13
22
 
14
23
  private
@@ -21,8 +30,23 @@ module Garb
21
30
  end
22
31
 
23
32
  def entries
24
- entry_hash = Crack::XML.parse(@xml)
25
- entry_hash ? [entry_hash['feed']['entry']].flatten.compact : []
33
+ feed? ? [parsed_xml['feed']['entry']].flatten.compact : []
34
+ end
35
+
36
+ def parse_total_results
37
+ feed? ? parsed_xml['feed']['openSearch:totalResults'].to_i : 0
38
+ end
39
+
40
+ def parse_sampled_flag
41
+ feed? ? (parsed_xml['feed']['dxp:containsSampledData'] == 'true') : false
42
+ end
43
+
44
+ def parsed_xml
45
+ @parsed_xml ||= Crack::XML.parse(@xml)
46
+ end
47
+
48
+ def feed?
49
+ !parsed_xml['feed'].nil?
26
50
  end
27
51
 
28
52
  def values_for(entry)
@@ -0,0 +1,21 @@
1
+ module Garb
2
+ class ResultSet
3
+ include Enumerable
4
+
5
+ attr_accessor :total_results, :sampled
6
+
7
+ alias :sampled? :sampled
8
+
9
+ def initialize(results)
10
+ @results = results
11
+ end
12
+
13
+ def each(&block)
14
+ @results.each(&block)
15
+ end
16
+
17
+ def to_a
18
+ @results
19
+ end
20
+ end
21
+ end
@@ -3,7 +3,7 @@ module Garb
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- TINY = 0
6
+ TINY = 1
7
7
 
8
8
  def self.to_s # :nodoc:
9
9
  [MAJOR, MINOR, TINY].join('.')
@@ -14,6 +14,8 @@
14
14
  </author>
15
15
  <openSearch:startIndex>3</openSearch:startIndex>
16
16
  <openSearch:itemsPerPage>4</openSearch:itemsPerPage>
17
+ <openSearch:totalResults>18</openSearch:totalResults>
18
+ <dxp:containsSampledData>true</dxp:containsSampledData>
17
19
  <ga:webPropertyID>UA-983247-67</ga:webPropertyID>
18
20
  <ga:start-date>2008-01-01</ga:start-date>
19
21
  <ga:end-date>2008-01-02</ga:end-date>
@@ -21,7 +21,7 @@
21
21
  <img src="./assets/0.3.9/loading.gif" alt="loading"/>
22
22
  </div>
23
23
  <div id="wrapper" style="display:none;">
24
- <div class="timestamp">Generated <abbr class="timeago" title="2010-12-09T15:19:41-05:00">2010-12-09T15:19:41-05:00</abbr></div>
24
+ <div class="timestamp">Generated <abbr class="timeago" title="2011-01-08T20:21:01-05:00">2011-01-08T20:21:01-05:00</abbr></div>
25
25
  <ul class="group_tabs"></ul>
26
26
 
27
27
  <div id="content">
@@ -2,4 +2,4 @@
2
2
  Unit Tests:
3
3
  :original_result: {}
4
4
 
5
- :created_at: 2010-12-09 15:19:41.584017 -05:00
5
+ :created_at: 2011-01-08 20:21:01.493065 -05:00
@@ -53,6 +53,15 @@ module Garb
53
53
  params = {'filters' => 'ga:pagePath%3D~New+York'}
54
54
  assert_equal params, @filter_parameters.to_params
55
55
  end
56
+
57
+ should "escape comma, semicolon, and backslash in values" do
58
+ @filter_parameters.filters do
59
+ eql(:url, 'this;that,thing\other')
60
+ end
61
+
62
+ params = {'filters' => 'ga:url%3D%3Dthis%5C%3Bthat%5C%2Cthing%5C%5Cother'}
63
+ assert_equal params, @filter_parameters.to_params
64
+ end
56
65
  end
57
66
  end
58
67
  end
@@ -21,7 +21,7 @@
21
21
  <img src="./assets/0.3.9/loading.gif" alt="loading"/>
22
22
  </div>
23
23
  <div id="wrapper" style="display:none;">
24
- <div class="timestamp">Generated <abbr class="timeago" title="2010-12-09T17:47:44-05:00">2010-12-09T17:47:44-05:00</abbr></div>
24
+ <div class="timestamp">Generated <abbr class="timeago" title="2011-01-08T19:38:09-05:00">2011-01-08T19:38:09-05:00</abbr></div>
25
25
  <ul class="group_tabs"></ul>
26
26
 
27
27
  <div id="content">
@@ -2,4 +2,4 @@
2
2
  Unit Tests:
3
3
  :original_result: {}
4
4
 
5
- :created_at: 2010-12-09 17:47:44.425037 -05:00
5
+ :created_at: 2011-01-08 19:38:09.152093 -05:00
@@ -23,6 +23,11 @@ module Garb
23
23
  assert_equal ['entry1', 'entry2'], @feed.entries
24
24
  end
25
25
 
26
+ should "handle case of a single entry" do
27
+ @feed.stubs(:parsed_response).returns({'feed' => {'entry' => {'profile_id' => '12345'}}})
28
+ assert_equal [{'profile_id' => '12345'}], @feed.entries
29
+ end
30
+
26
31
  should "have an empty array for entries without a response" do
27
32
  @feed.stubs(:parsed_response).returns(nil)
28
33
  assert_equal [], @feed.entries
@@ -64,7 +64,7 @@ module Garb
64
64
  @test_model.stubs(:dimensions).returns(stub(:to_params => {'dimensions' => 'ga:pagePath'}))
65
65
 
66
66
  now = Time.now
67
- Time.stubs(:new).returns(now)
67
+ Time.stubs(:now).returns(now)
68
68
 
69
69
  # p @profile.id
70
70
 
@@ -115,7 +115,13 @@ module Garb
115
115
  assert_data_params(@params.merge({'start-index' => 10}))
116
116
  end
117
117
 
118
- # should "be able to shift the date range"
118
+ should "be able to shift the date range" do
119
+ start_date = (Time.now - 1296000)
120
+ end_date = Time.now
121
+
122
+ assert_equal ['result'], @test_model.results(@profile, :start_date => start_date, :end_date => end_date)
123
+ assert_data_params(@params.merge({'start-date' => start_date.strftime('%Y-%m-%d'), 'end-date' => end_date.strftime('%Y-%m-%d')}))
124
+ end
119
125
 
120
126
  should "return a set of results in the defined class" do
121
127
  @test_model.stubs(:instance_klass).returns(ResultKlass)
@@ -125,7 +131,6 @@ module Garb
125
131
  end
126
132
  end
127
133
 
128
- # should "have a block syntax for filtering results"
129
134
  # should "return results as an array of the class it belongs to, if that class is an ActiveRecord descendant"
130
135
  # should "return results as an array of the class it belongs to, if that class is a DataMapper descendant"
131
136
  # should "return results as an array of the class it belongs to, if that class is a MongoMapper descendant"
@@ -7,30 +7,40 @@ module Garb
7
7
  context "A ReportResponse" do
8
8
  context "with a report feed" do
9
9
  setup do
10
- @file = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.xml"))
10
+ @xml = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.xml"))
11
11
  end
12
12
 
13
13
  should "parse results from atom xml" do
14
- response = ReportResponse.new(@file)
14
+ response = ReportResponse.new(@xml)
15
15
  assert_equal ['33', '2', '1'], response.results.map(&:pageviews)
16
16
  end
17
17
 
18
18
  should "default to returning an array of OpenStruct objects" do
19
- response = ReportResponse.new(@file)
19
+ response = ReportResponse.new(@xml)
20
20
  assert_equal [OpenStruct, OpenStruct, OpenStruct], response.results.map(&:class)
21
21
  end
22
22
 
23
23
  should "return an array of instances of a specified class" do
24
- response = ReportResponse.new(@file, SpecialKlass)
24
+ response = ReportResponse.new(@xml, SpecialKlass)
25
25
  assert_equal [SpecialKlass, SpecialKlass, SpecialKlass], response.results.map(&:class)
26
26
  end
27
+
28
+ should "know the total number of results" do
29
+ response = ReportResponse.new(@xml)
30
+ assert_equal 18, response.results.total_results
31
+ end
32
+
33
+ should "know if the data has been sampled" do
34
+ response = ReportResponse.new(@xml)
35
+ assert_equal true, response.results.sampled?
36
+ end
27
37
  end
28
38
 
29
39
  should "return an empty array if there are no results" do
30
40
  response = ReportResponse.new("result xml")
31
41
  Crack::XML.stubs(:parse).with("result xml").returns({'feed' => {'entry' => nil}})
32
42
 
33
- assert_equal [], response.results
43
+ assert_equal [], response.results.to_a
34
44
  end
35
45
  end
36
46
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 0
9
- version: 0.9.0
8
+ - 1
9
+ version: 0.9.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tony Pitale
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-10 00:00:00 -05:00
17
+ date: 2011-01-08 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -84,6 +84,7 @@ files:
84
84
  - lib/garb/reports/visits.rb
85
85
  - lib/garb/reports.rb
86
86
  - lib/garb/resource.rb
87
+ - lib/garb/result_set.rb
87
88
  - lib/garb/session.rb
88
89
  - lib/garb/step.rb
89
90
  - lib/garb/version.rb