legato 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODkwYmViYWE0MzY5MWQ5NTIxNThlYWMwMzU3ZjcyMmZhNGJmNmE0MA==
5
+ data.tar.gz: !binary |-
6
+ M2MxYTYzYzE1ZTJiZmU2YjEwNGJlMzYzNjI1M2JjN2UwMDlhY2MyMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MjVhMzdhNzZmOWM0M2I3NjNlY2RkYjk5NmQzYzU3ZDYzYWU0NWY0YzY0NWNi
10
+ Y2M0M2MyZmE0Zjc0MDk3ZTZmNDIyZDkxNTZkZWEzNzBmMjA0OTMyMjdlOTBl
11
+ MjQ4Yzc2Yzk5NjA2ZTBiOWI0MWYwNmNhYThkYWFlMDk0YzUyMTk=
12
+ data.tar.gz: !binary |-
13
+ YzcyNjI0Zjg0NDFiYTNhMzZhMmNlOTAxZWI5MTMzZDBhNTUwMGM4OGZiMjJh
14
+ ZGUyNTUwNDAxMzk4OTQwYmVhYTcyM2U5MDI1OTFlNGI2NjM1NWFhOWE5ODVm
15
+ MWRmYzk3MzUxMzIwNTUzMjk3YjlhMTM2MzhkZGE0NTQ2ODBmZmE=
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ Gemfile.lock
4
4
  pkg/*
5
5
  lib/demo.rb
6
6
  .rvmrc
7
- coverage
7
+ coverage
8
+ .DS_Store
data/.travis.yml CHANGED
@@ -3,4 +3,14 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
- script: bundle exec rspec spec
6
+ - 2.0.0
7
+ - 2.1.0
8
+ script: bundle exec rspec spec
9
+ notifications:
10
+ webhooks:
11
+ urls:
12
+ - "https://pitaleerb.slack.com/services/hooks/travis?token=wNtbVP9B3j1npZkLzK4bpq8Q"
13
+ - "https://webhooks.gitter.im/e/064c90f277ac13f3dd7c"
14
+ on_success: change # options: [always|never|change] default: always
15
+ on_failure: always # options: [always|never|change] default: always
16
+ on_start: false # default: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## Legato 0.3.1 ##
2
+
3
+ * Fixes `realtime` on query to change the `tracking_scope` to 'rt' and return `self`, a `Query`
4
+
5
+ *Tony Pitale*
6
+
1
7
  ## Legato 0.3.0 ##
2
8
 
3
9
  * Adds Management Goal under Profile
data/README.md CHANGED
@@ -1,8 +1,19 @@
1
- # Legato: Google Analytics Model/Mapper #
1
+ # Legato: Ruby Client for the Google Analytics Core Reporting and Management API #
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/legato.png)](http://badge.fury.io/rb/legato)
2
4
  [![Build Status](https://travis-ci.org/tpitale/legato.png)](https://travis-ci.org/tpitale/legato)
5
+ [![Code Climate](https://codeclimate.com/github/tpitale/legato.png)](https://codeclimate.com/github/tpitale/legato)
3
6
 
4
7
  ## [Check out the Wiki!](https://github.com/tpitale/legato/wiki) ##
5
8
 
9
+ **Feel free to open an issue if you have a question that is not answered in the [Wiki](https://github.com/tpitale/legato/wiki)**
10
+
11
+ ## Chat! ##
12
+
13
+ We're trying out chat using Gitter Chat. I'll try to be in there whenever I'm at my computer.
14
+
15
+ [![Gitter chat](https://badges.gitter.im/tpitale/legato.png)](https://gitter.im/tpitale/legato)
16
+
6
17
  If you've come here from Garb, welcome! There are a few changes from Garb, so you'll want to check out:
7
18
 
8
19
  * [Model Data](https://github.com/tpitale/legato/wiki/Model-Data)
@@ -15,48 +26,64 @@ If you're not able to upgrade quite yet, Garb has been maintained https://github
15
26
 
16
27
  1. Get an OAuth2 Access Token from Google, Read about [OAuth2](https://github.com/tpitale/legato/wiki/OAuth2-and-Google)
17
28
 
18
- access_token = OAuth2 Access Token # from Google
29
+ ```ruby
30
+ access_token = OAuth2 Access Token # from Google
31
+ ```
19
32
 
20
33
  2. Create a New User with the Access Token
21
34
 
22
- user = Legato::User.new(access_token)
35
+ ```ruby
36
+ user = Legato::User.new(access_token)
37
+ ```
23
38
 
24
39
  3. List the Accounts and Profiles of the first Account
25
40
 
26
- user.accounts
27
- user.accounts.first.profiles
41
+ ```ruby
42
+ user.accounts
43
+ user.accounts.first.profiles
44
+ ```
28
45
 
29
46
  4. List all the Profiles the User has Access to
30
47
 
31
- user.profiles
48
+ ```ruby
49
+ user.profiles
50
+ ```
32
51
 
33
52
  5. Get a Profile
34
53
 
35
- profile = user.profiles.first
54
+ ```ruby
55
+ profile = user.profiles.first
56
+ ```
36
57
 
37
58
  6. The Profile Carries the User
38
59
 
39
- profile.user == user #=> true
60
+ ```ruby
61
+ profile.user == user #=> true
62
+ ```
40
63
 
41
64
 
42
65
  ## Google Analytics Model ##
43
66
 
44
- class Exit
45
- extend Legato::Model
67
+ ```ruby
68
+ class Exit
69
+ extend Legato::Model
46
70
 
47
- metrics :exits, :pageviews
48
- dimensions :page_path, :operating_system, :browser
49
- end
71
+ metrics :exits, :pageviews
72
+ dimensions :page_path, :operating_system, :browser
73
+ end
50
74
 
51
- profile.exits #=> returns a Legato::Query
52
- profile.exits.each {} #=> any enumerable kicks off the request to GA
75
+ profile.exit #=> returns a Legato::Query
76
+ profile.exit.each {} #=> any enumerable kicks off the request to GA
77
+ ```
53
78
 
54
79
  ## Metrics & Dimensions ##
55
80
 
56
81
  http://code.google.com/apis/analytics/docs/gdata/dimsmets/dimsmets.html
57
82
 
58
- metrics :exits, :pageviews
59
- dimensions :page_path, :operating_system, :browser
83
+ ```ruby
84
+ metrics :exits, :pageviews
85
+ dimensions :page_path, :operating_system, :browser
86
+ ```
60
87
 
61
88
  ## Filtering ##
62
89
 
@@ -66,54 +93,78 @@ Here's what google has to say: http://code.google.com/apis/analytics/docs/gdata/
66
93
 
67
94
  ### Examples ###
68
95
 
96
+ Inside of any `Legato::Model` class, the method `filter` is available (like `metrics` and `dimensions`).
97
+
69
98
  Return entries with exits counts greater than or equal to 2000
70
99
 
71
- filter :high_exits, &lambda {gte(:exits, 2000)}
100
+ ```ruby
101
+ filter :high_exits, &lambda {gte(:exits, 2000)}
102
+ ```
72
103
 
73
104
  Return entries with pageview metric less than or equal to 200
74
105
 
75
- filter :low_pageviews, &lambda {lte(:pageviews, 200)}
106
+ ```ruby
107
+ filter :low_pageviews, &lambda {lte(:pageviews, 200)}
108
+ ```
76
109
 
77
110
  Filters with dimensions
78
111
 
79
- filter :for_browser, &lambda {|browser| matches(:browser, browser)}
112
+ ```ruby
113
+ filter :for_browser, &lambda {|browser| matches(:browser, browser)}
114
+ ```
80
115
 
81
116
  Filters with OR
82
117
 
83
- filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
118
+ ```ruby
119
+ filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
120
+ ```
84
121
 
85
122
 
86
123
  ## Using and Chaining Filters ##
87
124
 
88
125
  Pass the profile as the first or last parameter into any filter.
89
126
 
90
- Exit.for_browser("Safari", profile)
127
+ ```ruby
128
+ Exit.for_browser("Safari", profile)
129
+ ```
91
130
 
92
131
  Chain two filters.
93
132
 
94
- Exit.high_exits.low_pageviews(profile)
133
+ ```ruby
134
+ Exit.high_exits.low_pageviews(profile)
135
+ ```
95
136
 
96
137
  Profile gets a method for each class extended by Legato::Model
97
138
 
98
- Exit.results(profile) == profile.exit
139
+ ```ruby
140
+ Exit.results(profile) == profile.exit
141
+ ```
99
142
 
100
143
  We can chain off of that method, too.
101
144
 
102
- profile.exit.high_exits.low_pageviews.by_pageviews
145
+ ```ruby
146
+ profile.exit.high_exits.low_pageviews.by_pageviews
147
+ ```
103
148
 
104
149
  Chaining order doesn't matter. Profile can be given to any filter.
105
150
 
106
- Exit.high_exits(profile).low_pageviews == Exit.low_pageviews(profile).high_exits
151
+ ```ruby
152
+ Exit.high_exits(profile).low_pageviews == Exit.low_pageviews(profile).high_exits
153
+ ```
107
154
 
108
155
  Be sure to pass the appropriate number of arguments matching the lambda for your filter.
109
156
 
110
157
  For a filter defined like this:
111
158
 
112
- filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
159
+ ```ruby
160
+ filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
161
+ ```
113
162
 
114
163
  We can use it like this, passing any number of arguments:
115
164
 
116
- Exit.browsers("Firefox", "Safari", profile)
165
+ ```ruby
166
+ Exit.browsers("Firefox", "Safari", profile)
167
+ ```
117
168
 
118
169
  ## Google Analytics Supported Filtering Methods ##
119
170
 
@@ -140,9 +191,9 @@ Operators on dimensions:
140
191
  substring => '=@',
141
192
  not_substring => '!@'
142
193
 
143
- ## Dynamic Segment
194
+ ## Session-level Segments
144
195
 
145
- Your query can have a dynamic segment, which works with filter expressions. It
196
+ Your query can have a session-level segment, which works with filter expressions. It
146
197
  works like an [advanced
147
198
  segment](https://support.google.com/analytics/answer/1033017?hl=en), except you
148
199
  don't have to create it beforehand, you can just specify it at query time.
@@ -156,35 +207,44 @@ Some metrics and dimensions are not allowed for segments, see the [API
156
207
  documentation](https://developers.google.com/analytics/devguides/reporting/core/v3/reference#segment)
157
208
  for more details.
158
209
 
210
+ **Note**: Legato does _not_ support [Users vs Sessions](https://developers.google.com/analytics/devguides/reporting/core/v3/segments#users-vs-sessions), yet. The default will be sessions (the equivalent of the earlier, now removed, dynamic segments).
211
+
159
212
  ### Defining, using and chaining filters
160
213
 
161
214
  Return entries with exits counts greater than or equal to 2000
162
215
 
163
- segment :high_exits do
164
- gte(:exits, 2000)
165
- end
216
+ ```ruby
217
+ segment :high_exits do
218
+ gte(:exits, 2000)
219
+ end
220
+ ```
166
221
 
167
222
  Return entries with pageview metric less than or equal to 200
168
223
 
169
- segment :low_pageviews do
170
- lte(:pageviews, 200)
171
- end
224
+ ```ruby
225
+ segment :low_pageviews do
226
+ lte(:pageviews, 200)
227
+ end
228
+ ```
172
229
 
173
230
  You can chain them
174
231
 
175
- Exit.high_exits.low_pageviews(profile)
232
+ ```ruby
233
+ Exit.high_exits.low_pageviews(profile)
234
+ ```
176
235
 
177
236
  and call them directly on the profile
178
237
 
179
- profile.exit.high_exits.low_pageviews
180
-
181
-
238
+ ```ruby
239
+ profile.exit.high_exits.low_pageviews
240
+ ```
182
241
  ## Accounts, WebProperties, Profiles, and Goals ##
183
242
 
184
- > Legato::Management::Account.all(user)
185
- > Legato::Management::WebProperty.all(user)
186
- > Legato::Management::Profile.all(user)
187
-
243
+ ```ruby
244
+ Legato::Management::Account.all(user)
245
+ Legato::Management::WebProperty.all(user)
246
+ Legato::Management::Profile.all(user)
247
+ ```
188
248
  ## Other Parameters Can be Passed to a call to #results ##
189
249
 
190
250
  * :start_date - The date of the period you would like this report to start
@@ -193,12 +253,26 @@ and call them directly on the profile
193
253
  * :offset - The starting index
194
254
  * :sort - metric/dimension to sort by
195
255
  * :quota_user - any arbitrary string that uniquely identifies a user (40 characters max)
256
+ * :sampling_level - 'FASTER' or 'HIGHER_PRECISION' https://developers.google.com/analytics/devguides/reporting/core/v3/reference#samplingLevel
257
+
258
+ ## Real Time Reporting ##
259
+
260
+ https://developers.google.com/analytics/devguides/reporting/realtime/v3/
261
+ https://developers.google.com/analytics/devguides/reporting/realtime/dimsmets/
262
+
263
+ GA provides an endpoint to do **basic** reporting in near-realtime. Please read the above documentation to know which features (and dimentsion/metrics) are or are _not_ available. It is also only available in **beta** so you must already have access.
264
+
265
+ Inside of Legato, you can simply add `realtime` to your query, like this:
266
+
267
+ ```ruby
268
+ Exit.realtime.results(profile)
269
+ ```
196
270
 
197
271
  ## License ##
198
272
 
199
273
  (The MIT License)
200
274
 
201
- Copyright (c) 2012 Tony Pitale
275
+ Copyright (c) 2011-2014 Tony Pitale
202
276
 
203
277
  Permission is hereby granted, free of charge, to any person obtaining
204
278
  a copy of this software and associated documentation files (the
data/bin/legato CHANGED
File without changes
data/lib/legato.rb CHANGED
@@ -16,12 +16,12 @@ module Legato
16
16
  module Management
17
17
  end
18
18
 
19
- def self.to_ga_string(str)
20
- "#{$1}ga:#{$2}" if str.to_s.camelize(:lower) =~ /^(-)?(.*)$/
19
+ def self.to_ga_string(str, tracking_scope = "ga")
20
+ "#{$1}#{tracking_scope}:#{$2}" if str.to_s.camelize(:lower) =~ /^(-)?(.*)$/
21
21
  end
22
22
 
23
23
  def self.from_ga_string(str)
24
- str.gsub("ga:", '')
24
+ str.gsub(/ga:|mcf:|rt:/, '')
25
25
  end
26
26
 
27
27
  def self.format_time(t)
data/lib/legato/filter.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Legato
2
2
  class Filter
3
- attr_accessor :field, :operator, :value, :join_character
3
+ attr_accessor :field, :operator, :value, :join_character, :tracking_scope
4
4
 
5
5
  OPERATORS = {
6
6
  # metrics
@@ -21,15 +21,16 @@ module Legato
21
21
  # :descending => '-'
22
22
  }
23
23
 
24
- def initialize(field, operator, value, join_character)
24
+ def initialize(field, operator, value, join_character, tracking_scope = "ga")
25
25
  self.field = field
26
26
  self.operator = operator
27
27
  self.value = value
28
28
  self.join_character = join_character # if nil, will be overridden by Query#apply_filter
29
+ self.tracking_scope = tracking_scope
29
30
  end
30
31
 
31
32
  def google_field
32
- Legato.to_ga_string(field)
33
+ Legato.to_ga_string(field, tracking_scope)
33
34
  end
34
35
 
35
36
  def google_operator
@@ -45,7 +46,7 @@ module Legato
45
46
  end
46
47
 
47
48
  def to_param
48
- "#{google_field}#{google_operator}#{escaped_value}"
49
+ [google_field, google_operator, escaped_value].join
49
50
  end
50
51
 
51
52
  def join_with(param)
@@ -1,11 +1,12 @@
1
1
  module Legato
2
2
  class ListParameter
3
3
 
4
- attr_reader :name, :elements
4
+ attr_reader :name, :elements, :tracking_scope
5
5
 
6
- def initialize(name, elements=[])
6
+ def initialize(name, elements=[], tracking_scope = "ga")
7
7
  @name = name
8
8
  @elements = Array.wrap(elements)
9
+ @tracking_scope = tracking_scope
9
10
  end
10
11
 
11
12
  def name
@@ -18,7 +19,7 @@ module Legato
18
19
  end
19
20
 
20
21
  def to_params
21
- value = elements.map{|element| Legato.to_ga_string(element)}.join(',')
22
+ value = elements.map{|element| Legato.to_ga_string(element, tracking_scope)}.join(',')
22
23
  value.empty? ? {} : {name => value}
23
24
  end
24
25
 
data/lib/legato/model.rb CHANGED
@@ -4,13 +4,23 @@ module Legato
4
4
  ProfileMethods.add_profile_method(base)
5
5
  end
6
6
 
7
+ # Adds metrics to the class for retrieval from GA
8
+ #
9
+ # @param *fields [Symbol] the names of the fields to retrieve
10
+ # @return [ListParameter] the set of all metrics
7
11
  def metrics(*fields)
8
- @metrics ||= ListParameter.new(:metrics)
12
+ fields, options = options_from_fields(fields)
13
+ @metrics ||= ListParameter.new(:metrics, [], options.fetch(:tracking_scope, "ga"))
9
14
  @metrics << fields
10
15
  end
11
16
 
17
+ # Adds dimensions to the class for retrieval from GA
18
+ #
19
+ # @param *fields [Symbol] the names of the fields to retrieve
20
+ # @return [ListParameter] the set of all dimensions
12
21
  def dimensions(*fields)
13
- @dimensions ||= ListParameter.new(:dimensions)
22
+ fields, options = options_from_fields(fields)
23
+ @dimensions ||= ListParameter.new(:dimensions, [], options.fetch(:tracking_scope, "ga"))
14
24
  @dimensions << fields
15
25
  end
16
26
 
@@ -18,6 +28,12 @@ module Legato
18
28
  @filters ||= {}
19
29
  end
20
30
 
31
+ # Define a filter
32
+ #
33
+ # @param name [Symbol] the class method name for the resulting filter
34
+ # @param block the block which contains filter methods to define the
35
+ # parameters used for filtering the request to GA
36
+ # @return [Proc] the body of newly defined method
21
37
  def filter(name, &block)
22
38
  filters[name] = block
23
39
 
@@ -30,6 +46,12 @@ module Legato
30
46
  @segments ||= {}
31
47
  end
32
48
 
49
+ # Define a segment
50
+ #
51
+ # @param name [Symbol] the class method name for the resulting segment
52
+ # @param block the block which contains filter methods to define the
53
+ # parameters used for segmenting the request to GA
54
+ # @return [Proc] the body of newly defined method
33
55
  def segment(name, &block)
34
56
  segments[name] = block
35
57
 
@@ -38,6 +60,11 @@ module Legato
38
60
  end
39
61
  end
40
62
 
63
+ # Set the class used to make new instances of returned results from GA
64
+ #
65
+ # @param klass [Class] any class that accepts a hash of attributes to
66
+ # initialize the values of the class
67
+ # @return the original class given
41
68
  def set_instance_klass(klass)
42
69
  @instance_klass = klass
43
70
  end
@@ -46,9 +73,28 @@ module Legato
46
73
  @instance_klass || OpenStruct
47
74
  end
48
75
 
76
+ # Builds a `query` to get results from GA
77
+ #
78
+ # @param profile [Legato::Management::Profile] the profile to query GA against
79
+ # @param options [Hash] options:
80
+ # * start_date
81
+ # * end_date
82
+ # * limit
83
+ # * offset
84
+ # * sort
85
+ # * quota_user
86
+ # @return [Query] a new query with all the filters/segments defined on the
87
+ # model, allowing for chainable behavior before kicking of the request
88
+ # to Google Analytics which returns the result data
49
89
  def results(profile, options = {})
90
+ # TODO: making tracking scope configurable when results are querried. not sure how to do this.
50
91
  Query.new(self).results(profile, options)
51
92
  end
52
93
 
94
+ def options_from_fields(fields)
95
+ options = fields.pop if fields.last.is_a?(Hash)
96
+ [fields, (options || {})]
97
+ end
98
+
53
99
  end
54
- end
100
+ end
@@ -3,7 +3,8 @@ module Legato
3
3
  def self.add_profile_method(klass)
4
4
  # demodulize leaves potential to redefine
5
5
  # these methods given different namespaces
6
- method_name = klass.name.to_s.demodulize.underscore
6
+ method_name = method_name_from_klass(klass)
7
+
7
8
  return unless method_name.length > 0
8
9
 
9
10
  class_eval <<-CODE
@@ -12,5 +13,9 @@ module Legato
12
13
  end
13
14
  CODE
14
15
  end
16
+
17
+ def self.method_name_from_klass(klass)
18
+ klass.name.to_s.gsub(":", "_").demodulize.underscore
19
+ end
15
20
  end
16
21
  end
data/lib/legato/query.rb CHANGED
@@ -29,16 +29,18 @@ module Legato
29
29
 
30
30
  attr_reader :parent_klass
31
31
  attr_accessor :profile, :start_date, :end_date
32
- attr_accessor :sort, :limit, :offset, :quota_user #, :segment # individual, overwritten
32
+ attr_accessor :sort, :limit, :offset, :quota_user, :sampling_level #, :segment # individual, overwritten
33
33
  attr_accessor :filters, :segment_filters # combined, can be appended to
34
+ attr_accessor :tracking_scope
34
35
 
35
- def initialize(klass)
36
+ def initialize(klass, tracking_scope = "ga")
36
37
  @loaded = false
37
38
  @parent_klass = klass
38
39
  self.filters = FilterSet.new
39
40
  self.segment_filters = FilterSet.new
40
41
  self.start_date = Time.now - MONTH
41
42
  self.end_date = Time.now
43
+ self.tracking_scope = tracking_scope
42
44
 
43
45
  klass.filters.each do |name, block|
44
46
  define_filter(name, &block)
@@ -89,7 +91,7 @@ module Legato
89
91
  end
90
92
 
91
93
  def apply_basic_options(options)
92
- [:sort, :limit, :offset, :start_date, :end_date, :quota_user].each do |key| #:segment
94
+ [:sort, :limit, :offset, :start_date, :end_date, :quota_user, :sampling_level].each do |key| #:segment
93
95
  self.send("#{key}=".to_sym, options[key]) if options.has_key?(key)
94
96
  end
95
97
  end
@@ -180,11 +182,11 @@ module Legato
180
182
  end
181
183
 
182
184
  def sort=(arr)
183
- @sort = Legato::ListParameter.new(:sort, arr)
185
+ @sort = Legato::ListParameter.new(:sort, arr, tracking_scope)
184
186
  end
185
187
 
186
188
  def segment
187
- "dynamic::#{segment_filters.to_params}" if segment_filters.any?
189
+ "sessions::condition::#{segment_filters.to_params}" if segment_filters.any?
188
190
  end
189
191
 
190
192
  # def segment_id
@@ -195,6 +197,11 @@ module Legato
195
197
  profile && Legato.to_ga_string(profile.id)
196
198
  end
197
199
 
200
+ def realtime
201
+ self.tracking_scope = 'rt'
202
+ self
203
+ end
204
+
198
205
  def to_params
199
206
  params = {
200
207
  'ids' => profile_id,
data/lib/legato/user.rb CHANGED
@@ -2,39 +2,63 @@ module Legato
2
2
  class User
3
3
  attr_accessor :access_token, :api_key
4
4
 
5
+ VALID_TRACKING_SCOPES = {
6
+ 'ga' => 'ga',
7
+ 'mcf' => 'mcf',
8
+ 'rt' => 'realtime'
9
+ }
10
+
5
11
  def initialize(token, api_key = nil)
6
12
  self.access_token = token
7
13
  self.api_key = api_key
8
14
  end
9
15
 
10
- URL = "https://www.googleapis.com/analytics/v3/data/ga"
11
-
16
+ # TODO: refactor into request object again
12
17
  def request(query)
18
+ url = url_for(query)
19
+
13
20
  raw_response = if api_key
14
21
  # oauth 1 + api key
15
22
  query_string = URI.escape(query.to_query_string, '<>') # may need to add !~@
16
23
 
17
- access_token.get(URL + query_string + "&key=#{api_key}")
24
+ access_token.get(url + query_string + "&key=#{api_key}")
18
25
  else
19
26
  # oauth 2
20
- access_token.get(URL, :params => query.to_params)
27
+ access_token.get(url, :params => query.to_params)
21
28
  end
22
29
 
23
30
  Response.new(raw_response, query.instance_klass)
24
31
  end
25
32
 
26
- # Management
33
+ # Management Associations
34
+
35
+ # All the `Account` records available to this user
27
36
  def accounts
28
37
  Management::Account.all(self)
29
38
  end
30
39
 
40
+ # All the `WebProperty` records available to this user
31
41
  def web_properties
32
42
  Management::WebProperty.all(self)
33
43
  end
34
44
 
45
+ # All the `Profile` records available to this user
35
46
  def profiles
36
47
  Management::Profile.all(self)
37
48
  end
38
49
 
50
+ def url_for(query)
51
+ raise "invalid tracking_scope" unless tracking_scope_valid?(query.tracking_scope)
52
+
53
+ endpoint = VALID_TRACKING_SCOPES[query.tracking_scope]
54
+
55
+ "https://www.googleapis.com/analytics/v3/data/#{endpoint}"
56
+ end
57
+
58
+ private
59
+
60
+ def tracking_scope_valid?(tracking_scope)
61
+ VALID_TRACKING_SCOPES.keys.include?(tracking_scope)
62
+ end
39
63
  end
40
64
  end
@@ -1,3 +1,3 @@
1
1
  module Legato
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -1,6 +1,21 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Legato::Filter do
4
+ context "a Filter instance with mcf" do
5
+ before :each do
6
+ @filter = Legato::Filter.new(:exits, :lt, 1000, nil, "mcf")
7
+ end
8
+
9
+ it 'represents itself as a parameter' do
10
+ @filter.to_param.should == "mcf:exits<1000"
11
+ end
12
+
13
+ it 'joins with another filter' do
14
+ filter2 = Legato::Filter.new(:pageviews, :gt, 1000, ',', "mcf")
15
+ filter2.join_with(@filter.to_param).should == "mcf:exits<1000,mcf:pageviews>1000"
16
+ end
17
+ end
18
+
4
19
  context "a Filter instance" do
5
20
  before :each do
6
21
  @filter = Legato::Filter.new(:exits, :lt, 1000, nil)
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Legato do
4
+ context 'to_ga_string' do
5
+ it 'converts a string to google syntax' do
6
+ Legato.to_ga_string("whatever").should == "ga:whatever"
7
+ Legato.to_ga_string("whatever", "mcf").should == "mcf:whatever"
8
+ end
9
+ end
10
+
11
+ context 'from_ga_string' do
12
+ it 'converts a string google syntax' do
13
+ Legato.from_ga_string("ga:whatever").should == "whatever"
14
+ Legato.from_ga_string("mcf:whatever").should == "whatever"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Legato do
4
+ context 'to_ga_string' do
5
+ it 'returns the correct dimesion with the ga namespace' do
6
+ Legato.to_ga_string("dimension").should == "ga:dimension"
7
+ end
8
+
9
+ it 'returns the correct dimesion with the Multi-Channel Funnels namespace (mcf)' do
10
+ Legato.to_ga_string("dimension", "mcf").should == "mcf:dimension"
11
+ end
12
+ end
13
+ end
@@ -384,11 +384,11 @@ describe Legato::Query do
384
384
  @query.to_params['filters'].should == 'filter set parameters'
385
385
  end
386
386
 
387
- it 'includes the dynamic segment' do
388
- segment_filters = stub(:to_params => 'segment parameter', :any? => true)
387
+ it 'includes the session level conditional segment' do
388
+ segment_filters = stub(:to_params => 'ga::parameter', :any? => true)
389
389
  @query.stubs(:segment_filters).returns(segment_filters)
390
390
 
391
- @query.to_params['segment'].should == 'dynamic::segment parameter'
391
+ @query.to_params['segment'].should == 'sessions::condition::ga::parameter'
392
392
  end
393
393
 
394
394
  it 'includes metrics' do
@@ -1,21 +1,46 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Legato::User do
4
+ context "an instance of Legato::User with the scope set" do
5
+ let(:user) {user = Legato::User.new(@access_token, nil)}
6
+
7
+ before :each do
8
+ @access_token = stub
9
+ end
10
+
11
+ it 'raises when an invalid scope is passed in' do
12
+ expect { user.url_for(stub(:tracking_scope => "what"))}.to raise_error
13
+ end
14
+
15
+ it 'sets the correct endpoint url' do
16
+ user.url_for(stub(:tracking_scope => 'mcf')).should == "https://www.googleapis.com/analytics/v3/data/mcf"
17
+ end
18
+ end
19
+
4
20
  context "an instance of Legato::User" do
5
21
  before :each do
6
22
  @access_token = stub
7
23
  @user = Legato::User.new(@access_token)
8
24
  end
9
25
 
26
+ it 'has the correct api endpoint' do
27
+ @user.url_for(stub(:tracking_scope => 'ga')).should == "https://www.googleapis.com/analytics/v3/data/ga"
28
+ end
29
+
30
+ it 'has the realtime api endpoint' do
31
+ @user.url_for(stub(:tracking_scope => 'rt')).should == "https://www.googleapis.com/analytics/v3/data/realtime"
32
+ end
33
+
10
34
  it 'returns a response for a given query' do
11
35
  klass = Class.new
12
36
  @access_token.stubs(:get).returns('a response')
13
37
  Legato::Response.stubs(:new)
38
+ @user.stubs(:url_for).returns("the_api_url")
14
39
 
15
40
  @user.request(stub(:to_params => "params", :instance_klass => klass))
16
41
 
17
42
  Legato::Response.should have_received(:new).with('a response', klass)
18
- @access_token.should have_received(:get).with(Legato::User::URL, :params => "params")
43
+ @access_token.should have_received(:get).with("the_api_url", :params => "params")
19
44
  end
20
45
 
21
46
  it 'has accounts' do
@@ -36,4 +61,4 @@ describe Legato::User do
36
61
  Legato::Management::Profile.should have_received(:all).with(@user)
37
62
  end
38
63
  end
39
- end
64
+ end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legato
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 0.3.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Tony Pitale
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-01-08 00:00:00.000000000 Z
11
+ date: 2014-06-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ! '>='
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ! '>='
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ! '>='
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: mocha
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ! '>='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ! '>='
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bourne
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ! '>='
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ! '>='
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: vcr
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - '='
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - '='
92
81
  - !ruby/object:Gem::Version
@@ -94,7 +83,6 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: fakeweb
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ! '>='
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ! '>='
108
95
  - !ruby/object:Gem::Version
@@ -110,7 +97,6 @@ dependencies:
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: simplecov
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ! '>='
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ! '>='
124
109
  - !ruby/object:Gem::Version
@@ -126,7 +111,6 @@ dependencies:
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: multi_json
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ! '>='
132
116
  - !ruby/object:Gem::Version
@@ -134,7 +118,6 @@ dependencies:
134
118
  type: :runtime
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ! '>='
140
123
  - !ruby/object:Gem::Version
@@ -187,9 +170,11 @@ files:
187
170
  - spec/integration/management_spec.rb
188
171
  - spec/integration/model_spec.rb
189
172
  - spec/lib/legato/filter_spec.rb
173
+ - spec/lib/legato/legato_spec.rb
190
174
  - spec/lib/legato/list_parameter_spec.rb
191
175
  - spec/lib/legato/management/account_spec.rb
192
176
  - spec/lib/legato/management/goal_spec.rb
177
+ - spec/lib/legato/management/legato_spec.rb
193
178
  - spec/lib/legato/management/profile_spec.rb
194
179
  - spec/lib/legato/management/segment_spec.rb
195
180
  - spec/lib/legato/management/web_property_spec.rb
@@ -202,27 +187,26 @@ files:
202
187
  - spec/support/macros/oauth.rb
203
188
  homepage: http://github.com/tpitale/legato
204
189
  licenses: []
190
+ metadata: {}
205
191
  post_install_message:
206
192
  rdoc_options: []
207
193
  require_paths:
208
194
  - lib
209
195
  required_ruby_version: !ruby/object:Gem::Requirement
210
- none: false
211
196
  requirements:
212
197
  - - ! '>='
213
198
  - !ruby/object:Gem::Version
214
199
  version: 1.8.7
215
200
  required_rubygems_version: !ruby/object:Gem::Requirement
216
- none: false
217
201
  requirements:
218
202
  - - ! '>='
219
203
  - !ruby/object:Gem::Version
220
204
  version: '0'
221
205
  requirements: []
222
206
  rubyforge_project: legato
223
- rubygems_version: 1.8.23
207
+ rubygems_version: 2.1.11
224
208
  signing_key:
225
- specification_version: 3
209
+ specification_version: 4
226
210
  summary: Access the Google Analytics API with Ruby
227
211
  test_files:
228
212
  - spec/cassettes/management/accounts.json
@@ -234,9 +218,11 @@ test_files:
234
218
  - spec/integration/management_spec.rb
235
219
  - spec/integration/model_spec.rb
236
220
  - spec/lib/legato/filter_spec.rb
221
+ - spec/lib/legato/legato_spec.rb
237
222
  - spec/lib/legato/list_parameter_spec.rb
238
223
  - spec/lib/legato/management/account_spec.rb
239
224
  - spec/lib/legato/management/goal_spec.rb
225
+ - spec/lib/legato/management/legato_spec.rb
240
226
  - spec/lib/legato/management/profile_spec.rb
241
227
  - spec/lib/legato/management/segment_spec.rb
242
228
  - spec/lib/legato/management/web_property_spec.rb