keen 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Keen IO Official Ruby Client Library
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/keenlabs/keen-gem.png?branch=master)](http://travis-ci.org/keenlabs/keen-gem) [![Code Climate](https://codeclimate.com/github/keenlabs/keen-gem.png)](https://codeclimate.com/github/keenlabs/keen-gem)
4
+ [![Gem Version](https://badge.fury.io/rb/keen.svg)](http://badge.fury.io/rb/keen)
4
5
 
5
6
  keen-gem is the official Ruby Client for the [Keen IO](https://keen.io/) API. The
6
7
  Keen IO API lets developers build analytics features directly into their apps.
@@ -48,7 +49,7 @@ environment-based approach because it keeps sensitive information out of the cod
48
49
 
49
50
  Once your environment is properly configured, the `Keen` object is ready to go immediately.
50
51
 
51
- ### Publishing events
52
+ ### Synchronous Publishing
52
53
 
53
54
  Publishing events requires that `KEEN_WRITE_KEY` is set. Publish an event like this:
54
55
 
@@ -57,18 +58,17 @@ Keen.publish(:sign_ups, { :username => "lloyd", :referred_by => "harry" })
57
58
  ```
58
59
 
59
60
  This will publish an event to the `sign_ups` collection with the `username` and `referred_by` properties set.
60
- The event properties can be any valid Ruby hash and nested properties are allowed. You can learn more about data modeling with Keen IO with the [Data Modeling Guide](https://keen.io/docs/event-data-modeling/event-data-intro/).
61
+ The event properties can be any valid Ruby hash. Nested properties are allowed. Lists of objects are also allowed, but not recommended because they can be difficult to query over. See alternatives to lists of objects [here](http://stackoverflow.com/questions/24620330/nested-json-objects-in-keen-io). You can learn more about data modeling with Keen IO with the [Data Modeling Guide](https://keen.io/docs/event-data-modeling/event-data-intro/).
62
+
63
+ Protip: Marshalling gems like [Blockhead](https://github.com/vinniefranco/blockhead) make converting structs or objects to hashes easier.
61
64
 
62
65
  The event collection need not exist in advance. If it doesn't exist, Keen IO will create it on the first request.
63
66
 
64
67
  ### Asynchronous publishing
65
68
 
66
- Publishing events shouldn't slow your application down or make
67
- users wait longer for page loads & server requests.
69
+ Publishing events shouldn't slow your application down or make users wait longer for page loads & server requests.
68
70
 
69
- The Keen IO API is fast, but any synchronous network call you make will
70
- negatively impact response times. For this reason, we recommend you use the `publish_async`
71
- method to send events.
71
+ The Keen IO API is fast, but any synchronous network call you make will negatively impact response times. For this reason, we recommend you use the `publish_async` method to send events when latency is a concern. Alternatively, you can drop events into a background queue e.g. Delayed Jobs and publish synchronously from there.
72
72
 
73
73
  To compare asychronous vs. synchronous performance, check out the [keen-gem-example](http://keen-gem-example.herokuapp.com/) app.
74
74
 
@@ -91,7 +91,7 @@ Thread.new { EventMachine.run }
91
91
  The best place for this is in an initializer, or anywhere that runs when your app boots up.
92
92
  Here's a useful blog article that explains more about this approach - [EventMachine and Passenger](http://railstips.org/blog/archives/2011/05/04/eventmachine-and-passenger/).
93
93
 
94
- And here's an example repository that shows an example of [Eventmachine with Unicorn](https://github.com/dzello/em-unicorn/blob/master/unicorn.rb), specifically the Unicorn config for starting and stopping EventMachine after forking.
94
+ And here's a gist that shows an example of [Eventmachine with Unicorn](https://gist.github.com/jonkgrimes/5103321), specifically the Unicorn config for starting and stopping EventMachine after forking.
95
95
 
96
96
  Now, in your code, replace `publish` with `publish_async`. Bind callbacks if you require them.
97
97
 
@@ -143,6 +143,32 @@ Many of these queries can be performed with group by, filters, series and interv
143
143
 
144
144
  Detailed information on available parameters for each API resource can be found on the [API Technical Reference](https://keen.io/docs/api/reference/).
145
145
 
146
+ ##### The Query Method
147
+
148
+ You can also specify the analysis type as a parameter to a method called `query`:
149
+
150
+ ``` ruby
151
+ Keen.query("median", "purchases", :target_property => "price") # => 60
152
+ ```
153
+
154
+ This simplifes querying code where the analysis type is dynamic.
155
+
156
+ ##### Getting Query URLs
157
+
158
+ Sometimes you just want the URL for a query, but don't actually need to run it. Maybe to paste into a dashboard, or open in your browser. In that case, use the `query_url` method:
159
+
160
+ ``` ruby
161
+ Keen.query_url("median", "purchases", :target_property => "price")
162
+ # => "https://api.keen.io/3.0/projects/<project-id>/queries/median?target_property=price&event_collection=purchases&api_key=<api-key>"
163
+ ```
164
+
165
+ If you don't want the API key included, pass the `:exclude_api_key` option:
166
+
167
+ ``` ruby
168
+ Keen.query_url("median", "purchases", { :target_property => "price" }, :exclude_api_key => true)
169
+ # => "https://api.keen.io/3.0/projects/<project-id>/queries/median?target_property=price&event_collection=purchases"
170
+ ```
171
+
146
172
  ### Listing collections
147
173
 
148
174
  The Keen IO API let you get the event collections for the project set, it includes properties and their type. It also returns links to the collection resource.
@@ -297,6 +323,10 @@ EventMachine itself won't do this because it runs in a different thread. Here's
297
323
 
298
324
  ### Changelog
299
325
 
326
+ ##### 0.8.5
327
+ + Add support for getting [query URLs](https://github.com/keenlabs/keen-gem/pull/47)
328
+ + Make the `query` method public so code supporting dynamic analysis types is easier to write
329
+
300
330
  ##### 0.8.4
301
331
  + Add support for getting [project details](https://keen.io/docs/api/reference/#project-row-resource)
302
332
 
@@ -49,7 +49,8 @@ module Keen
49
49
  def_delegators :default_client,
50
50
  :delete,
51
51
  :event_collections,
52
- :project_info
52
+ :project_info,
53
+ :query_url
53
54
 
54
55
  attr_writer :logger
55
56
 
@@ -191,33 +191,58 @@ module Keen
191
191
  query(__method__, event_collection, params)
192
192
  end
193
193
 
194
+ # Returns the URL for a Query without running it
195
+ # @param event_colection
196
+ # @param params [Hash] (required)
197
+ # analysis_type (required)
198
+ # group_by (optional)
199
+ # timeframe (optional)
200
+ # interval (optional)
201
+ # filters (optional) [Array]
202
+ # timezone (optional)
203
+ # @param options
204
+ # exclude_api_key
205
+ def query_url(analysis_type, event_collection, params={}, options={})
206
+ str = _query_url(analysis_type, event_collection, params)
207
+ str << "&api_key=#{self.read_key}" unless options[:exclude_api_key]
208
+ str
209
+ end
210
+
211
+ # Run a query
212
+ # @param event_colection
213
+ # @param params [Hash] (required)
214
+ # analysis_type (required)
215
+ # group_by (optional)
216
+ # timeframe (optional)
217
+ # interval (optional)
218
+ # filters (optional) [Array]
219
+ # timezone (optional)
220
+ def query(analysis_type, event_collection, params={})
221
+ url = _query_url(analysis_type, event_collection, params)
222
+ response = get_response(url)
223
+ response_body = response.body.chomp
224
+ process_response(response.code, response_body)["result"]
225
+ end
226
+
194
227
  private
195
228
 
196
- def query(query_name, event_collection, params)
197
- query_params = clone_params(params)
229
+ def _query_url(analysis_type, event_collection, params={})
198
230
  ensure_project_id!
199
231
  ensure_read_key!
200
232
 
201
- if event_collection
202
- query_params[:event_collection] = event_collection.to_s
203
- end
204
-
205
- query_params = preprocess_params(query_params)
206
-
207
- begin
208
- response = Keen::HTTP::Sync.new(self.api_url, self.proxy_url).get(
209
- :path => "#{api_query_resource_path(query_name)}?#{query_params}",
210
- :headers => api_headers(self.read_key, "sync"))
211
- rescue Exception => http_error
212
- raise HttpError.new("Couldn't perform #{query_name} on Keen IO: #{http_error.message}", http_error)
213
- end
214
-
215
- response_body = response.body.chomp
216
- process_response(response.code, response_body)["result"]
233
+ query_params = params.dup
234
+ query_params[:event_collection] = event_collection.to_s if event_collection
235
+ "#{self.api_url}#{api_query_resource_path(analysis_type)}?#{preprocess_params(query_params)}"
217
236
  end
218
237
 
219
- def clone_params(params)
220
- params.dup
238
+ def get_response(url)
239
+ uri = URI.parse(url)
240
+ Keen::HTTP::Sync.new(self.api_url, self.proxy_url).get(
241
+ :path => "#{uri.path}?#{uri.query}",
242
+ :headers => api_headers(self.read_key, "sync")
243
+ )
244
+ rescue Exception => http_error
245
+ raise HttpError.new("Couldn't perform #{@analysis_type} on Keen IO: #{http_error.message}", http_error)
221
246
  end
222
247
 
223
248
  def api_query_resource_path(analysis_type)
@@ -1,3 +1,3 @@
1
1
  module Keen
2
- VERSION = "0.8.4"
2
+ VERSION = "0.8.5"
3
3
  end
@@ -172,4 +172,22 @@ describe Keen::Client do
172
172
  expect_keen_get(url, "sync", read_key)
173
173
  end
174
174
  end
175
+
176
+ describe "#query_url" do
177
+ let(:expected) { }
178
+
179
+ it "should returns the URL for a query" do
180
+ response = client.query_url('count', event_collection)
181
+ expect(response).to eq 'https://notreal.keen.io/3.0/projects/12345/queries/count?event_collection=users&api_key=abcde'
182
+ end
183
+
184
+ it "should exclude the api key if option is passed" do
185
+ response = client.query_url('count', event_collection, {}, :exclude_api_key => true)
186
+ expect(response).to eq 'https://notreal.keen.io/3.0/projects/12345/queries/count?event_collection=users'
187
+ end
188
+
189
+ it "should not run the query" do
190
+ Keen::HTTP::Sync.should_not receive(:new)
191
+ end
192
+ end
175
193
  end
@@ -94,6 +94,7 @@ describe Keen do
94
94
  # pull the query methods list at runtime in order to ensure
95
95
  # any new methods have a corresponding delegator
96
96
  Keen::Client::QueryingMethods.instance_methods.each do |_method|
97
+ next if _method.to_sym == :query
97
98
  it "should forward the #{_method} query method" do
98
99
  @default_client.should_receive(_method).with("users", {})
99
100
  Keen.send(_method, "users", {})
metadata CHANGED
@@ -1,184 +1,79 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: keen
3
- version: !ruby/object:Gem::Version
4
- version: 0.8.4
3
+ version: !ruby/object:Gem::Version
4
+ hash: 53
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 5
10
+ version: 0.8.5
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Kyle Wild
9
14
  - Josh Dzielak
10
15
  - Daniel Kador
11
16
  autorequire:
12
17
  bindir: bin
13
18
  cert_chain: []
14
- date: 2014-07-03 00:00:00.000000000 Z
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
19
+
20
+ date: 2014-08-01 00:00:00 -07:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
17
24
  name: multi_json
18
- requirement: !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ~>
22
- - !ruby/object:Gem::Version
23
- version: '1.3'
24
- type: :runtime
25
25
  prerelease: false
26
- version_requirements: !ruby/object:Gem::Requirement
27
- none: false
28
- requirements:
29
- - - ~>
30
- - !ruby/object:Gem::Version
31
- version: '1.3'
32
- - !ruby/object:Gem::Dependency
33
- name: addressable
34
- requirement: !ruby/object:Gem::Requirement
26
+ requirement: &id001 !ruby/object:Gem::Requirement
35
27
  none: false
36
- requirements:
28
+ requirements:
37
29
  - - ~>
38
- - !ruby/object:Gem::Version
39
- version: 2.3.5
30
+ - !ruby/object:Gem::Version
31
+ hash: 9
32
+ segments:
33
+ - 1
34
+ - 3
35
+ version: "1.3"
40
36
  type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: addressable
41
40
  prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
41
+ requirement: &id002 !ruby/object:Gem::Requirement
43
42
  none: false
44
- requirements:
43
+ requirements:
45
44
  - - ~>
46
- - !ruby/object:Gem::Version
45
+ - !ruby/object:Gem::Version
46
+ hash: 9
47
+ segments:
48
+ - 2
49
+ - 3
50
+ - 5
47
51
  version: 2.3.5
48
- - !ruby/object:Gem::Dependency
49
- name: guard
50
- requirement: !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
57
- prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- none: false
60
- requirements:
61
- - - ! '>='
62
- - !ruby/object:Gem::Version
63
- version: '0'
64
- - !ruby/object:Gem::Dependency
65
- name: guard-rspec
66
- requirement: !ruby/object:Gem::Requirement
67
- none: false
68
- requirements:
69
- - - ! '>='
70
- - !ruby/object:Gem::Version
71
- version: '0'
72
- type: :development
73
- prerelease: false
74
- version_requirements: !ruby/object:Gem::Requirement
75
- none: false
76
- requirements:
77
- - - ! '>='
78
- - !ruby/object:Gem::Version
79
- version: '0'
80
- - !ruby/object:Gem::Dependency
81
- name: rb-inotify
82
- requirement: !ruby/object:Gem::Requirement
83
- none: false
84
- requirements:
85
- - - ! '>='
86
- - !ruby/object:Gem::Version
87
- version: '0'
88
- type: :development
89
- prerelease: false
90
- version_requirements: !ruby/object:Gem::Requirement
91
- none: false
92
- requirements:
93
- - - ! '>='
94
- - !ruby/object:Gem::Version
95
- version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: rb-fsevent
98
- requirement: !ruby/object:Gem::Requirement
99
- none: false
100
- requirements:
101
- - - ! '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- none: false
108
- requirements:
109
- - - ! '>='
110
- - !ruby/object:Gem::Version
111
- version: '0'
112
- - !ruby/object:Gem::Dependency
113
- name: rb-fchange
114
- requirement: !ruby/object:Gem::Requirement
115
- none: false
116
- requirements:
117
- - - ! '>='
118
- - !ruby/object:Gem::Version
119
- version: '0'
120
- type: :development
121
- prerelease: false
122
- version_requirements: !ruby/object:Gem::Requirement
123
- none: false
124
- requirements:
125
- - - ! '>='
126
- - !ruby/object:Gem::Version
127
- version: '0'
128
- - !ruby/object:Gem::Dependency
129
- name: ruby_gntp
130
- requirement: !ruby/object:Gem::Requirement
131
- none: false
132
- requirements:
133
- - - ! '>='
134
- - !ruby/object:Gem::Version
135
- version: '0'
136
- type: :development
52
+ type: :runtime
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: ruby-debug
137
56
  prerelease: false
138
- version_requirements: !ruby/object:Gem::Requirement
139
- none: false
140
- requirements:
141
- - - ! '>='
142
- - !ruby/object:Gem::Version
143
- version: '0'
144
- - !ruby/object:Gem::Dependency
145
- name: rb-readline
146
- requirement: !ruby/object:Gem::Requirement
147
- none: false
148
- requirements:
149
- - - ! '>='
150
- - !ruby/object:Gem::Version
151
- version: '0'
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
152
66
  type: :development
153
- prerelease: false
154
- version_requirements: !ruby/object:Gem::Requirement
155
- none: false
156
- requirements:
157
- - - ! '>='
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- - !ruby/object:Gem::Dependency
161
- name: debugger
162
- requirement: !ruby/object:Gem::Requirement
163
- none: false
164
- requirements:
165
- - - ! '>='
166
- - !ruby/object:Gem::Version
167
- version: '0'
168
- type: :development
169
- prerelease: false
170
- version_requirements: !ruby/object:Gem::Requirement
171
- none: false
172
- requirements:
173
- - - ! '>='
174
- - !ruby/object:Gem::Version
175
- version: '0'
67
+ version_requirements: *id003
176
68
  description: Send events and build analytics features into your Ruby applications.
177
69
  email: josh@keen.io
178
70
  executables: []
71
+
179
72
  extensions: []
73
+
180
74
  extra_rdoc_files: []
181
- files:
75
+
76
+ files:
182
77
  - .gitignore
183
78
  - .rspec
184
79
  - .travis.yml
@@ -210,32 +105,41 @@ files:
210
105
  - spec/spec_helper.rb
211
106
  - spec/synchrony/spec_helper.rb
212
107
  - spec/synchrony/synchrony_spec.rb
108
+ has_rdoc: true
213
109
  homepage: https://github.com/keenlabs/keen-gem
214
- licenses:
110
+ licenses:
215
111
  - MIT
216
112
  post_install_message:
217
113
  rdoc_options: []
218
- require_paths:
114
+
115
+ require_paths:
219
116
  - lib
220
- required_ruby_version: !ruby/object:Gem::Requirement
117
+ required_ruby_version: !ruby/object:Gem::Requirement
221
118
  none: false
222
- requirements:
223
- - - ! '>='
224
- - !ruby/object:Gem::Version
225
- version: '0'
226
- required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
227
127
  none: false
228
- requirements:
229
- - - ! '>='
230
- - !ruby/object:Gem::Version
231
- version: '0'
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
232
135
  requirements: []
136
+
233
137
  rubyforge_project:
234
- rubygems_version: 1.8.23
138
+ rubygems_version: 1.6.2
235
139
  signing_key:
236
140
  specification_version: 3
237
141
  summary: Keen IO API Client
238
- test_files:
142
+ test_files:
239
143
  - spec/integration/api_spec.rb
240
144
  - spec/integration/spec_helper.rb
241
145
  - spec/keen/client/maintenance_methods_spec.rb