keen 0.4.2 → 0.4.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/.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