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 +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
|
+
[](http://badge.fury.io/rb/legato)
|
2
4
|
[](https://travis-ci.org/tpitale/legato)
|
5
|
+
[](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
|
+
[](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
|