keen 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ Gemfile.lock
3
3
  tmp
4
4
  .env
5
5
  log
6
+ *.gem
data/.travis.yml CHANGED
@@ -8,10 +8,16 @@ rvm:
8
8
  - rbx-19mode
9
9
 
10
10
  env:
11
- global:
12
- - KEEN_API_KEY=f806128f31c349fda124b62d1f4cf4b2
13
- - KEEN_PROJECT_ID=50e5ffa6897a2c319b000000
11
+ - PATTERN=keen
12
+ - PATTERN=integration KEEN_API_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_PROJECT_ID=50e5ffa6897a2c319b000000
13
+ - PATTERN=synchrony
14
+
15
+ matrix:
16
+ exclude:
17
+ - rvm: 1.8.7
18
+ env: PATTERN=synchrony
19
+ - rvm: jruby-19mode
20
+ env: PATTERN=synchrony
14
21
 
15
22
  script:
16
- - bundle exec rake spec
17
- - bundle exec rake integration
23
+ - bundle exec rake pattern
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ group :development, :test do
6
6
  gem 'rake'
7
7
  gem 'rspec'
8
8
  gem 'em-http-request'
9
+ gem 'em-synchrony', :require => false
9
10
  gem 'webmock'
10
11
  end
11
12
 
data/Guardfile CHANGED
@@ -14,3 +14,11 @@ group :integration do
14
14
  watch(%r{^spec/integration/.+_spec\.rb$})
15
15
  end
16
16
  end
17
+
18
+ group :synchrony do
19
+ guard 'rspec', :spec_paths => "spec/synchrony" do
20
+ watch('spec/spec_helper.rb') { "spec" }
21
+ watch('spec/synchrony/spec_helper.rb') { "spec" }
22
+ watch(%r{^spec/synchrony/.+_spec\.rb$})
23
+ end
24
+ end
data/README.md CHANGED
@@ -23,7 +23,7 @@ keen is tested with Ruby 1.8 and 1.9 on:
23
23
 
24
24
  ### Usage
25
25
 
26
- Before making any API calls, you must supply the keen gem with a Project ID and an API Key.
26
+ Before making any API calls, you must supply keen-gem with a Project ID and an API Key.
27
27
  (If you need a Keen IO account, [sign up here](https://keen.io/) - it's free.)
28
28
 
29
29
  The recommended way to do this is to set `KEEN_PROJECT_ID` and `KEEN_API_KEY` in your
@@ -80,22 +80,40 @@ to resume processing immediately.
80
80
 
81
81
  ### Other code examples
82
82
 
83
- ##### Authentication
83
+ #### Authentication
84
84
 
85
- To configure the keen gem credentials in code, do as follows:
85
+ To configure keen-gem credentials in code, do as follows:
86
86
 
87
87
  Keen.project_id = 'your-project-id'
88
88
  Keen.api_key = 'your-api-key'
89
89
 
90
90
  You can also configure individual client instances as follows:
91
91
 
92
- keen = new Keen::Client.new(:project_id => 'your-project-id',
93
- :api_key => 'your-api-key')
92
+ keen = Keen::Client.new(:project_id => 'your-project-id',
93
+ :api_key => 'your-api-key')
94
94
 
95
- ##### On keen.io
95
+ #### em-synchrony
96
+ keen-gem can be used with [em-synchrony](https://github.com/igrigorik/em-synchrony).
97
+ If you call `publish_async` and `EM::Synchrony` is defined the method will return the response
98
+ directly. (It does not return the deferrable on which to register callbacks.) Likewise, it will raise
99
+ exceptions 'synchronously' should they happen.
96
100
 
97
- For more information and examples visit the
98
- Keen IO [Ruby Usage Guide](https://keen.io/docs/clients/ruby/usage-guide/).
101
+ #### Beacon URL's
102
+
103
+ It's possible to publish events to your Keen IO project using the HTTP GET method.
104
+ This is useful for situations like tracking email opens using [image beacons](http://en.wikipedia.org/wiki/Web_bug).
105
+
106
+ In this situation, the JSON event data is passed by encoding it base-64 and adding it as a request parameter called `data`.
107
+ The `beacon_url` method found on the `Keen::Client` does this for you. Here's an example:
108
+
109
+ keen = Keen::Client.new(:project_id => '12345',
110
+ :api_key => 'abcde')
111
+
112
+ keen.beacon_url("sign_ups", :recipient => "foo@foo.com")
113
+ # => "https://api.keen.io/3.0/projects/50e5ffa6897a2c319b000000/events/ \
114
+ email_opens?api_key=f806128f31c349fda124b62d1f4cf4b2&data=eyJyZWNpcGllbnQiOiJmb29AZm9vLmNvbSJ9"
115
+
116
+ To track email opens, simply add an image to your email template that points to this URL.
99
117
 
100
118
  ### Questions & Support
101
119
 
@@ -103,3 +121,6 @@ If you have any questions, bugs, or suggestions, please
103
121
  report them via Github Issues. Or, come chat with us anytime
104
122
  at [users.keen.io](http://users.keen.io). We'd love to hear your feedback and ideas!
105
123
 
124
+ ### Contributing
125
+ keen-gem is an open source project and we welcome your contributions.
126
+ Fire away with issues and pull requests!
data/Rakefile CHANGED
@@ -11,5 +11,15 @@ RSpec::Core::RakeTask.new(:integration) do |t|
11
11
  t.pattern = "spec/integration/**/*_spec.rb"
12
12
  end
13
13
 
14
+ desc "Run Rspec synchrony tests"
15
+ RSpec::Core::RakeTask.new(:synchrony) do |t|
16
+ t.pattern = "spec/synchrony/**/*_spec.rb"
17
+ end
18
+
19
+ desc "Run Rspec pattern"
20
+ RSpec::Core::RakeTask.new(:pattern) do |t|
21
+ t.pattern = "spec/#{ENV['PATTERN']}/**/*_spec.rb"
22
+ end
23
+
14
24
  task :default => :spec
15
25
  task :test => [:spec]
data/lib/keen.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'logger'
2
2
  require 'forwardable'
3
- require 'multi_json'
4
3
 
5
4
  require 'keen/client'
6
5
 
@@ -23,7 +22,8 @@ module Keen
23
22
  extend Forwardable
24
23
 
25
24
  def_delegators :default_client, :project_id, :api_key,
26
- :project_id=, :api_key=, :publish, :publish_async
25
+ :project_id=, :api_key=, :publish, :publish_async,
26
+ :beacon_url
27
27
 
28
28
  attr_writer :logger
29
29
 
data/lib/keen/client.rb CHANGED
@@ -1,5 +1,8 @@
1
- require 'keen/version'
2
1
  require 'keen/http'
2
+ require 'keen/version'
3
+ require 'openssl'
4
+ require 'multi_json'
5
+ require 'base64'
3
6
 
4
7
  module Keen
5
8
  class Client
@@ -8,6 +11,7 @@ module Keen
8
11
  CONFIG = {
9
12
  :api_host => "api.keen.io",
10
13
  :api_port => 443,
14
+ :api_version => "3.0",
11
15
  :api_sync_http_options => {
12
16
  :use_ssl => true,
13
17
  :verify_mode => OpenSSL::SSL::VERIFY_PEER,
@@ -20,6 +24,12 @@ module Keen
20
24
  }
21
25
  }
22
26
 
27
+ def beacon_url(event_name, properties)
28
+ json = MultiJson.encode(properties)
29
+ data = [json].pack("m0").tr("+/", "-_").gsub("\n", "")
30
+ "https://#{api_host}/#{api_version}/projects/#{@project_id}/events/#{event_name}?api_key=#{@api_key}&data=#{data}"
31
+ end
32
+
23
33
  def initialize(*args)
24
34
  options = args[0]
25
35
  unless options.is_a?(Hash)
@@ -59,20 +69,29 @@ module Keen
59
69
  :headers => api_headers_with_auth,
60
70
  :body => MultiJson.encode(properties)
61
71
  })
62
- http.callback {
63
- begin
64
- response = process_response(http.response_header.status, http.response.chomp)
65
- deferrable.succeed(response)
66
- rescue Exception => e
67
- deferrable.fail(e)
68
- end
69
- }
70
- http.errback {
71
- Keen.logger.warn("Couldn't connect to Keen IO: #{http.error}")
72
- deferrable.fail(Error.new("Couldn't connect to Keen IO: #{http.error}"))
73
- }
74
72
 
75
- deferrable
73
+ if defined?(EM::Synchrony)
74
+ if http.error
75
+ Keen.logger.warn("Couldn't connect to Keen IO: #{http.error}")
76
+ raise HttpError.new("Couldn't connect to Keen IO: #{http.error}")
77
+ else
78
+ process_response(http.response_header.status, http.response.chomp)
79
+ end
80
+ else
81
+ http.callback {
82
+ begin
83
+ response = process_response(http.response_header.status, http.response.chomp)
84
+ deferrable.succeed(response)
85
+ rescue Exception => e
86
+ deferrable.fail(e)
87
+ end
88
+ }
89
+ http.errback {
90
+ Keen.logger.warn("Couldn't connect to Keen IO: #{http.error}")
91
+ deferrable.fail(Error.new("Couldn't connect to Keen IO: #{http.error}"))
92
+ }
93
+ deferrable
94
+ end
76
95
  end
77
96
 
78
97
  # deprecated
@@ -99,7 +118,7 @@ module Keen
99
118
  end
100
119
 
101
120
  def api_path(collection)
102
- "/3.0/projects/#{project_id}/events/#{collection}"
121
+ "/#{api_version}/projects/#{project_id}/events/#{collection}"
103
122
  end
104
123
 
105
124
  def api_headers_with_auth
data/lib/keen/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Keen
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3"
3
3
  end
@@ -7,24 +7,6 @@ describe Keen::Client do
7
7
  let(:event_properties) { { "name" => "Bob" } }
8
8
  let(:api_success) { { "created" => true } }
9
9
 
10
- def stub_api(url, status, json_body)
11
- stub_request(:post, url).to_return(
12
- :status => status,
13
- :body => MultiJson.encode(json_body))
14
- end
15
-
16
- def expect_post(url, event_properties, api_key)
17
- WebMock.should have_requested(:post, url).with(
18
- :body => MultiJson.encode(event_properties),
19
- :headers => { "Content-Type" => "application/json",
20
- "User-Agent" => "keen-gem v#{Keen::VERSION}",
21
- "Authorization" => api_key })
22
- end
23
-
24
- def api_url(collection)
25
- "https://api.keen.io/3.0/projects/#{project_id}/events/#{collection}"
26
- end
27
-
28
10
  describe "#initialize" do
29
11
  context "deprecated" do
30
12
  it "should allow created via project_id and api_key args" do
@@ -188,4 +170,12 @@ describe Keen::Client do
188
170
  end
189
171
  end
190
172
  end
173
+
174
+ describe "beacon_url" do
175
+ it "should return a url with a base-64 encoded json param" do
176
+ client = Keen::Client.new(project_id, api_key)
177
+ client.beacon_url("sign_ups", { :name => "Bob" }).should ==
178
+ "https://api.keen.io/3.0/projects/12345/events/sign_ups?api_key=abcde&data=eyJuYW1lIjoiQm9iIn0="
179
+ end
180
+ end
191
181
  end
@@ -4,6 +4,7 @@ describe Keen do
4
4
  describe "default client" do
5
5
  describe "configuring from the environment" do
6
6
  before do
7
+ Keen.instance_variable_set(:@default_client, nil)
7
8
  ENV["KEEN_PROJECT_ID"] = "12345"
8
9
  ENV["KEEN_API_KEY"] = "abcde"
9
10
  end
@@ -17,11 +18,6 @@ describe Keen do
17
18
  it "should set an api key from the environment" do
18
19
  client.api_key.should == "abcde"
19
20
  end
20
-
21
- after do
22
- ENV["KEEN_PROJECT_ID"] = nil
23
- ENV["KEEN_API_KEY"] = nil
24
- end
25
21
  end
26
22
  end
27
23
 
data/spec/spec_helper.rb CHANGED
@@ -10,7 +10,27 @@ require 'em-http'
10
10
 
11
11
  require File.expand_path("../../lib/keen", __FILE__)
12
12
 
13
- RSpec.configure do |config|
14
- config.before(:all) do
13
+ module Keen::SpecHelpers
14
+ def stub_api(url, status, json_body)
15
+ stub_request(:post, url).to_return(
16
+ :status => status,
17
+ :body => MultiJson.encode(json_body))
18
+ end
19
+
20
+ def expect_post(url, event_properties, api_key)
21
+ WebMock.should have_requested(:post, url).with(
22
+ :body => MultiJson.encode(event_properties),
23
+ :headers => { "Content-Type" => "application/json",
24
+ "User-Agent" => "keen-gem v#{Keen::VERSION}",
25
+ "Authorization" => api_key })
26
+ end
27
+
28
+ def api_url(collection)
29
+ "https://api.keen.io/3.0/projects/#{project_id}/events/#{collection}"
15
30
  end
16
31
  end
32
+
33
+ RSpec.configure do |config|
34
+ config.include(Keen::SpecHelpers)
35
+ end
36
+
@@ -0,0 +1,7 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ require 'em-synchrony'
4
+ require 'em-synchrony/em-http'
5
+
6
+ require 'webmock/rspec'
7
+
@@ -0,0 +1,53 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe Keen::HTTP::Async do
4
+ let(:project_id) { "12345" }
5
+ let(:api_key) { "abcde" }
6
+ let(:collection) { "users" }
7
+ let(:event_properties) { { "name" => "Bob" } }
8
+ let(:api_success) { { "created" => true } }
9
+
10
+ describe "synchrony" do
11
+ before do
12
+ @client = Keen::Client.new(
13
+ :project_id => project_id,
14
+ :api_key => api_key)
15
+ end
16
+
17
+ describe "success" do
18
+ it "should post the event data" do
19
+ stub_api(api_url(collection), 201, api_success)
20
+ EM.synchrony {
21
+ @client.publish_async(collection, event_properties)
22
+ expect_post(api_url(collection), event_properties, api_key)
23
+ EM.stop
24
+ }
25
+ end
26
+
27
+ it "should recieve the right response 'synchronously'" do
28
+ stub_api(api_url(collection), 201, api_success)
29
+ EM.synchrony {
30
+ @client.publish_async(collection, event_properties).should == api_success
31
+ EM.stop
32
+ }
33
+ end
34
+ end
35
+
36
+ describe "failure" do
37
+ it "should raise an exception" do
38
+ stub_request(:post, api_url(collection)).to_timeout
39
+ e = nil
40
+ EM.synchrony {
41
+ begin
42
+ @client.publish_async(collection, event_properties).should == api_success
43
+ rescue Exception => exception
44
+ e = exception
45
+ end
46
+ e.class.should == Keen::HttpError
47
+ e.message.should == "Couldn't connect to Keen IO: WebMock timeout error"
48
+ EM.stop
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
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.4.2
4
+ version: 0.4.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-16 00:00:00.000000000 Z
13
+ date: 2013-01-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: multi_json
@@ -54,6 +54,8 @@ files:
54
54
  - spec/keen/keen_spec.rb
55
55
  - spec/keen/spec_helper.rb
56
56
  - spec/spec_helper.rb
57
+ - spec/synchrony/spec_helper.rb
58
+ - spec/synchrony/synchrony_spec.rb
57
59
  homepage: https://github.com/keenlabs/keen-gem
58
60
  licenses: []
59
61
  post_install_message:
@@ -85,3 +87,5 @@ test_files:
85
87
  - spec/keen/keen_spec.rb
86
88
  - spec/keen/spec_helper.rb
87
89
  - spec/spec_helper.rb
90
+ - spec/synchrony/spec_helper.rb
91
+ - spec/synchrony/synchrony_spec.rb