gaapi 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +70 -0
- data/LICENSE +21 -0
- data/README.md +260 -0
- data/lib/gaapi/report.rb +57 -0
- data/lib/gaapi/response.rb +25 -21
- data/lib/gaapi/row.rb +111 -0
- data/lib/gaapi/version.rb +1 -1
- data/lib/gaapi.rb +5 -4
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 297b653a2ab27e34a552b37d270d675473eb3a282205bcffcd6b41a1ad9eb541
|
4
|
+
data.tar.gz: 9dfa54aae6e7d654000de0d7ba6aa6dd40619114dabb6269e35d689f7a243283
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c93a38a5beae05b5e1583f6ddf2df29758b588ff68e196c617c06e74c723e7a3f5daefd38a9a839ae04ef8bcaba9f8a72e79aff1f1179666e93d6be4ca8de6bd
|
7
|
+
data.tar.gz: eaf0ca31bc981f5a0789fcf4dd03ffb294961d5a4354c9fa5923761cfc41dfe774fba7fe45268b38f9d0a47ab0fea5d9dcb53d58f5a0746dd43152e6c1bebe9a
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
## [Pending Release][0.5.0]
|
2
|
+
|
3
|
+
### Breaking changes
|
4
|
+
|
5
|
+
* Your contribution here!
|
6
|
+
|
7
|
+
### New features
|
8
|
+
|
9
|
+
* Your contribution here!
|
10
|
+
|
11
|
+
### Bugfixes
|
12
|
+
|
13
|
+
* Your contribution here!
|
14
|
+
|
15
|
+
## [0.4.0][](2018-10-31)
|
16
|
+
|
17
|
+
### Breaking changes
|
18
|
+
|
19
|
+
* The CSV output from the command-line tool may have changed in certain edge cases, like when no dimensions are specified in the query.
|
20
|
+
|
21
|
+
### New features
|
22
|
+
|
23
|
+
* Report and Row classes for the result make writing Ruby code a little easier.
|
24
|
+
* [#5] Dimensions and metrics in rows can be accessed by name. See the README.
|
25
|
+
|
26
|
+
## [0.3.0][](2018-10-23)
|
27
|
+
|
28
|
+
### New features
|
29
|
+
|
30
|
+
* [#4] The query can now be specified as a string, a JSON hash, or a regular Ruby hash with symbolic keys.
|
31
|
+
* [#3] `gaapi` automatically retrieves the Google Analytics-defined maximum of 10,000 rows, unless the user specifies a lower limit.
|
32
|
+
|
33
|
+
## [0.2.1][](2018-09-07)
|
34
|
+
|
35
|
+
### Breaking changes
|
36
|
+
|
37
|
+
### New features
|
38
|
+
|
39
|
+
* Documentation changes.
|
40
|
+
|
41
|
+
### Bugfixes
|
42
|
+
|
43
|
+
* `gaapi` returns appropriate exit status to operating system.
|
44
|
+
|
45
|
+
## [0.2.0][0.2.0](2018-09-06)
|
46
|
+
|
47
|
+
### Breaking changes
|
48
|
+
|
49
|
+
* Refactor code so it's more useful to incorporate in other programs.
|
50
|
+
|
51
|
+
### New features
|
52
|
+
|
53
|
+
### Bugfixes
|
54
|
+
|
55
|
+
## [0.0.1.alpha1][] (2018-08-27)
|
56
|
+
|
57
|
+
### Breaking changes
|
58
|
+
|
59
|
+
* N/A.
|
60
|
+
|
61
|
+
### New features
|
62
|
+
|
63
|
+
* N/A.
|
64
|
+
|
65
|
+
### Bugfixes
|
66
|
+
|
67
|
+
* N/A.
|
68
|
+
|
69
|
+
[Pending Release]: https://github.com/weenhanceit/gaapi/compare/v0.4.0...HEAD
|
70
|
+
[0.4.0]: https://github.com/weenhanceit/gaapi/compare/v0.4.0...v0.3.0
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 weenhanceit
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# Google Analytics Reporting for Ruby
|
2
|
+
`gaapi` provides:
|
3
|
+
|
4
|
+
- A command line executable program to retrieve reporting data from Google Analytics (GA). It takes the user's GA request, specified in JSON format, and sends it to GA. It outputs the result of the request in JSON or comma-separated values (CSV) format
|
5
|
+
- A library of classes that can be used in other programs to retrieve reporting data from GA
|
6
|
+
|
7
|
+
`gaapi` supports two ways of providing credentials. One way is more useful while testing scripts or doing ad-hoc queries. The other is more appropriate for unattended script usage. See the [Authentication](#Authentication) section for more details.
|
8
|
+
|
9
|
+
Google provides a [Ruby client library](https://developers.google.com/api-client-library/ruby/apis/analyticsreporting/v4) that builds queries by constructing them from Ruby objects. `gaapi` allows you to express queries as JSON. If you prefer the JSON format, you may prefer to use `gaapi`. If you want to deal with Ruby objects (which are likely more verbose than JSON), use the Google gem.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
For stand-alone use:
|
13
|
+
|
14
|
+
```bash
|
15
|
+
gem install gaapi --no-doc
|
16
|
+
```
|
17
|
+
|
18
|
+
In a Gemfile:
|
19
|
+
|
20
|
+
```
|
21
|
+
gem 'gaapi'
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
### Command Line
|
26
|
+
```bash
|
27
|
+
gaapi [options] VIEW_ID
|
28
|
+
```
|
29
|
+
If no query is specified on the command line, `gaapi` tries to read the query from standard input.
|
30
|
+
|
31
|
+
The `VIEW_ID` is what identifies the GA data (a view of a property). To find the view ID, log in to GA, select the account of interest, select Admin (the gear near the bottom left of the page), and select "View Settings" (on the right of the page).
|
32
|
+
|
33
|
+
#### Options
|
34
|
+
```
|
35
|
+
-a, --access-token TOKEN An access token obtained from https://developers.google.com/oauthplayground.
|
36
|
+
--csv Output result as a csv file.
|
37
|
+
-c, --credentials CREDENTIALS Location of the credentials file. Default: `.gaapi/ga-api-key`.
|
38
|
+
-d, --debug Print debugging information.
|
39
|
+
-e, --end-date END_DATE Report including END_DATE (yyyy-mm-dd).
|
40
|
+
-n, --dry-run Don't actually send the query to Google.
|
41
|
+
-q, --query-file QUERYFILE File containing the query. Default STDIN.
|
42
|
+
-s, --start-date START_DATE Report including START_DATE (yyyy-mm-dd).
|
43
|
+
```
|
44
|
+
|
45
|
+
If you specify both the `-a` and `-c` options, `gaapi` will use the `-a` option.
|
46
|
+
|
47
|
+
#### Example
|
48
|
+
Get the number of visitors to a site for January, 2018, with credentials previously obtained and stored in `./credentials.json`:
|
49
|
+
```bash
|
50
|
+
gaapi -s "2018-01-01" -e "2018-01-31" -c ./credentials.json 000000
|
51
|
+
{
|
52
|
+
"reportRequests": [{
|
53
|
+
"viewId": "VIEW_ID",
|
54
|
+
"dimensions": [{"name": "ga:date"}],
|
55
|
+
"dateRanges": [{
|
56
|
+
"startDate": "START_DATE",
|
57
|
+
"endDate": "END_DATE"
|
58
|
+
}],
|
59
|
+
"metrics": [{
|
60
|
+
"expression": "ga:users"
|
61
|
+
}],
|
62
|
+
"includeEmptyRows": true,
|
63
|
+
"hideTotals": false,
|
64
|
+
"hideValueRanges": true
|
65
|
+
}]
|
66
|
+
}
|
67
|
+
```
|
68
|
+
|
69
|
+
### In a Program
|
70
|
+
Make sure the program can find GAAPI. Without Rails:
|
71
|
+
```ruby
|
72
|
+
require "gaapi"
|
73
|
+
```
|
74
|
+
With Rails, simply include `gaapi` in the `Gemfile`:
|
75
|
+
```ruby
|
76
|
+
gem "gaapi"
|
77
|
+
```
|
78
|
+
|
79
|
+
Next, get an access token. To run the program unattended, the best way is to use the approach described [here](#Unattended Running), which translates to the following code:
|
80
|
+
```ruby
|
81
|
+
access_token = GAAPI::AccessToken.new("path/to/credential_file")
|
82
|
+
```
|
83
|
+
|
84
|
+
Set up the query. This may raise exceptions:
|
85
|
+
```ruby
|
86
|
+
begin
|
87
|
+
query = GAAPI::Query.new(query_string, 00000000, access_token, "2018-01-01", "2018-06-30")
|
88
|
+
rescue StandardError => e
|
89
|
+
# Handle the error
|
90
|
+
end
|
91
|
+
```
|
92
|
+
A typical exception would be from a `query_string` that isn't valid JSON. The `query_string` has to be a valid GA reporting query. See the [Queries](#Queries) section. Because the access token is lazy-evaluated, you may also get an exception here if the credential file doesn't exist or is malformed.
|
93
|
+
|
94
|
+
Execute the request:
|
95
|
+
```ruby
|
96
|
+
result = query.execute
|
97
|
+
if result.success?
|
98
|
+
...
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
If the query was successful, you have access to a few interesting methods:
|
103
|
+
```ruby
|
104
|
+
puts result.body # raw response body
|
105
|
+
puts result.pp # a string formatted into more readable JSON
|
106
|
+
puts result.csv # comma-separated values format, ready to be written to a file
|
107
|
+
```
|
108
|
+
|
109
|
+
There is also some support now for a more structured use of the resulting query. If the query was successful (`result.success?`), you can use the following:
|
110
|
+
```
|
111
|
+
result.reports # An array of GAAPI::Report objects
|
112
|
+
report.dimensions # An array of the dimension names
|
113
|
+
report.headers # An array of the dimension names and metric names
|
114
|
+
report.metrics # An array of the metric names
|
115
|
+
report.rows # An array of GAAPI::Row objects
|
116
|
+
```
|
117
|
+
|
118
|
+
If you have a `Row` object, you can access the dimensions and metrics using method names. For example, to get the `ga:sessionDuration` metric for a row:
|
119
|
+
```
|
120
|
+
row.session_duration
|
121
|
+
```
|
122
|
+
|
123
|
+
The `ga:` is stripped from the front of the dimension or metric name, and then the rest is converted to snake case.
|
124
|
+
|
125
|
+
You can also get all the dimensions or all the metrics for a row:
|
126
|
+
```
|
127
|
+
row.dimensions
|
128
|
+
row.metrics
|
129
|
+
```
|
130
|
+
|
131
|
+
These return arrays with the values in the order corresponding to the `report.dimensions` and `report.metrics` arrays.
|
132
|
+
|
133
|
+
Putting it all together, to get all the `ga:avgSessionDuration` from all the rows in all the reports:
|
134
|
+
```
|
135
|
+
result.reports.flat_map do |report|
|
136
|
+
report.rows.map do |row|
|
137
|
+
row.avg_session_duration
|
138
|
+
end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
## Queries
|
143
|
+
`gaapi` uses the Google Analytics Reporting API v4 (https://developers.google.com/analytics/devguides/reporting/core/v4/). An introduction to querying for GA data is here: https://developers.google.com/analytics/devguides/reporting/core/v4/basics.
|
144
|
+
A very useful reference of the dimensions and metrics available is at: https://developers.google.com/analytics/devguides/reporting/core/dimsmets.
|
145
|
+
|
146
|
+
A query to find basic visit data for a web site is:
|
147
|
+
```json
|
148
|
+
{
|
149
|
+
"reportRequests": [{
|
150
|
+
"viewId": "VIEW_ID",
|
151
|
+
"dimensions": [{"name": "ga:date"}],
|
152
|
+
"dateRanges": [{
|
153
|
+
"startDate": "2017-10-01",
|
154
|
+
"endDate": "2017-10-31"
|
155
|
+
}],
|
156
|
+
"metrics": [{
|
157
|
+
"expression": "ga:avgSessionDuration"
|
158
|
+
},
|
159
|
+
{
|
160
|
+
"expression": "ga:pageviewsPerSession"
|
161
|
+
},
|
162
|
+
{
|
163
|
+
"expression": "ga:sessions"
|
164
|
+
},
|
165
|
+
{
|
166
|
+
"expression": "ga:users"
|
167
|
+
}
|
168
|
+
],
|
169
|
+
"includeEmptyRows": true,
|
170
|
+
"hideTotals": false,
|
171
|
+
"hideValueRanges": true
|
172
|
+
},
|
173
|
+
{
|
174
|
+
"viewId": "VIEW_ID",
|
175
|
+
"dimensions": [{"name": "ga:date"}],
|
176
|
+
"dateRanges": [{
|
177
|
+
"startDate": "2017-10-01",
|
178
|
+
"endDate": "2017-10-31"
|
179
|
+
}],
|
180
|
+
"metrics": [{
|
181
|
+
"expression": "ga:goal1Completions"
|
182
|
+
},
|
183
|
+
{
|
184
|
+
"expression": "ga:goal2Completions"
|
185
|
+
},
|
186
|
+
{
|
187
|
+
"expression": "ga:goal6Completions"
|
188
|
+
},
|
189
|
+
{
|
190
|
+
"expression": "ga:goal8Completions"
|
191
|
+
},
|
192
|
+
{
|
193
|
+
"expression": "ga:goal9Completions"
|
194
|
+
},
|
195
|
+
{
|
196
|
+
"expression": "ga:goal11Completions"
|
197
|
+
},
|
198
|
+
{
|
199
|
+
"expression": "ga:goal13Completions"
|
200
|
+
},
|
201
|
+
{
|
202
|
+
"expression": "ga:goal14Completions"
|
203
|
+
},
|
204
|
+
{
|
205
|
+
"expression": "ga:goal16Completions"
|
206
|
+
},
|
207
|
+
{
|
208
|
+
"expression": "ga:goalCompletionsAll"
|
209
|
+
}
|
210
|
+
],
|
211
|
+
"includeEmptyRows": true,
|
212
|
+
"hideTotals": false,
|
213
|
+
"hideValueRanges": true
|
214
|
+
},
|
215
|
+
{
|
216
|
+
"viewId": "VIEW_ID",
|
217
|
+
"dimensions": [{"name": "ga:date"}],
|
218
|
+
"dateRanges": [{
|
219
|
+
"startDate": "2017-10-01",
|
220
|
+
"endDate": "2017-10-31"
|
221
|
+
}],
|
222
|
+
"metrics": [{
|
223
|
+
"expression": "ga:avgSessionDuration"
|
224
|
+
},
|
225
|
+
{
|
226
|
+
"expression": "ga:pageviewsPerSession"
|
227
|
+
},
|
228
|
+
{
|
229
|
+
"expression": "ga:sessions"
|
230
|
+
},
|
231
|
+
{
|
232
|
+
"expression": "ga:users"
|
233
|
+
}
|
234
|
+
],
|
235
|
+
"includeEmptyRows": true,
|
236
|
+
"hideTotals": false,
|
237
|
+
"hideValueRanges": true
|
238
|
+
}
|
239
|
+
]
|
240
|
+
}
|
241
|
+
```
|
242
|
+
|
243
|
+
By default, Google Analytics will return a maximum of 1,000 rows. `gaapi` automatically adds a `pageSize: 10000` to your query, if no `pageSize` is specified. This causes Google Analytics to return 10,000 rows, the maximum that Google Analytics will return.
|
244
|
+
|
245
|
+
If `gaapi` returns 10,000 rows, it's your responsibility to use the `nextPageToken` in the returned result, to query additional rows.
|
246
|
+
|
247
|
+
## Authentication
|
248
|
+
[The introduction to authentication for Google products is here: https://developers.google.com/analytics/devguides/reporting/core/v4/authorization.]
|
249
|
+
|
250
|
+
### Testing and Ad-Hoc Usage
|
251
|
+
This method involves cutting and pasting an access token obtained from https://developers.google.com/oauthplayground onto the command line. The access token is simply a long string of characters generated by Google. The access token expires after an hour, so the user has to return to the Google URL to get a new token.
|
252
|
+
|
253
|
+
### Unattended Running
|
254
|
+
This method obtains a file of secure credentials from Google. It's very important that these credentials be kept secure, as whoever has a copy of the file, has access to the Google Analytics data for the account.
|
255
|
+
|
256
|
+
To use this type of credential with `gaapi`:
|
257
|
+
|
258
|
+
1. Follow the instructions at: https://developers.google.com/identity/protocols/OAuth2ServiceAccount, choose a JSON format file, and when you're prompted to save a file, save it
|
259
|
+
2. Immediately change the permissions of the file to make it readable only by you. On Linux, Unix, OSX that's `chmod 600 filename`
|
260
|
+
3. Give the file name in the `--credentials` option when you run `gaapi`, or pass it to `AccessToken.new`
|
data/lib/gaapi/report.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GAAPI
|
4
|
+
# A single report from a query to Google Analytics
|
5
|
+
class Report
|
6
|
+
# An array of the dimensions, in the order that they appear in the response.
|
7
|
+
def dimensions
|
8
|
+
report["columnHeader"]["dimensions"] || []
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [Boolean] True if dimensions were returned.
|
12
|
+
def dimensions?
|
13
|
+
!report["columnHeader"]["dimensions"].nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
# An array of the dimensions first and then the metrics, in the order that
|
17
|
+
# they appear in the response.
|
18
|
+
def headers
|
19
|
+
dimensions + metrics
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(response, report)
|
23
|
+
@response = response
|
24
|
+
@report = report
|
25
|
+
end
|
26
|
+
attr_reader :report
|
27
|
+
|
28
|
+
# An array of the metric names, in the order that they appear in the response.
|
29
|
+
def metric_type(i)
|
30
|
+
report["columnHeader"]["metricHeader"]["metricHeaderEntries"][i]["type"]
|
31
|
+
end
|
32
|
+
|
33
|
+
# An array of the metric names, in the order that they appear in the response.
|
34
|
+
def metrics
|
35
|
+
report["columnHeader"]["metricHeader"]["metricHeaderEntries"].map { |metric| metric["name"] }
|
36
|
+
end
|
37
|
+
|
38
|
+
# The data rows in the report.
|
39
|
+
def rows
|
40
|
+
report["data"]["rows"].map { |row| Row.new(self, row) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# The totals, if there were any.
|
44
|
+
def totals
|
45
|
+
Array.new(dimensions.size) + report["data"]["totals"][0]["values"]
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Boolean] True if there totals were returned from the query.
|
49
|
+
def totals?
|
50
|
+
report["data"]["totals"]
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :response
|
56
|
+
end
|
57
|
+
end
|
data/lib/gaapi/response.rb
CHANGED
@@ -23,16 +23,20 @@ module GAAPI
|
|
23
23
|
# @return [String] The result of the query formatted as a comma-separated
|
24
24
|
# values string.
|
25
25
|
def csv
|
26
|
-
result = to_json
|
27
26
|
@csv ||= CSV.generate do |csv|
|
28
|
-
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
csv <<
|
27
|
+
reports.each(&:report).each do |report|
|
28
|
+
# If there are no dimensions, but totals, we need to put an extra
|
29
|
+
# column at the start for the word "Total".
|
30
|
+
# I don't see how totals will be different than the metrics if you
|
31
|
+
# don't specify dimensions, but whatever.
|
32
|
+
totals_column = report.totals? && !report.dimensions? ? [nil] : []
|
33
|
+
csv << totals_column + report.headers
|
34
|
+
report.rows.each { |row| csv << totals_column + row.to_a }
|
35
|
+
csv << ["Totals"] + if report.totals? && !report.dimensions?
|
36
|
+
report.totals
|
37
|
+
else
|
38
|
+
report.totals[1..-1]
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
@@ -47,6 +51,18 @@ module GAAPI
|
|
47
51
|
@pp ||= JSON.pretty_generate(to_json)
|
48
52
|
end
|
49
53
|
|
54
|
+
# The array of reports returned by the query.
|
55
|
+
# @return [Array] An array of reports.
|
56
|
+
def reports
|
57
|
+
@reports ||= if success?
|
58
|
+
to_json["reports"].map do |report|
|
59
|
+
Report.new(self, report)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
[]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
50
66
|
# Return true if the request was successful.
|
51
67
|
# @return [Boolean] True if the request was successful (response code 200).
|
52
68
|
def success?
|
@@ -64,17 +80,5 @@ module GAAPI
|
|
64
80
|
def to_s
|
65
81
|
response.body
|
66
82
|
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def csv_data_row(row_headers, metrics)
|
71
|
-
(Array(row_headers) || []) + metrics[0]["values"]
|
72
|
-
end
|
73
|
-
|
74
|
-
def csv_header_row(report)
|
75
|
-
(report["columnHeader"]["dimensions"] || []) + report["columnHeader"]["metricHeader"]["metricHeaderEntries"].map do |entry|
|
76
|
-
entry["name"]
|
77
|
-
end
|
78
|
-
end
|
79
83
|
end
|
80
84
|
end
|
data/lib/gaapi/row.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GAAPI
|
4
|
+
# A single row from a query to Google Analytics
|
5
|
+
class Row
|
6
|
+
# An array of the dimension values, in the order that they appear in the
|
7
|
+
# dimension headers.
|
8
|
+
def dimensions
|
9
|
+
row["dimensions"] || []
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(report, row)
|
13
|
+
@report = report
|
14
|
+
@row = row
|
15
|
+
end
|
16
|
+
|
17
|
+
# Define and call methods for the columns in the report.
|
18
|
+
def method_missing(method, *args)
|
19
|
+
if (i = dimension_method_names.find_index(method))
|
20
|
+
define_singleton_method(method) do
|
21
|
+
dimensions[i]
|
22
|
+
end
|
23
|
+
send(method)
|
24
|
+
elsif (i = metric_method_names.find_index(method))
|
25
|
+
define_singleton_method(method) do
|
26
|
+
convert_metric(i)
|
27
|
+
end
|
28
|
+
send(method)
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# An array of the metric values, in the order that they appear in the
|
35
|
+
# metric headers.
|
36
|
+
def metrics
|
37
|
+
# NOTE: There is one entry in the `row["metrics"]` array for each data range.
|
38
|
+
# Since currently we only support one date range, this following index is
|
39
|
+
# always 0.
|
40
|
+
row["metrics"][0]["values"]
|
41
|
+
end
|
42
|
+
|
43
|
+
def respond_to_missing?
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return the data from the row as an Array, ordered by:
|
48
|
+
# Headers first, in the order that they appear in the Report#headers array.
|
49
|
+
# Metrics next, in the order that they appear in the Rport#metrics array.
|
50
|
+
def to_a
|
51
|
+
dimensions + metrics
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
attr_reader :report, :row
|
57
|
+
|
58
|
+
# Convert metric to the right type.
|
59
|
+
def convert_metric(i)
|
60
|
+
case report.metric_type(i)
|
61
|
+
when "INTEGER"
|
62
|
+
# INTEGER Integer metric.
|
63
|
+
metrics[i].to_i
|
64
|
+
when "FLOAT", "PERCENT"
|
65
|
+
# FLOAT Float metric.
|
66
|
+
# PERCENT Percentage metric.
|
67
|
+
metrics[i].to_f
|
68
|
+
when "CURRENCY"
|
69
|
+
# CURRENCY Currency metric.
|
70
|
+
# TODO: Do this better.
|
71
|
+
metrics[i].to_f
|
72
|
+
when "TIME"
|
73
|
+
# TIME Time metric in HH:MM:SS format.
|
74
|
+
# Time in fraction of a day.
|
75
|
+
(metrics[i][0..1].to_i +
|
76
|
+
metrics[i][3..4].to_i * 60 +
|
77
|
+
metrics[i][6..7].to_i * 24 * 60) / 86_400
|
78
|
+
else
|
79
|
+
# METRIC_TYPE_UNSPECIFIED Metric type is unspecified.
|
80
|
+
metric[i]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Return the dimensions in the response, as method names.
|
85
|
+
def dimension_method_names
|
86
|
+
report.dimensions.map { |d| ga_to_method_name(d) }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Change a dimension or metric name to a method name.
|
90
|
+
# Strip off the "ga:" at the beginning, change it to snake case, and
|
91
|
+
# convert it to a symbol.
|
92
|
+
def ga_to_method_name(name)
|
93
|
+
snakecase(name.gsub(/\Aga:/, "")).to_sym
|
94
|
+
end
|
95
|
+
|
96
|
+
# Return the metrics in the response, as method names.
|
97
|
+
def metric_method_names
|
98
|
+
report.metrics.map { |d| ga_to_method_name(d) }
|
99
|
+
end
|
100
|
+
|
101
|
+
# From: https://stackoverflow.com/a/37381260/3109926
|
102
|
+
def snakecase(string)
|
103
|
+
string.to_s.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
104
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
105
|
+
.tr("-", "_")
|
106
|
+
.gsub(/\s/, "_")
|
107
|
+
.gsub(/__+/, "_")
|
108
|
+
.downcase
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/gaapi/version.rb
CHANGED
data/lib/gaapi.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
# http://www.rubydoc.info/github/google/google-api-ruby-client/
|
4
4
|
require "google/apis/analyticsreporting_v4"
|
5
5
|
require "googleauth"
|
6
|
-
require "gaapi/access_token.rb"
|
7
|
-
require "gaapi/main.rb"
|
8
|
-
require "gaapi/query.rb"
|
9
|
-
require "gaapi/response.rb"
|
6
|
+
# require "gaapi/access_token.rb"
|
7
|
+
# require "gaapi/main.rb"
|
8
|
+
# require "gaapi/query.rb"
|
9
|
+
# require "gaapi/response.rb"
|
10
|
+
Dir.glob("lib/gaapi/**/*.rb").each { |f| require f.gsub(%r{lib/}, "") }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gaapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Larry Reid
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-11-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chandler
|
@@ -90,12 +90,17 @@ executables:
|
|
90
90
|
extensions: []
|
91
91
|
extra_rdoc_files: []
|
92
92
|
files:
|
93
|
+
- CHANGELOG.md
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
93
96
|
- bin/gaapi
|
94
97
|
- lib/gaapi.rb
|
95
98
|
- lib/gaapi/access_token.rb
|
96
99
|
- lib/gaapi/main.rb
|
97
100
|
- lib/gaapi/query.rb
|
101
|
+
- lib/gaapi/report.rb
|
98
102
|
- lib/gaapi/response.rb
|
103
|
+
- lib/gaapi/row.rb
|
99
104
|
- lib/gaapi/version.rb
|
100
105
|
homepage: https://github.com/weenhanceit/gaapi
|
101
106
|
licenses:
|