legato 0.3.0 → 0.3.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.
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