datasift 0.2.0

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.
@@ -0,0 +1,104 @@
1
+ #
2
+ # user.rb - This file contains the User class.
3
+ #
4
+ # Copyright (C) 2011 MediaSift Ltd
5
+ #
6
+ # == Overview
7
+ #
8
+ # The User class represents a user of the API. Applications should start their
9
+ # API interactions by creating an instance of this class. Once initialised it
10
+ # provides factory methods for all of the functionality in the API.
11
+
12
+ require 'rest_client'
13
+ require 'crack'
14
+
15
+ module DataSift
16
+ # User class.
17
+ #
18
+ # == Introduction
19
+ #
20
+ # The User class represents a user of the API. Applications should start their
21
+ # API interactions by creating an instance of this class. Once initialised it
22
+ # provides factory methods for all of the functionality in the API.
23
+ #
24
+ class User
25
+ USER_AGENT = 'DataSiftRuby/0.1';
26
+ API_BASE_URL = 'api.datasift.net/';
27
+ STREAM_BASE_URL = 'stream.datasift.net/';
28
+
29
+ attr_reader :username, :api_key, :rate_limit, :rate_limit_remaining, :api_client
30
+
31
+ # Constructor. A username and API key are required when constructing an
32
+ # instance of this class.
33
+ # === Parameters
34
+ #
35
+ # * +username+ - The user's username
36
+ # * +api_key+ - The user's API key
37
+ def initialize(username, api_key)
38
+ username.strip!
39
+ api_key.strip!
40
+
41
+ raise EInvalidData, 'Please supply valid credentials when creating a User object.' unless username.size > 0 and api_key.size > 0
42
+
43
+ @username = username
44
+ @api_key = api_key
45
+ @rate_limit = -1;
46
+ @rate_limit_remaining = -1
47
+ end
48
+
49
+ # Creates and returns a definition object.
50
+ # === Parameters
51
+ #
52
+ # * +csdl+ - Optional CSDL string with which to prime the object.
53
+ def createDefinition(csdl = '')
54
+ DataSift::Definition.new(self, csdl, false)
55
+ end
56
+
57
+ # Returns the user agent this library should use for all API calls.
58
+ def getUserAgent()
59
+ USER_AGENT
60
+ end
61
+
62
+ # Sets the ApiClient object to use to access the API
63
+ def setApiClient(client)
64
+ @api_client = client
65
+ end
66
+
67
+ # Make a call to a DataSift API endpoint.
68
+ # === Parameters
69
+ #
70
+ # * +endpoint+ - The endpoint of the API call.
71
+ # * +params+ - The parameters to be passed along with the request.
72
+ def callAPI(endpoint, params = {})
73
+ if !@api_client
74
+ @api_client = ApiClient.new()
75
+ end
76
+
77
+ res = @api_client.call(@username, @api_key, endpoint, params)
78
+
79
+ # Set up the return value
80
+ retval = res['data']
81
+
82
+ # Update the rate limits from the headers
83
+ @rate_limit = res['rate_limit']
84
+ @rate_limit_remaining = res['rate_limit_remaining']
85
+
86
+ case res['response_code']
87
+ when 200
88
+ # Do nothing
89
+ when 401
90
+ # Authentication failure
91
+ raise AccessDeniedError, retval.has_key?('error') ? retval['error'] : 'Authentication failed'
92
+ when 403
93
+ # Check the rate limit
94
+ raise RateLimitExceededError, retval['comment'] if @rate_limit_remaining == 0
95
+ # Rate limit is ok, raise a generic exception
96
+ raise APIError.new(403), retval.has_key?('error') ? retval['error'] : 'Unknown error'
97
+ else
98
+ raise APIError.new(res['http_code']), retval.has_key?('error') ? retval['error'] : 'Unknown error'
99
+ end
100
+
101
+ retval
102
+ end
103
+ end
104
+ end
data/lib/datasift.rb ADDED
@@ -0,0 +1,19 @@
1
+ #
2
+ # datasift.rb - DataSift module base file
3
+ #
4
+ # Copyright (C) 2011 MediaSift Ltd
5
+ #
6
+ # == Overview
7
+ #
8
+ # This is the base file for the DataSift API library. Require this file to get
9
+ # access to the full library functionality.
10
+ #
11
+ require 'rubygems'
12
+
13
+ dir = File.dirname(__FILE__)
14
+ require dir + '/DataSift/exceptions'
15
+ require dir + '/DataSift/apiclient'
16
+ require dir + '/DataSift/user'
17
+ require dir + '/DataSift/definition'
18
+ require dir + '/DataSift/stream_consumer'
19
+ require dir + '/DataSift/stream_consumer_http'
data/test/helper.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'yaml'
5
+ require File.dirname(__FILE__) + '/../lib/DataSift/mockapiclient'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+ require 'datasift'
10
+
11
+ class Test::Unit::TestCase
12
+ def init()
13
+ @config = YAML::load(File.open(File.join(File.dirname(__FILE__), '..', 'config.yml')))
14
+ @testdata = YAML::load(File.open(File.join(File.dirname(__FILE__), 'testdata.yml')))
15
+ end
16
+
17
+ def initUser(mock = true)
18
+ @user = DataSift::User.new(@config['username'], @config['api_key'])
19
+ if mock
20
+ @user.setApiClient(DataSift::MockApiClient.new())
21
+ @user.api_client.clearResponse()
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,282 @@
1
+ require 'helper'
2
+
3
+ class TestDefinition < Test::Unit::TestCase
4
+ context "Given an empty Definition object" do
5
+ setup do
6
+ init()
7
+ initUser()
8
+ @definition = @user.createDefinition()
9
+ end
10
+
11
+ should "have an empty CSDL" do
12
+ assert_not_nil @definition
13
+ assert_equal '', @definition.csdl
14
+ end
15
+
16
+ should "correctly set and get the CSDL" do
17
+ @definition.csdl = @testdata['definition']
18
+ assert_equal @testdata['definition'], @definition.csdl
19
+ end
20
+ end
21
+
22
+ context "Given a Definition object with CSDL" do
23
+ setup do
24
+ init()
25
+ initUser()
26
+ @definition = @user.createDefinition(@testdata['definition'])
27
+ end
28
+
29
+ should "have the correct CSDL" do
30
+ assert_not_nil @definition
31
+ assert_equal @testdata['definition'], @definition.csdl
32
+ end
33
+ end
34
+
35
+ context "Given a Definition object with CSDL plus padding" do
36
+ setup do
37
+ init()
38
+ initUser()
39
+ @definition = @user.createDefinition(" " + @testdata['definition'] + " ")
40
+ end
41
+
42
+ should "have the correct CSDL" do
43
+ assert_not_nil @definition
44
+ assert_equal @testdata['definition'], @definition.csdl
45
+ end
46
+ end
47
+
48
+ context "When trying to create a Definition object with an invalid user" do
49
+ should "raise an InvalidDataError" do
50
+ assert_raise(DataSift::InvalidDataError) { DataSift::Definition.new('username') }
51
+ end
52
+ end
53
+
54
+ context "When trying to create a Definition object with an invalid CSDL" do
55
+ setup do
56
+ init()
57
+ initUser()
58
+ end
59
+
60
+ should "raise an InvalidDataError" do
61
+ assert_raise(DataSift::InvalidDataError) { DataSift::Definition.new(@user, 1234) }
62
+ end
63
+ end
64
+
65
+ context "Given a Definition object with a valid CSDL" do
66
+ setup do
67
+ init()
68
+ initUser()
69
+ @definition = @user.createDefinition(@testdata['definition'])
70
+ end
71
+
72
+ should "compile the definition successfully" do
73
+ begin
74
+ @user.api_client.setResponse(200, {
75
+ 'hash' => @testdata['definition_hash'],
76
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
77
+ 'cost' => 10,
78
+ }, 200, 150)
79
+ @definition.compile()
80
+ rescue InvalidDataError
81
+ assert false, "InvalidDataError"
82
+ rescue CompileFailedError
83
+ assert false, "CompileFailedError"
84
+ rescue APIError
85
+ assert false, "APIError"
86
+ end
87
+ end
88
+
89
+ should "have the correct hash" do
90
+ @user.api_client.setResponse(200, {
91
+ 'hash' => @testdata['definition_hash'],
92
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
93
+ 'cost' => 10,
94
+ }, 200, 150)
95
+ assert_equal @testdata['definition_hash'], @definition.hash
96
+ end
97
+
98
+ should "have a positive cost" do
99
+ @user.api_client.setResponse(200, {
100
+ 'hash' => @testdata['definition_hash'],
101
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
102
+ 'cost' => 10,
103
+ }, 200, 150)
104
+ @definition.compile()
105
+ assert @definition.total_cost > 0
106
+ end
107
+
108
+ should "have a valid created_at date" do
109
+ @user.api_client.setResponse(200, {
110
+ 'hash' => @testdata['definition_hash'],
111
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
112
+ 'cost' => 10,
113
+ }, 200, 150)
114
+ @definition.compile()
115
+ assert @definition.created_at
116
+ end
117
+ end
118
+
119
+ context "Given a Definition object with an invalid CSDL" do
120
+ setup do
121
+ init()
122
+ initUser()
123
+ @definition = @user.createDefinition(@testdata['invalid_definition'])
124
+ end
125
+
126
+ should "fail to compile the definition" do
127
+ @user.api_client.setResponse(400, {
128
+ 'error' => 'The target interactin.content does not exist',
129
+ }, 200, 150)
130
+ assert_raise(DataSift::CompileFailedError) { @definition.compile() }
131
+ end
132
+
133
+ should "have a hash of false" do
134
+ @user.api_client.setResponse(400, {
135
+ 'error' => 'The target interactin.content does not exist',
136
+ }, 200, 150)
137
+ assert_equal false, @definition.hash
138
+ end
139
+ end
140
+
141
+ context "The cost returned from a valid Definition object" do
142
+ setup do
143
+ init()
144
+ initUser()
145
+ @definition = @user.createDefinition(@testdata['definition'])
146
+ # Compile the definition first
147
+ @user.api_client.setResponse(200, {
148
+ 'hash' => @testdata['definition_hash'],
149
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
150
+ 'cost' => 10,
151
+ }, 200, 150)
152
+ @definition.compile()
153
+ # Now get the cost
154
+ @user.api_client.setResponse(200, {
155
+ 'costs' => {
156
+ 'contains' => {
157
+ 'count' => 1,
158
+ 'cost' => 4,
159
+ 'targets' => {
160
+ 'interaction.content' => {
161
+ 'count' => 1,
162
+ 'cost' => 4,
163
+ },
164
+ },
165
+ },
166
+ },
167
+ 'total' => 4
168
+ }, 200, 150)
169
+ @cost = @definition.getCostBreakdown()
170
+ end
171
+
172
+ should "contain valid cost data" do
173
+ assert @cost.has_key?('costs')
174
+ assert @cost.has_key?('total')
175
+ end
176
+
177
+ should "have a positive total cost" do
178
+ assert @cost['total'] > 0
179
+ end
180
+ end
181
+
182
+ context "Buffered data returned by a valid Definition object" do
183
+ setup do
184
+ init()
185
+ initUser()
186
+ @definition = @user.createDefinition(@testdata['definition'])
187
+ # Compile the definition first
188
+ @user.api_client.setResponse(200, {
189
+ 'hash' => @testdata['definition_hash'],
190
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
191
+ 'cost' => 10,
192
+ }, 200, 150)
193
+ @definition.compile()
194
+ # Now get some buffered interactions
195
+ @user.api_client.setResponse(200, {
196
+ 'stream' => {
197
+ 0 => {
198
+ 'interaction' => {
199
+ 'source' => 'Snaptu',
200
+ 'author' => {
201
+ 'username' => 'nittolexia',
202
+ 'name' => 'nittosoetreznoe',
203
+ 'id' => 172192091,
204
+ 'avatar' => 'http://a0.twimg.com/profile_images/1429378181/gendowor_normal.jpg',
205
+ 'link' => 'http://twitter.com/nittolexia',
206
+ },
207
+ 'type' => 'twitter',
208
+ 'link' => 'http://twitter.com/nittolexia/statuses/89571192838684672',
209
+ 'created_at' => 'Sat, 09 Jul 2011 05:46:51 +0000',
210
+ 'content' => 'RT @ayyuchadel: Haha RT @nittolexia: Mending gak ush maen twitter dehh..RT @sansan_arie:',
211
+ 'id' => '1e0a9eedc207acc0e074ea8aecb2c5ea',
212
+ },
213
+ 'twitter' => {
214
+ 'user' => {
215
+ 'name' => 'nittosoetreznoe',
216
+ 'description' => 'fuck all',
217
+ 'location' => 'denpasar, bali',
218
+ 'statuses_count' => 6830,
219
+ 'followers_count' => 88,
220
+ 'friends_count' => 111,
221
+ 'screen_name' => 'nittolexia',
222
+ 'lang' => 'en',
223
+ 'time_zone' => 'Alaska',
224
+ 'id' => 172192091,
225
+ 'geo_enabled' => true,
226
+ },
227
+ 'mentions' => {
228
+ 0 => 'ayyuchadel',
229
+ 1 => 'nittolexia',
230
+ 2 => 'sansan_arie',
231
+ },
232
+ 'id' => '89571192838684672',
233
+ 'text' => 'RT @ayyuchadel: Haha RT @nittolexia: Mending gak ush maen twitter dehh..RT @sansan_arie:',
234
+ 'source' => '<a href="http://www.snaptu.com" rel="nofollow">Snaptu</a>',
235
+ 'created_at' => 'Sat, 09 Jul 2011 05:46:51 +0000',
236
+ },
237
+ 'klout' => {
238
+ 'score' => 45,
239
+ 'network' => 55,
240
+ 'amplification' => 17,
241
+ 'true_reach' => 31,
242
+ 'slope' => 0,
243
+ 'class' => 'Networker',
244
+ },
245
+ 'peerindex' => {
246
+ 'score' => 30,
247
+ },
248
+ 'language' => {
249
+ 'tag' => 'da',
250
+ },
251
+ },
252
+ },
253
+ }, 200, 150)
254
+ @interactions = @definition.getBuffered()
255
+ end
256
+
257
+ should "be valid" do
258
+ assert @interactions
259
+ end
260
+ end
261
+
262
+ context "A StreamConsumer object returned by a valid Definition object" do
263
+ setup do
264
+ init()
265
+ initUser()
266
+ @definition = @user.createDefinition(@testdata['definition'])
267
+ # Compile the definition first
268
+ @user.api_client.setResponse(200, {
269
+ 'hash' => @testdata['definition_hash'],
270
+ 'created_at' => Time.now.strftime('%Y-%m-%d %H:%M:%S'),
271
+ 'cost' => 10,
272
+ }, 200, 150)
273
+ @definition.compile()
274
+ # Now get a consumer
275
+ @consumer = @definition.getConsumer()
276
+ end
277
+
278
+ should "be valid" do
279
+ assert @consumer.is_a? DataSift::StreamConsumer
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,100 @@
1
+ require 'helper'
2
+
3
+ class TestDefinitionLive < Test::Unit::TestCase
4
+ context "Given a Definition object with a valid CSDL" do
5
+ setup do
6
+ init()
7
+ initUser(false)
8
+ @user = DataSift::User.new(@config['username'], @config['api_key'])
9
+ @definition = @user.createDefinition(@testdata['definition'])
10
+ end
11
+
12
+ should "compile the definition successfully" do
13
+ begin
14
+ @definition.compile()
15
+ rescue InvalidDataError
16
+ assert false, "InvalidDataError"
17
+ rescue CompileFailedError
18
+ assert false, "CompileFailedError"
19
+ rescue APIError
20
+ assert false, "APIError"
21
+ end
22
+ end
23
+
24
+ should "have the correct hash" do
25
+ @definition.compile()
26
+ assert_equal @testdata['definition_hash'], @definition.hash
27
+ end
28
+
29
+ should "have a positive cost" do
30
+ @definition.compile()
31
+ assert @definition.total_cost > 0
32
+ end
33
+
34
+ should "have a valid created_at date" do
35
+ @definition.compile()
36
+ assert @definition.created_at
37
+ end
38
+ end
39
+
40
+ context "Given a Definition object with an invalid CSDL" do
41
+ setup do
42
+ init()
43
+ initUser(false)
44
+ @definition = @user.createDefinition(@testdata['invalid_definition'])
45
+ end
46
+
47
+ should "fail to compile the definition" do
48
+ assert_raise(DataSift::CompileFailedError) { @definition.compile() }
49
+ end
50
+
51
+ should "have a hash of false" do
52
+ assert_raise(DataSift::CompileFailedError) { @definition.compile() }
53
+ assert_equal false, @definition.hash
54
+ end
55
+ end
56
+
57
+ context "The cost returned from a valid Definition object" do
58
+ setup do
59
+ init()
60
+ initUser(false)
61
+ @definition = @user.createDefinition(@testdata['definition'])
62
+ @cost = @definition.getCostBreakdown()
63
+ end
64
+
65
+ should "contain valid cost data" do
66
+ assert @cost.has_key?('costs')
67
+ assert @cost.has_key?('total')
68
+ end
69
+
70
+ should "have a positive total cost" do
71
+ assert @cost['total'] > 0
72
+ end
73
+ end
74
+
75
+ context "Buffered data returned by a valid Definition object" do
76
+ setup do
77
+ init()
78
+ initUser(false)
79
+ @definition = @user.createDefinition(@testdata['definition'])
80
+ @interactions = @definition.getBuffered()
81
+ end
82
+
83
+ should "be valid" do
84
+ assert @interactions
85
+ end
86
+ end
87
+
88
+ context "A StreamConsumer object returned by a valid Definition object" do
89
+ setup do
90
+ init()
91
+ initUser(false)
92
+ @definition = @user.createDefinition(@testdata['definition'])
93
+ @consumer = @definition.getConsumer()
94
+ end
95
+
96
+ should "be valid" do
97
+ assert @consumer.is_a? DataSift::StreamConsumer
98
+ end
99
+ end
100
+ end