analytics-ruby 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
data/History.md ADDED
@@ -0,0 +1,4 @@
1
+ 0.0.3 / 2013-1-17
2
+ ==========
3
+ * Rakefile and renaming courtesy of [@kiennt](https://github.com/kiennt)
4
+ * Updated tests with mocks
data/README.md CHANGED
@@ -3,6 +3,8 @@ analytics-ruby
3
3
 
4
4
  analytics-ruby is a ruby client for [Segment.io](https://segment.io).
5
5
 
6
+ [![Build Status](https://travis-ci.org/segmentio/analytics-ruby.png?branch=master)](https://travis-ci.org/segmentio/analytics-ruby)
7
+
6
8
  ### Ruby Analytics Made Simple
7
9
 
8
10
  [Segment.io](https://segment.io) is the cleanest, simplest API for recording analytics data.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec) do |spec|
4
+ spec.pattern = 'spec/**/*_spec.rb'
5
+ end
6
+
7
+ task :default => :spec
data/analytics.gemspec CHANGED
@@ -9,10 +9,16 @@ Gem::Specification.new do |spec|
9
9
  spec.files = Dir.glob('**/*')
10
10
  spec.require_paths = ['lib']
11
11
  spec.summary = 'Segment.io analytics library'
12
- spec.authors = ['friends@segment.io']
12
+ spec.description = 'The Segment.io ruby analytics library'
13
+ spec.authors = ['Segment.io']
14
+ spec.email = 'friends@segment.io'
15
+ spec.homepage = 'https://github.com/segmentio/analytics-ruby'
13
16
 
14
17
  spec.add_dependency 'faraday', ['~> 0.8', '< 0.10']
15
18
  spec.add_dependency 'faraday_middleware', ['~> 0.9.0']
16
19
  spec.add_dependency 'multi_json', ['~> 1.0']
17
20
  spec.add_dependency 'typhoeus', ['~> 0.5.0']
21
+
22
+ spec.add_development_dependency('rake')
23
+ spec.add_development_dependency('rspec')
18
24
  end
@@ -9,11 +9,12 @@ module Analytics
9
9
 
10
10
  class Client
11
11
 
12
- # Public: Creates a new client
12
+ # public: Creates a new client
13
13
  #
14
14
  # options - Hash
15
15
  # :secret - String of your project's secret
16
16
  # :max_queue_size - Fixnum of the max calls to remain queued (optional)
17
+ # :on_error - Proc which handles error calls from the API
17
18
  def initialize (options = {})
18
19
 
19
20
  @queue = Queue.new
@@ -26,7 +27,7 @@ module Analytics
26
27
  Thread.new { @consumer.run }
27
28
  end
28
29
 
29
- # Public: Tracks an event
30
+ # public: Tracks an event
30
31
  #
31
32
  # options - Hash
32
33
  # :event - String of event name.
@@ -64,7 +65,7 @@ module Analytics
64
65
  action: 'track' })
65
66
  end
66
67
 
67
- # Public: Identifies a user
68
+ # public: Identifies a user
68
69
  #
69
70
  # options - Hash
70
71
  # :sessionId - String of the user session. (optional with userId)
@@ -97,10 +98,16 @@ module Analytics
97
98
  action: 'identify' })
98
99
  end
99
100
 
101
+ # public: Returns the number of queued messages
102
+ #
103
+ # returns Fixnum of messages in the queue
104
+ def queued_messages
105
+ @queue.length
106
+ end
100
107
 
101
108
  private
102
109
 
103
- # Private: Enqueues the action.
110
+ # private: Enqueues the action.
104
111
  #
105
112
  # returns Boolean of whether the item was added to the queue.
106
113
  def enqueue(action)
@@ -110,7 +117,7 @@ module Analytics
110
117
  !queue_full
111
118
  end
112
119
 
113
- # Private: Ensures that a user id was passed in.
120
+ # private: Ensures that a user id was passed in.
114
121
  #
115
122
  # session_id - String of the session
116
123
  # user_id - String of the user id
@@ -124,19 +131,19 @@ module Analytics
124
131
  fail ArgumentError, message unless valid
125
132
  end
126
133
 
127
- # Private: Adds contextual information to the call
134
+ # private: Adds contextual information to the call
128
135
  #
129
136
  # context - Hash of call context
130
137
  def add_context(context)
131
138
  context[:library] = 'analytics-ruby'
132
139
  end
133
140
 
134
- # Private: Checks that the secret is properly initialized
141
+ # private: Checks that the secret is properly initialized
135
142
  def check_secret
136
143
  fail 'Secret must be initialized' if @secret.nil?
137
144
  end
138
145
 
139
- # Private: Checks the timstamp option to make sure it is a Time.
146
+ # private: Checks the timstamp option to make sure it is a Time.
140
147
  def check_timestamp(timestamp)
141
148
  fail ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
142
149
  end
@@ -11,11 +11,19 @@ module Analytics
11
11
  # The consumer continuously takes messages off the queue
12
12
  # and makes requests to the segment.io api
13
13
  #
14
+ # queue - Queue synchronized between client and consumer
15
+ # secret - String of the project's secret
16
+ # options - Hash of consumer options
17
+ # batch_size - Fixnum of how many items to send in a batch
18
+ # on_error - Proc of what to do on an error
19
+ #
14
20
  def initialize(queue, secret, options = {})
15
- @current_batch = []
16
21
  @queue = queue
17
- @batch_size = options[:batch_size] || Analytics::Defaults::Queue::BATCH_SIZE
18
22
  @secret = secret
23
+ @batch_size = options[:batch_size] || Analytics::Defaults::Queue::BATCH_SIZE
24
+ @on_error = options[:on_error] || Proc.new { |status, error| }
25
+
26
+ @current_batch = []
19
27
  end
20
28
 
21
29
  # public: Continuously runs the loop to check for new events
@@ -26,9 +34,7 @@ module Analytics
26
34
  end
27
35
  end
28
36
 
29
- private
30
-
31
- # private: Flush some events from our queue
37
+ # public: Flush some events from our queue
32
38
  #
33
39
  def flush
34
40
 
@@ -41,18 +47,9 @@ module Analytics
41
47
 
42
48
  req = Analytics::Request.new
43
49
  res = req.post(@secret, @current_batch)
44
-
45
- onError(res) unless res.status == 200
46
-
50
+ @on_error.call(res.status, res.error) unless res.status == 200
47
51
  @current_batch = []
48
52
  end
49
53
 
50
- # private: Error handler whenever the api does not
51
- # return a valid response
52
- def onError(res)
53
- puts res.status
54
- puts res.body
55
- end
56
-
57
54
  end
58
55
  end
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'analytics/defaults'
3
+ require 'analytics/response'
3
4
  require 'multi_json'
4
5
  require 'faraday'
5
6
  require 'faraday_middleware'
@@ -26,13 +27,27 @@ module Analytics
26
27
  end
27
28
  end
28
29
 
29
- # public: Posts
30
+ # public: Posts the secret and batch of messages to the API.
30
31
  #
32
+ # returns - Response of the status and error if it exists
31
33
  def post(secret, batch)
32
- @conn.post do |req|
33
- req.url(@path)
34
- req.body = MultiJson.dump(secret: secret, batch: batch)
34
+
35
+ status, error = nil, nil
36
+
37
+ begin
38
+ res = @conn.post do |req|
39
+ req.url(@path)
40
+ req.body = MultiJson.dump(secret: secret, batch: batch)
41
+ end
42
+ status = res.status
43
+ error = res.body["error"]
44
+
45
+ rescue Exception => err
46
+ status = -1
47
+ error = "Connection error: #{err}"
35
48
  end
49
+
50
+ Analytics::Response.new(status, error)
36
51
  end
37
52
  end
38
53
  end
@@ -0,0 +1,17 @@
1
+
2
+ module Analytics
3
+
4
+ class Response
5
+
6
+ attr_reader :status
7
+ attr_reader :error
8
+
9
+ # public: Simple class to wrap responses from the API
10
+ #
11
+ #
12
+ def initialize(status = 200, error = nil)
13
+ @status = status
14
+ @error = error
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Analytics
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
@@ -0,0 +1,58 @@
1
+ require 'analytics'
2
+ require 'spec_helper'
3
+
4
+
5
+ describe Analytics::Client do
6
+
7
+ describe '#init' do
8
+
9
+ it 'should error if no secret is supplied' do
10
+ expect { Analytics::Client.new }.to raise_error(RuntimeError)
11
+ end
12
+
13
+ it 'should not error if a secret is supplied' do
14
+ Analytics::Client.new secret: AnalyticsHelpers::SECRET
15
+ end
16
+
17
+ end
18
+
19
+ describe '#track' do
20
+
21
+ before(:all) do
22
+ @client = Analytics::Client.new secret: AnalyticsHelpers::SECRET
23
+ end
24
+
25
+ it 'should error without an event' do
26
+ expect { @client.track(user_id: 'user') }.to raise_error(ArgumentError)
27
+ end
28
+
29
+ it 'should error without a user or session' do
30
+ expect { @client.track(event: 'Event') }.to raise_error(ArgumentError)
31
+ end
32
+
33
+ it 'should not error with the required options' do
34
+ @client.track AnalyticsHelpers::Queued::TRACK
35
+ end
36
+
37
+ end
38
+
39
+
40
+ describe '#identify' do
41
+
42
+ before(:all) do
43
+ @client = Analytics::Client.new secret: AnalyticsHelpers::SECRET
44
+ end
45
+
46
+ it 'should error without any user id' do
47
+ expect { @client.identify({}) }.to raise_error(ArgumentError)
48
+ end
49
+
50
+ it 'should not error with the required options' do
51
+ @client.identify AnalyticsHelpers::Queued::IDENTIFY
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+
@@ -0,0 +1,61 @@
1
+ require 'analytics'
2
+ require 'thread'
3
+ require 'spec_helper'
4
+
5
+ describe Analytics::Consumer do
6
+
7
+ describe '#flush' do
8
+
9
+ it 'should not error if the endpoint is unreachable' do
10
+
11
+ Faraday::Connection.any_instance.stub(:post).and_raise(Exception)
12
+
13
+ queue = Queue.new
14
+ queue << {}
15
+ consumer = Analytics::Consumer.new(queue, 'secret')
16
+ consumer.flush
17
+
18
+ queue.should be_empty
19
+
20
+ Faraday::Connection.any_instance.unstub(:post)
21
+ end
22
+
23
+ it 'should execute the error handler if the request is invalid' do
24
+
25
+ Analytics::Request.any_instance
26
+ .stub(:post)
27
+ .and_return(Analytics::Response.new(400, "Some error"))
28
+
29
+ on_error = Proc.new do |status, error|
30
+ puts "#{status}, #{error}"
31
+ end
32
+
33
+ on_error.should_receive(:call).once
34
+
35
+ queue = Queue.new
36
+ queue << {}
37
+ consumer = Analytics::Consumer.new(queue, 'secret', { on_error: on_error })
38
+ consumer.flush
39
+
40
+ Analytics::Request::any_instance.unstub(:post)
41
+
42
+ queue.should be_empty
43
+ end
44
+
45
+ it 'should not call on_error if the request is good' do
46
+
47
+ on_error = Proc.new do |status, error|
48
+ puts "#{status}, #{error}"
49
+ end
50
+
51
+ on_error.should_receive(:call).at_most(0).times
52
+
53
+ queue = Queue.new
54
+ queue << AnalyticsHelpers::Requested::TRACK
55
+ consumer = Analytics::Consumer.new(queue, 'testsecret', { on_error: on_error })
56
+ consumer.flush
57
+
58
+ queue.should be_empty
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,39 @@
1
+ require 'analytics'
2
+ require 'spec_helper'
3
+
4
+ describe Analytics do
5
+
6
+ describe '#init' do
7
+
8
+ it 'should successfully init' do
9
+ Analytics.init secret: AnalyticsHelpers::SECRET
10
+ end
11
+ end
12
+
13
+
14
+ describe '#track' do
15
+
16
+ it 'should error without an event' do
17
+ expect { Analytics.track user_id: 'user' }.to raise_error(ArgumentError)
18
+ end
19
+
20
+ it 'should error without a user or session' do
21
+ expect { Analytics.track event: 'Event' }.to raise_error(ArgumentError)
22
+ end
23
+
24
+ it 'should not error with the required options' do
25
+ Analytics.track AnalyticsHelpers::Queued::TRACK
26
+ end
27
+ end
28
+
29
+
30
+ describe '#identify' do
31
+ it 'should error without a user or session' do
32
+ expect { Analytics.identify traits: {} }.to raise_error(ArgumentError)
33
+ end
34
+
35
+ it 'should not error with the required options' do
36
+ Analytics.identify AnalyticsHelpers::Queued::IDENTIFY
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+
2
+ module AnalyticsHelpers
3
+
4
+ SECRET = 'testsecret'
5
+
6
+ TRACK = { event: 'Baked a cake',
7
+ properties: {
8
+ type: 'Chocolate',
9
+ is_a_lie: true,
10
+ layers: 20,
11
+ created: Time.new
12
+ }
13
+ }
14
+
15
+ IDENTIFY = { traits: {
16
+ likes_animals: true,
17
+ instrument: 'Guitar',
18
+ age: 25
19
+ },
20
+ action: 'identify'
21
+ }
22
+
23
+ USER_ID = 'Bret'
24
+ SESSION_ID = '4815162342'
25
+
26
+ # Hashes sent to the client
27
+ module Queued
28
+ TRACK = TRACK.merge({ user_id: USER_ID })
29
+
30
+ IDENTIFY = IDENTIFY.merge({ user_id: USER_ID,
31
+ session_id: SESSION_ID })
32
+ end
33
+
34
+ # Hashes which are sent from the consumer
35
+ module Requested
36
+ TRACK = TRACK.merge({ userId: USER_ID,
37
+ action: 'track' })
38
+
39
+ IDENTIFY = IDENTIFY.merge({ userId: USER_ID,
40
+ sessionId: SESSION_ID,
41
+ action: 'identify' })
42
+ end
43
+ end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: analytics-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
- - friends@segment.io
8
+ - Segment.io
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-16 00:00:00.000000000 Z
12
+ date: 2013-01-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
16
- requirement: &14967320 !ruby/object:Gem::Requirement
16
+ requirement: &22786760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -24,10 +24,10 @@ dependencies:
24
24
  version: '0.10'
25
25
  type: :runtime
26
26
  prerelease: false
27
- version_requirements: *14967320
27
+ version_requirements: *22786760
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: faraday_middleware
30
- requirement: &14962920 !ruby/object:Gem::Requirement
30
+ requirement: &22785200 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
33
  - - ~>
@@ -35,10 +35,10 @@ dependencies:
35
35
  version: 0.9.0
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *14962920
38
+ version_requirements: *22785200
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: multi_json
41
- requirement: &14961260 !ruby/object:Gem::Requirement
41
+ requirement: &22784660 !ruby/object:Gem::Requirement
42
42
  none: false
43
43
  requirements:
44
44
  - - ~>
@@ -46,10 +46,10 @@ dependencies:
46
46
  version: '1.0'
47
47
  type: :runtime
48
48
  prerelease: false
49
- version_requirements: *14961260
49
+ version_requirements: *22784660
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: typhoeus
52
- requirement: &14956120 !ruby/object:Gem::Requirement
52
+ requirement: &22784020 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ~>
@@ -57,26 +57,52 @@ dependencies:
57
57
  version: 0.5.0
58
58
  type: :runtime
59
59
  prerelease: false
60
- version_requirements: *14956120
61
- description:
62
- email:
60
+ version_requirements: *22784020
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: &22783500 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: *22783500
72
+ - !ruby/object:Gem::Dependency
73
+ name: rspec
74
+ requirement: &22781240 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: *22781240
83
+ description: The Segment.io ruby analytics library
84
+ email: friends@segment.io
63
85
  executables: []
64
86
  extensions: []
65
87
  extra_rdoc_files: []
66
88
  files:
67
89
  - analytics.gemspec
90
+ - Gemfile
68
91
  - README.md
69
92
  - lib/analytics.rb
93
+ - lib/analytics/response.rb
70
94
  - lib/analytics/defaults.rb
71
95
  - lib/analytics/consumer.rb
72
96
  - lib/analytics/request.rb
73
97
  - lib/analytics/version.rb
74
98
  - lib/analytics/client.rb
75
- - analytics-ruby-0.0.1.gem
76
- - spec/test.rb
77
- - spec/client.rb
78
- - spec/module.rb
79
- homepage:
99
+ - History.md
100
+ - Rakefile
101
+ - spec/client_spec.rb
102
+ - spec/module_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/consumer_spec.rb
105
+ homepage: https://github.com/segmentio/analytics-ruby
80
106
  licenses: []
81
107
  post_install_message:
82
108
  rdoc_options: []
Binary file
data/spec/client.rb DELETED
@@ -1,21 +0,0 @@
1
- require_relative '../lib/analytics'
2
-
3
-
4
- describe Analytics::Client, '#track' do
5
-
6
- before(:all) { @client = Analytics::Client.new(secret: 'testsecret') }
7
-
8
- it 'should error without an event' do
9
- expect { @client.track(user_id: 'user') }.to raise_error(ArgumentError)
10
- end
11
-
12
- it 'should error without a user or session' do
13
- expect { @client.track(event: 'Event') }.to raise_error(ArgumentError)
14
- end
15
-
16
- it 'should not error with the required options' do
17
- @client.track(user_id: 'user',
18
- event: 'Event')
19
- end
20
-
21
- end
data/spec/module.rb DELETED
@@ -1,27 +0,0 @@
1
- require_relative '../lib/analytics'
2
-
3
-
4
- describe Analytics, '#init' do
5
-
6
- it 'should successfully init' do
7
- Analytics.init secret: 'testsecret'
8
- end
9
- end
10
-
11
-
12
- describe Analytics, '#track' do
13
-
14
- it 'should error without an event' do
15
- expect { Analytics.track user_id: 'user' }.to raise_error(ArgumentError)
16
- end
17
-
18
- it 'should error without a user or session' do
19
- expect { Analytics.track event: 'Event' }.to raise_error(ArgumentError)
20
- end
21
-
22
- it 'should not error with the required options' do
23
- Analytics.track user_id: 'user',
24
- event: 'Event'
25
- end
26
-
27
- end
data/spec/test.rb DELETED
@@ -1,25 +0,0 @@
1
-
2
-
3
- module Analytics
4
- module Defaults
5
- module Request
6
- BASE_URL = "http://localhost:7001"
7
- end
8
- end
9
- end
10
-
11
- require_relative '../lib/analytics'
12
-
13
- puts "Hello"
14
-
15
-
16
- client = Analytics::Client.new(secret: "testsecret")
17
-
18
- puts "Client made"
19
-
20
- 100.times do
21
- client.identify(user_id: "user")
22
- client.track(user_id: "user",
23
- event: "No Typhoeus")
24
- end
25
- sleep 10