analytics-ruby 0.0.2 → 0.0.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 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