keen 0.7.2 → 0.7.3
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.
- data/Gemfile +2 -0
- data/Gemfile.lock +4 -2
- data/README.md +26 -1
- data/lib/keen/client/publishing_methods.rb +40 -13
- data/lib/keen/client/querying_methods.rb +1 -1
- data/lib/keen/version.rb +1 -1
- data/lib/keen.rb +7 -6
- data/spec/integration/api_spec.rb +23 -0
- data/spec/keen/client/publishing_methods_spec.rb +52 -13
- data/spec/keen/client/querying_methods_spec.rb +13 -3
- data/spec/keen/keen_spec.rb +10 -1
- data/spec/spec_helper.rb +5 -1
- data/spec/synchrony/synchrony_spec.rb +4 -4
- metadata +2 -2
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
keen (0.7.
|
4
|
+
keen (0.7.3)
|
5
5
|
multi_json (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -42,6 +42,7 @@ GEM
|
|
42
42
|
guard (>= 1.8)
|
43
43
|
rspec (~> 2.13)
|
44
44
|
http_parser.rb (0.5.3)
|
45
|
+
json (1.7.7)
|
45
46
|
linecache (0.46)
|
46
47
|
rbx-require-relative (> 0.0.4)
|
47
48
|
listen (1.0.3)
|
@@ -50,7 +51,7 @@ GEM
|
|
50
51
|
rb-kqueue (>= 0.2)
|
51
52
|
lumberjack (1.0.3)
|
52
53
|
method_source (0.8.1)
|
53
|
-
multi_json (1.7.
|
54
|
+
multi_json (1.7.3)
|
54
55
|
pry (0.9.12.1)
|
55
56
|
coderay (~> 1.0.5)
|
56
57
|
method_source (~> 0.8)
|
@@ -94,6 +95,7 @@ DEPENDENCIES
|
|
94
95
|
em-synchrony
|
95
96
|
guard
|
96
97
|
guard-rspec
|
98
|
+
json (~> 1.7.7)
|
97
99
|
keen!
|
98
100
|
rake
|
99
101
|
rb-fchange
|
data/README.md
CHANGED
@@ -133,6 +133,26 @@ Detailed information on available parameters for each API resource can be found
|
|
133
133
|
|
134
134
|
### Other code examples
|
135
135
|
|
136
|
+
#### Batch publishing
|
137
|
+
|
138
|
+
The keen-gem supports publishing events in batches via the `publish_batch` method. Here's an example usage:
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
Keen.publish_batch(
|
142
|
+
:signups => [
|
143
|
+
{ :name => "Bob" },
|
144
|
+
{ :name => "Mary" }
|
145
|
+
],
|
146
|
+
:purchases => [
|
147
|
+
{ :price => 10 },
|
148
|
+
{ :price => 20 }
|
149
|
+
]
|
150
|
+
)
|
151
|
+
```
|
152
|
+
|
153
|
+
This call would publish 2 `signups` events and 2 `purchases` events - all in just one API call.
|
154
|
+
Batch publishing is ideal for loading historical events into Keen IO.
|
155
|
+
|
136
156
|
#### Authentication
|
137
157
|
|
138
158
|
To configure keen-gem in code, do as follows:
|
@@ -177,6 +197,10 @@ To track email opens, simply add an image to your email template that points to
|
|
177
197
|
|
178
198
|
### Changelog
|
179
199
|
|
200
|
+
##### 0.7.3
|
201
|
+
+ Add batch publishing support
|
202
|
+
+ Allow event collection names for querying methods to be symbols. Thanks to [cbartlett](https://github.com/cbartlett).
|
203
|
+
|
180
204
|
##### 0.7.2
|
181
205
|
+ Fix support for non-https API URL testing
|
182
206
|
|
@@ -223,5 +247,6 @@ Fire away with issues and pull requests!
|
|
223
247
|
+ [alexkwolfe](https://github.com/alexkwolfe)
|
224
248
|
+ [peteygao](https://github.com/peteygao)
|
225
249
|
+ [obieq](https://github.com/obieq)
|
226
|
-
|
250
|
+
+ [cbartlett](https://github.com/cbartlett)
|
251
|
+
|
227
252
|
Thanks everyone, you rock!
|
@@ -25,17 +25,27 @@ module Keen
|
|
25
25
|
ensure_project_id!
|
26
26
|
ensure_write_key!
|
27
27
|
check_event_data!(event_collection, properties)
|
28
|
+
publish_body(
|
29
|
+
api_event_collection_resource_path(event_collection),
|
30
|
+
MultiJson.encode(properties),
|
31
|
+
"publish")
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
# Publishes a batch of events
|
35
|
+
# See detailed documentation here
|
36
|
+
# https://keen.io/docs/api/reference/#post-request-body-example-of-batch-event-posting
|
37
|
+
#
|
38
|
+
# @param events - a hash where the keys are event collection names
|
39
|
+
# and the values are arrays of hashes (event properties)
|
40
|
+
#
|
41
|
+
# @return the JSON response from the API
|
42
|
+
def publish_batch(events)
|
43
|
+
ensure_project_id!
|
44
|
+
ensure_write_key!
|
45
|
+
publish_body(
|
46
|
+
api_events_resource_path,
|
47
|
+
MultiJson.encode(events),
|
48
|
+
"publish")
|
39
49
|
end
|
40
50
|
|
41
51
|
# Publishes an asynchronous event
|
@@ -55,7 +65,7 @@ module Keen
|
|
55
65
|
|
56
66
|
http_client = Keen::HTTP::Async.new(self.api_url)
|
57
67
|
http = http_client.post(
|
58
|
-
:path =>
|
68
|
+
:path => api_event_collection_resource_path(event_collection),
|
59
69
|
:headers => api_headers(self.write_key, "async"),
|
60
70
|
:body => MultiJson.encode(properties)
|
61
71
|
)
|
@@ -98,15 +108,32 @@ module Keen
|
|
98
108
|
def beacon_url(event_collection, properties)
|
99
109
|
json = MultiJson.encode(properties)
|
100
110
|
data = [json].pack("m0").tr("+/", "-_").gsub("\n", "")
|
101
|
-
"#{self.api_url}#{
|
111
|
+
"#{self.api_url}#{api_event_collection_resource_path(event_collection)}?api_key=#{self.write_key}&data=#{data}"
|
102
112
|
end
|
103
113
|
|
104
114
|
private
|
105
115
|
|
106
|
-
def
|
116
|
+
def publish_body(path, body, error_method)
|
117
|
+
begin
|
118
|
+
response = Keen::HTTP::Sync.new(
|
119
|
+
self.api_url).post(
|
120
|
+
:path => path,
|
121
|
+
:headers => api_headers(self.write_key, "sync"),
|
122
|
+
:body => body)
|
123
|
+
rescue Exception => http_error
|
124
|
+
raise HttpError.new("HTTP #{error_method} failure: #{http_error.message}", http_error)
|
125
|
+
end
|
126
|
+
process_response(response.code, response.body.chomp)
|
127
|
+
end
|
128
|
+
|
129
|
+
def api_event_collection_resource_path(event_collection)
|
107
130
|
"/#{api_version}/projects/#{project_id}/events/#{URI.escape(event_collection)}"
|
108
131
|
end
|
109
132
|
|
133
|
+
def api_events_resource_path
|
134
|
+
"/#{api_version}/projects/#{project_id}/events"
|
135
|
+
end
|
136
|
+
|
110
137
|
def check_event_data!(event_collection, properties)
|
111
138
|
raise ArgumentError, "Event collection can not be nil" unless event_collection
|
112
139
|
raise ArgumentError, "Event properties can not be nil" unless properties
|
data/lib/keen/version.rb
CHANGED
data/lib/keen.rb
CHANGED
@@ -25,19 +25,20 @@ module Keen
|
|
25
25
|
class << self
|
26
26
|
extend Forwardable
|
27
27
|
|
28
|
-
def_delegators :default_client,
|
29
|
-
:project_id, :project_id=,
|
30
|
-
:write_key, :write_key=,
|
31
|
-
:read_key, :read_key=,
|
28
|
+
def_delegators :default_client,
|
29
|
+
:project_id, :project_id=,
|
30
|
+
:write_key, :write_key=,
|
31
|
+
:read_key, :read_key=,
|
32
32
|
:api_url, :api_url=
|
33
33
|
|
34
34
|
def_delegators :default_client,
|
35
|
-
:publish, :publish_async,
|
35
|
+
:publish, :publish_async, :publish_batch,
|
36
36
|
:beacon_url
|
37
37
|
|
38
38
|
def_delegators :default_client,
|
39
39
|
:count, :count_unique, :minimum, :maximum,
|
40
|
-
:sum, :average, :select_unique, :funnel, :extraction
|
40
|
+
:sum, :average, :select_unique, :funnel, :extraction,
|
41
|
+
:multi_analysis
|
41
42
|
|
42
43
|
attr_writer :logger
|
43
44
|
|
@@ -60,6 +60,29 @@ describe "Keen IO API" do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
63
|
+
|
64
|
+
describe "batch" do
|
65
|
+
it "should publish a batch of events" do
|
66
|
+
Keen.publish_batch(
|
67
|
+
:batch_signups => [
|
68
|
+
{ :name => "bob" },
|
69
|
+
{ :name => "ted" }
|
70
|
+
],
|
71
|
+
:batch_purchases => [
|
72
|
+
{ :price => 30 },
|
73
|
+
{ :price => 40 }
|
74
|
+
]
|
75
|
+
).should == {
|
76
|
+
"batch_purchases" => [
|
77
|
+
{ "success" => true },
|
78
|
+
{ "success" => true }
|
79
|
+
],
|
80
|
+
"batch_signups" => [
|
81
|
+
{ "success" => true },
|
82
|
+
{ "success"=>true }
|
83
|
+
]}
|
84
|
+
end
|
85
|
+
end
|
63
86
|
end
|
64
87
|
|
65
88
|
describe "queries" do
|
@@ -13,14 +13,14 @@ describe Keen::Client::PublishingMethods do
|
|
13
13
|
|
14
14
|
describe "publish" do
|
15
15
|
it "should post using the collection and properties" do
|
16
|
-
stub_keen_post(
|
16
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, "")
|
17
17
|
client.publish(collection, event_properties)
|
18
|
-
expect_keen_post(
|
18
|
+
expect_keen_post(api_event_collection_resource_url(api_url, collection), event_properties, "sync", write_key)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should return the proper response" do
|
22
22
|
api_response = { "created" => true }
|
23
|
-
stub_keen_post(
|
23
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_response)
|
24
24
|
client.publish(collection, event_properties).should == api_response
|
25
25
|
end
|
26
26
|
|
@@ -37,13 +37,13 @@ describe Keen::Client::PublishingMethods do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should url encode the event collection" do
|
40
|
-
stub_keen_post(
|
40
|
+
stub_keen_post(api_event_collection_resource_url(api_url, "foo%20bar"), 201, "")
|
41
41
|
client.publish("foo bar", event_properties)
|
42
|
-
expect_keen_post(
|
42
|
+
expect_keen_post(api_event_collection_resource_url(api_url, "foo%20bar"), event_properties, "sync", write_key)
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should wrap exceptions" do
|
46
|
-
stub_request(:post,
|
46
|
+
stub_request(:post, api_event_collection_resource_url(api_url, collection)).to_timeout
|
47
47
|
e = nil
|
48
48
|
begin
|
49
49
|
client.publish(collection, event_properties)
|
@@ -73,6 +73,45 @@ describe Keen::Client::PublishingMethods do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
describe "publish_batch" do
|
77
|
+
let(:events) {
|
78
|
+
{
|
79
|
+
:purchases => [
|
80
|
+
{ :price => 10 },
|
81
|
+
{ :price => 11 }
|
82
|
+
],
|
83
|
+
:signups => [
|
84
|
+
{ :name => "bob" },
|
85
|
+
{ :name => "bill" }
|
86
|
+
]
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
it "should raise an exception if client has no project_id" do
|
91
|
+
expect {
|
92
|
+
Keen::Client.new(
|
93
|
+
:write_key => "abcde"
|
94
|
+
).publish_batch(events)
|
95
|
+
}.to raise_error(Keen::ConfigurationError, "Keen IO Exception: Project ID must be set")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should raise an exception if client has no write_key" do
|
99
|
+
expect {
|
100
|
+
Keen::Client.new(
|
101
|
+
:project_id => "12345"
|
102
|
+
).publish_batch(events)
|
103
|
+
}.to raise_error(Keen::ConfigurationError, "Keen IO Exception: Write Key must be set for sending events")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should publish a batch of events" do
|
107
|
+
stub_keen_post(api_event_resource_url(api_url), 201, "")
|
108
|
+
client.publish_batch(events)
|
109
|
+
expect_keen_post(
|
110
|
+
api_event_resource_url(api_url),
|
111
|
+
events, "sync", write_key)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
76
115
|
describe "publish_async" do
|
77
116
|
# no TLS support in EventMachine on jRuby
|
78
117
|
unless defined?(JRUBY_VERSION)
|
@@ -83,11 +122,11 @@ describe Keen::Client::PublishingMethods do
|
|
83
122
|
end
|
84
123
|
|
85
124
|
it "should post the event data" do
|
86
|
-
stub_keen_post(
|
125
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_success)
|
87
126
|
EM.run {
|
88
127
|
client.publish_async(collection, event_properties).callback {
|
89
128
|
begin
|
90
|
-
expect_keen_post(
|
129
|
+
expect_keen_post(api_event_collection_resource_url(api_url, collection), event_properties, "async", write_key)
|
91
130
|
ensure
|
92
131
|
EM.stop
|
93
132
|
end
|
@@ -99,11 +138,11 @@ describe Keen::Client::PublishingMethods do
|
|
99
138
|
end
|
100
139
|
|
101
140
|
it "should uri encode the event collection" do
|
102
|
-
stub_keen_post(
|
141
|
+
stub_keen_post(api_event_collection_resource_url(api_url, "foo%20bar"), 201, api_success)
|
103
142
|
EM.run {
|
104
143
|
client.publish_async("foo bar", event_properties).callback {
|
105
144
|
begin
|
106
|
-
expect_keen_post(
|
145
|
+
expect_keen_post(api_event_collection_resource_url(api_url, "foo%20bar"), event_properties, "async", write_key)
|
107
146
|
ensure
|
108
147
|
EM.stop
|
109
148
|
end
|
@@ -128,7 +167,7 @@ describe Keen::Client::PublishingMethods do
|
|
128
167
|
|
129
168
|
describe "deferrable callbacks" do
|
130
169
|
it "should trigger callbacks" do
|
131
|
-
stub_keen_post(
|
170
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_success)
|
132
171
|
EM.run {
|
133
172
|
client.publish_async(collection, event_properties).callback { |response|
|
134
173
|
begin
|
@@ -141,7 +180,7 @@ describe Keen::Client::PublishingMethods do
|
|
141
180
|
end
|
142
181
|
|
143
182
|
it "should trigger errbacks" do
|
144
|
-
stub_request(:post,
|
183
|
+
stub_request(:post, api_event_collection_resource_url(api_url, collection)).to_timeout
|
145
184
|
EM.run {
|
146
185
|
client.publish_async(collection, event_properties).errback { |error|
|
147
186
|
begin
|
@@ -155,7 +194,7 @@ describe Keen::Client::PublishingMethods do
|
|
155
194
|
end
|
156
195
|
|
157
196
|
it "should not trap exceptions in the client callback" do
|
158
|
-
stub_keen_post(
|
197
|
+
stub_keen_post(api_event_collection_resource_url(api_url, "foo%20bar"), 201, api_success)
|
159
198
|
expect {
|
160
199
|
EM.run {
|
161
200
|
client.publish_async("foo bar", event_properties).callback {
|
@@ -113,13 +113,23 @@ describe Keen::Client do
|
|
113
113
|
end
|
114
114
|
|
115
115
|
describe "#count" do
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
let(:query_params) { "?event_collection=#{event_collection}" }
|
117
|
+
let(:url) { query_url("count", query_params) }
|
118
|
+
before do
|
119
119
|
stub_keen_get(url, 200, :result => 10)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should not require params" do
|
120
123
|
client.count(event_collection).should == 10
|
121
124
|
expect_keen_get(url, "sync", read_key)
|
122
125
|
end
|
126
|
+
|
127
|
+
context "with event collection as symbol" do
|
128
|
+
let(:event_collection) { :users }
|
129
|
+
it "should not require a string" do
|
130
|
+
client.count(event_collection).should == 10
|
131
|
+
end
|
132
|
+
end
|
123
133
|
end
|
124
134
|
|
125
135
|
describe "#extraction" do
|
data/spec/keen/keen_spec.rb
CHANGED
@@ -62,12 +62,21 @@ describe Keen do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
[:publish, :publish_async].each do |_method|
|
65
|
+
[:publish, :publish_async, :publish_batch].each do |_method|
|
66
66
|
it "should forward the #{_method} method" do
|
67
67
|
@default_client.should_receive(_method).with("users", {})
|
68
68
|
Keen.send(_method, "users", {})
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
# pull the query methods list at runtime in order to ensure
|
73
|
+
# any new methods have a corresponding delegator
|
74
|
+
Keen::Client::QueryingMethods.instance_methods.each do |_method|
|
75
|
+
it "should forward the #{_method} query method" do
|
76
|
+
@default_client.should_receive(_method).with("users", {})
|
77
|
+
Keen.send(_method, "users", {})
|
78
|
+
end
|
79
|
+
end
|
71
80
|
end
|
72
81
|
|
73
82
|
describe "logger" do
|
data/spec/spec_helper.rb
CHANGED
@@ -48,9 +48,13 @@ module Keen::SpecHelpers
|
|
48
48
|
expect_keen_request(:post, url, MultiJson.encode(event_properties), sync_or_async_ua, write_key)
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
51
|
+
def api_event_collection_resource_url(base_url, collection)
|
52
52
|
"#{base_url}/3.0/projects/#{project_id}/events/#{collection}"
|
53
53
|
end
|
54
|
+
|
55
|
+
def api_event_resource_url(base_url)
|
56
|
+
"#{base_url}/3.0/projects/#{project_id}/events"
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
RSpec.configure do |config|
|
@@ -17,16 +17,16 @@ describe Keen::HTTP::Async do
|
|
17
17
|
|
18
18
|
describe "success" do
|
19
19
|
it "should post the event data" do
|
20
|
-
stub_keen_post(
|
20
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_success)
|
21
21
|
EM.synchrony {
|
22
22
|
@client.publish_async(collection, event_properties)
|
23
|
-
expect_keen_post(
|
23
|
+
expect_keen_post(api_event_collection_resource_url(api_url, collection), event_properties, "async", write_key)
|
24
24
|
EM.stop
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should recieve the right response 'synchronously'" do
|
29
|
-
stub_keen_post(
|
29
|
+
stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_success)
|
30
30
|
EM.synchrony {
|
31
31
|
@client.publish_async(collection, event_properties).should == api_success
|
32
32
|
EM.stop
|
@@ -36,7 +36,7 @@ describe Keen::HTTP::Async do
|
|
36
36
|
|
37
37
|
describe "failure" do
|
38
38
|
it "should raise an exception" do
|
39
|
-
stub_request(:post,
|
39
|
+
stub_request(:post, api_event_collection_resource_url(api_url, collection)).to_timeout
|
40
40
|
e = nil
|
41
41
|
EM.synchrony {
|
42
42
|
begin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-05-
|
14
|
+
date: 2013-05-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: multi_json
|