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 +15 -0
- data/.gitignore +2 -1
- data/.travis.yml +11 -1
- data/CHANGELOG.md +6 -0
- data/README.md +119 -45
- data/bin/legato +0 -0
- data/lib/legato.rb +3 -3
- data/lib/legato/filter.rb +5 -4
- data/lib/legato/list_parameter.rb +4 -3
- data/lib/legato/model.rb +49 -3
- data/lib/legato/profile_methods.rb +6 -1
- data/lib/legato/query.rb +12 -5
- data/lib/legato/user.rb +29 -5
- data/lib/legato/version.rb +1 -1
- data/spec/lib/legato/filter_spec.rb +15 -0
- data/spec/lib/legato/legato_spec.rb +17 -0
- data/spec/lib/legato/management/legato_spec.rb +13 -0
- data/spec/lib/legato/query_spec.rb +3 -3
- data/spec/lib/legato/user_spec.rb +27 -2
- metadata +9 -23
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
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
|
-
|
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
data/README.md
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
-
# Legato: Google Analytics
|
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
|
-
|
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
|
-
|
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
|
-
|
27
|
-
|
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
|
-
|
48
|
+
```ruby
|
49
|
+
user.profiles
|
50
|
+
```
|
32
51
|
|
33
52
|
5. Get a Profile
|
34
53
|
|
35
|
-
|
54
|
+
```ruby
|
55
|
+
profile = user.profiles.first
|
56
|
+
```
|
36
57
|
|
37
58
|
6. The Profile Carries the User
|
38
59
|
|
39
|
-
|
60
|
+
```ruby
|
61
|
+
profile.user == user #=> true
|
62
|
+
```
|
40
63
|
|
41
64
|
|
42
65
|
## Google Analytics Model ##
|
43
66
|
|
44
|
-
|
45
|
-
|
67
|
+
```ruby
|
68
|
+
class Exit
|
69
|
+
extend Legato::Model
|
46
70
|
|
47
|
-
|
48
|
-
|
49
|
-
|
71
|
+
metrics :exits, :pageviews
|
72
|
+
dimensions :page_path, :operating_system, :browser
|
73
|
+
end
|
50
74
|
|
51
|
-
|
52
|
-
|
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
|
-
|
59
|
-
|
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
|
-
|
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
|
-
|
106
|
+
```ruby
|
107
|
+
filter :low_pageviews, &lambda {lte(:pageviews, 200)}
|
108
|
+
```
|
76
109
|
|
77
110
|
Filters with dimensions
|
78
111
|
|
79
|
-
|
112
|
+
```ruby
|
113
|
+
filter :for_browser, &lambda {|browser| matches(:browser, browser)}
|
114
|
+
```
|
80
115
|
|
81
116
|
Filters with OR
|
82
117
|
|
83
|
-
|
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
|
-
|
127
|
+
```ruby
|
128
|
+
Exit.for_browser("Safari", profile)
|
129
|
+
```
|
91
130
|
|
92
131
|
Chain two filters.
|
93
132
|
|
94
|
-
|
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
|
-
|
139
|
+
```ruby
|
140
|
+
Exit.results(profile) == profile.exit
|
141
|
+
```
|
99
142
|
|
100
143
|
We can chain off of that method, too.
|
101
144
|
|
102
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
##
|
194
|
+
## Session-level Segments
|
144
195
|
|
145
|
-
Your query can have a
|
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
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
232
|
+
```ruby
|
233
|
+
Exit.high_exits.low_pageviews(profile)
|
234
|
+
```
|
176
235
|
|
177
236
|
and call them directly on the profile
|
178
237
|
|
179
|
-
|
180
|
-
|
181
|
-
|
238
|
+
```ruby
|
239
|
+
profile.exit.high_exits.low_pageviews
|
240
|
+
```
|
182
241
|
## Accounts, WebProperties, Profiles, and Goals ##
|
183
242
|
|
184
|
-
|
185
|
-
|
186
|
-
|
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)
|
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}
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
"
|
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
|
-
|
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(
|
24
|
+
access_token.get(url + query_string + "&key=#{api_key}")
|
18
25
|
else
|
19
26
|
# oauth 2
|
20
|
-
access_token.get(
|
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
|
data/lib/legato/version.rb
CHANGED
@@ -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
|
388
|
-
segment_filters = stub(:to_params => '
|
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 == '
|
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(
|
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.
|
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-
|
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.
|
207
|
+
rubygems_version: 2.1.11
|
224
208
|
signing_key:
|
225
|
-
specification_version:
|
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
|