nervion 0.0.1 → 0.0.2

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
@@ -1,4 +1,6 @@
1
- TODOs
2
1
  .DS_Store
3
- examples
2
+ .rbx
3
+ .yardoc
4
4
  coverage
5
+ doc
6
+ examples
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ matrix:
3
+ allow_failures:
4
+ - rvm: ruby-head
5
+ rvm:
6
+ - rbx-19mode
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - ruby-head
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # version 0.0.2
2
+
3
+ - Support for firehose endpoint
4
+ - Validate client setup before start streaming
5
+
6
+ # version 0.0.1
7
+
8
+ - Support for sample and filter endpoints
9
+ - OAuth authentication
data/Gemfile.lock CHANGED
@@ -22,6 +22,7 @@ GEM
22
22
  http_parser.rb (0.5.3)
23
23
  json (1.7.3)
24
24
  multi_json (1.3.6)
25
+ rake (0.9.2.2)
25
26
  rspec (2.9.0)
26
27
  rspec-core (~> 2.9.0)
27
28
  rspec-expectations (~> 2.9.0)
@@ -35,6 +36,7 @@ GEM
35
36
  simplecov-html (~> 0.5.3)
36
37
  simplecov-html (0.5.3)
37
38
  yajl-ruby (1.1.0)
39
+ yard (0.8.2.1)
38
40
 
39
41
  PLATFORMS
40
42
  ruby
@@ -42,5 +44,7 @@ PLATFORMS
42
44
  DEPENDENCIES
43
45
  cucumber
44
46
  nervion!
47
+ rake
45
48
  rspec
46
49
  simplecov
50
+ yard
data/README.md CHANGED
@@ -1,24 +1,16 @@
1
- # Nervion
1
+ # Nervion [![Build Status](https://secure.travis-ci.org/jacegu/nervion.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/jacegu/nervion.png?travis)][gemnasium]
2
2
 
3
- **A minimalistic Twitter Stream API Ruby client**.
3
+ **A minimalistic Ruby client for the
4
+ [Public Streams](https://dev.twitter.com/docs/streaming-apis/streams/public)
5
+ of Twitter Streaming API**.
4
6
 
5
-
6
- ## Motivation
7
-
8
- In our current project we had the need to consume the stream provided by twitter.
9
- Although there are a few gems available we had to suffer the pain of poor
10
- documentation and error swallowing, which made us lose a lot of time.
11
-
12
- At that point I decided to build one on my own, and that's why you are reading
13
- this.
7
+ [travis]: http://travis-ci.org/jacegu/nervion
8
+ [gemnasium]: https://gemnasium.com/jacegu/nervion
14
9
 
15
10
 
16
11
 
17
12
  ## Installation
18
13
 
19
- **WARNING: This project hasn't been released as a Gem yet**. This is here for
20
- future reference.
21
-
22
14
  Add this line to your application's Gemfile:
23
15
 
24
16
  gem 'nervion'
@@ -33,36 +25,29 @@ Or install it yourself as:
33
25
 
34
26
 
35
27
 
36
- ## Usage
28
+ ## Overview
37
29
 
38
30
  Nervion mimics the endpoints provided by the
39
- [Twitter Stream API](https://dev.twitter.com/docs/streaming-apis).
40
- Currently it supports the
41
- [Public Streams](https://dev.twitter.com/docs/streaming-apis/streams/public).
42
- In the future we will add support for the
43
- [User Streams](https://dev.twitter.com/docs/streaming-apis/streams/user)
44
- and the
45
- [Site Streams](Use://dev.twitter.com/docs/streaming-apis/streams/site).
46
-
47
- Specifically the two calls that are that are available to the broad audience:
31
+ [Twitter Stream API](https://dev.twitter.com/docs/streaming-apis)
32
+ through the following methods:
48
33
 
49
34
  - [`follow`](https://dev.twitter.com/docs/api/1/post/statuses/filter)
50
35
  - [`sample`](https://dev.twitter.com/docs/api/1/get/statuses/sample)
51
-
52
- [`firehose`](https://dev.twitter.com/docs/api/1/get/statuses/firehose)
53
- is not supported yet since requires a special access level.
54
-
55
- Checkout the docs of both endpoints to know what tweets you can query the
56
- Streaming API for.
57
-
58
- You can specify any of the parameters supported by the endpoints by passing them
36
+ - [`firehose`](https://dev.twitter.com/docs/api/1/get/statuses/firehose)
37
+ *notice that the firehose support hasn't been tested against the actual API
38
+ since it requires a level of access I don't have. If you were able to verify
39
+ that it works, please, let me know*
40
+
41
+ Checkout the docs of the endpoints to know what tweets you can query the
42
+ Streaming API for and what parameters you have to provide to do so. You can
43
+ specify any of the parameters supported by the endpoints by passing them
59
44
  as named parameters to the provided methods:
60
45
 
61
46
  ```ruby
62
- require 'nervion'
63
-
64
- Nervion.filter(delimited: 1953, track: 'ruby', stall_warnings: true) do |parsed_status|
65
- #do something with the parsed status
47
+ # This is tracking every tweet that includes the string "madrid" OR any tweet
48
+ # that is geo-located in Madrid.
49
+ Nervion.filter(track: 'madrid', locations: '40.364,-3.760,40.365,-3.609') do |message|
50
+ # do something with the message
66
51
  end
67
52
  ```
68
53
 
@@ -72,7 +57,7 @@ Twitter.
72
57
 
73
58
 
74
59
 
75
- ###Authentication
60
+ ## Authentication
76
61
 
77
62
  Since Twitter plans to remove support for basic auth eventually, **Nervion only
78
63
  supports OAuth authentication**.
@@ -81,15 +66,16 @@ You can provide the tokens and secrets in a configuration flavour:
81
66
 
82
67
  ```ruby
83
68
  Nervion.configure do |config|
84
- config.consumer_key = the_consumer_key
85
- config.consumer_secret = the_consumer_secret
86
- config.access_token = the_access_token
87
- config.access_token_secret = the_access_token_secret
69
+ config.consumer_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
70
+ config.consumer_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
71
+ config.access_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
72
+ config.access_token_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
88
73
  end
89
74
  ```
90
75
 
91
76
 
92
- ###Parsing JSON
77
+
78
+ ## JSON Parsing
93
79
 
94
80
  **Nervion will parse the JSON returned by twitter for you**. It uses
95
81
  [Yajl](https://github.com/brianmario/yajl-ruby) as JSON parser for its out of
@@ -100,37 +86,42 @@ to use symbols to fetch data in the callbacks.
100
86
 
101
87
 
102
88
 
103
- ###Callbacks
89
+ ## Callbacks
104
90
 
105
- Nowdays Nervion only has one callback that acts upon the received statuses. It
106
- **will support callbacks on specific types of tweets and errors** in future
107
- versions.
91
+ Nervion provides three callbacks:
108
92
 
109
- The callbacks will receive only one parameter: the hash with the symbolized keys
110
- resultant of the JSON parsing. You get to choose what to do with the hash:
111
- [mash](https://github.com/intridea/hashie) it before working with it or even
112
- wrap it in some object that specializes on querying the information that is
113
- relevant to you.
114
-
115
- To know what keys to expect you should browse the
116
- [*Platform Objects Documentation*](https://dev.twitter.com/docs/platform-objects/tweets).
93
+ - **Message callback**: called when message is received and parsed
94
+ - **HTTP error callback**: called when Twitter responds with a status above 200
95
+ - **Network error callback**: called when the connection to the stream is lost
117
96
 
118
97
 
119
- ####Status Callback
98
+ ### Message Callback
120
99
 
121
- You can setup a callback that **acts on all the received statuses** by simply
100
+ You must setup a callback that **acts on all the received messages** by simply
122
101
  passing in a block to the API call you are making:
123
102
 
124
103
  ```ruby
125
- Nervion.sample { |status| puts status[:text] if status.has_key? :text }
104
+ Nervion.sample { |message| puts message[:text] if message.has_key? :text }
126
105
  ```
127
106
 
128
- Be aware that **the callback will be called with any type of timeline update**
129
- (or even with warnings if the `stall_warnings` parameter is set to `true`. Keep
130
- this in mind when querying the hash.
107
+ Be aware that
108
+ **[every message type](https://dev.twitter.com/docs/streaming-apis/messages)
109
+ will trigger this callback**. Keep this in mind when querying the hash.
110
+
111
+ The callback receives only one parameter: the hash with the symbolized keys
112
+ resultant of the JSON parsing. You get to choose what to do with the hash:
113
+ [mash](https://github.com/intridea/hashie) it before working with it or even
114
+ wrap it in some object that specializes on querying the information that is
115
+ relevant to you.
116
+
117
+ To know what keys to expect you should browse the
118
+ [*Platform Objects Documentation*](https://dev.twitter.com/docs/platform-objects/tweets)
119
+ and know the different
120
+ [message types](https://dev.twitter.com/docs/streaming-apis/messages)
121
+ .
131
122
 
132
123
 
133
- #### HTTP Error Callback
124
+ ### HTTP Error Callback
134
125
 
135
126
  This callback will be executed when the Streaming API sends a response with a
136
127
  status code above 200. After the callback has been executed a retry will be
@@ -142,17 +133,18 @@ You can setup the callback like this:
142
133
 
143
134
  ```ruby
144
135
  Nervion.on_http_error do |status, body|
145
- puts "Response status was: #{status}"
146
- puts "Response body was: #{body}"
136
+ puts "the status of the response was: #{status}"
137
+ puts "the body of the response body was: #{body}"
147
138
  end
148
139
  ```
149
140
 
150
- If no callback is set, Nervion's default behaviour will be to output the an
151
- error message to `STDERR` that contains both the status and the body of Twitter
152
- Streaming API's response.
141
+ Given that most of the HTTP errors are due to client configuration, if no
142
+ callback is set, Nervion's default behaviour will be to output an error message
143
+ to `STDERR` that contains both the status and the body of Twitter Streaming
144
+ API's response.
153
145
 
154
146
 
155
- #### Network Error callback
147
+ ### Network Error callback
156
148
 
157
149
  This callback will be executed when the connection with the Twitter Stream API
158
150
  is unexpectedly closed.
@@ -163,10 +155,26 @@ Nervion.on_network_error do
163
155
  end
164
156
  ```
165
157
 
166
- **Nervion will do nothing by default when network errors occurr** because it is
158
+ Nervion will do nothing by default when network errors occur because it is
167
159
  unlikely that they are provoked by the client itself.
168
160
 
169
161
 
162
+ ### Callback chaining
163
+
164
+ Callback setup can be chained like this:
165
+
166
+ ```ruby
167
+ Nervion.on_network_error do
168
+ #do something about the error
169
+ end.on_http_error do |status, body|
170
+ #do something about the error
171
+ end.sample do |status|
172
+ #do something with the status
173
+ end
174
+ ```
175
+
176
+
177
+
170
178
  ## EventMachine Integration
171
179
 
172
180
  Nervion runs on the top of EventMachine.
@@ -174,6 +182,8 @@ Nervion runs on the top of EventMachine.
174
182
  In the near future this `README` will provide a guideline to take advantage of
175
183
  the benefits that EventMachine can provide when used correctly.
176
184
 
185
+
186
+
177
187
  ## Roadmap
178
188
 
179
189
  There are some features that are needed and that will be developed before the first
@@ -184,14 +194,12 @@ release of the gem:
184
194
  - <del>Adhere to the
185
195
  [Twitter Connection guidelines](https://dev.twitter.com/docs/streaming-api/concepts#connecting)</del>
186
196
  *done!*
187
- - Take advantage of EventMachine deferrables on callbacks
188
- - Rewrite and improve the DSL provided to setup Nervion
197
+ - <del>Improve the DSL provided to setup Nervion to validate the client
198
+ setup</del> *done!*
189
199
 
190
- Once those basic features are provided there are a few more that will be very
191
- interesting to have:
200
+ Future features will be:
192
201
 
193
202
  - Use a gzip compressed stream
194
- - Add callbacks to act on specific types of tweets: i.e. `on_retweet`,
195
- `on_deleted_status`
196
-
197
- If people start using the client more features will be added.
203
+ - Be able to configure the client to skip parsing and yield bare Strings with
204
+ the JSON of the streamed messages. The objective is to improve performance by
205
+ parsing in other process.
data/Rakefile CHANGED
@@ -1,10 +1,11 @@
1
- #!/usr/bin/env rake
2
-
3
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
4
2
  require 'rspec/core/rake_task'
5
3
  require 'cucumber/rake/task'
4
+ require 'yard'
6
5
 
7
6
  task :default => [:test]
7
+
8
+ desc 'Run all the features and specs'
8
9
  task :test => [:rspec, :cucumber]
9
10
 
10
11
  RSpec::Core::RakeTask.new(:rspec) do |t|
@@ -15,7 +16,10 @@ Cucumber::Rake::Task.new(:cucumber) do |t|
15
16
  t.cucumber_opts = '--format progress'
16
17
  end
17
18
 
18
- task :cov do
19
+ YARD::Rake::YardocTask.new
20
+
21
+ desc 'Generate test coverage report'
22
+ task :coverage do
19
23
  ENV['COVERAGE'] = 'true'
20
24
  Rake::Task[:rspec].execute
21
25
  Rake::Task[:cucumber].execute
@@ -1,7 +1,8 @@
1
1
  Feature: Callbacks
2
2
 
3
3
  Background:
4
- Given Nervion is connected to Twitter Streaming API
4
+ Given Nervion has been configured
5
+ And Nervion is connected to Twitter Streaming API
5
6
 
6
7
  Scenario: Calling the status callback
7
8
  When a status update is sent by Twitter
@@ -0,0 +1,17 @@
1
+ Feature: Client setup validation
2
+
3
+ Scenario: Missing authentication
4
+ Given I haven't configured Nervion
5
+ When I try to start streaming
6
+ Then I get an error pointing me to the readme file
7
+
8
+ Scenario Outline: Calling filter without a message callback
9
+ Given Nervion has been configured
10
+ When I try to start streaming the <endpoint_name> endpoint
11
+ Then I get an error pointing me to the readme file
12
+
13
+ Examples:
14
+ | endpoint_name |
15
+ | filter |
16
+ | firehose |
17
+ | sample |
@@ -0,0 +1,26 @@
1
+ AUTHENTICATION_README_URL = 'https://github.com/jacegu/nervion'
2
+
3
+ def capture_errors_in
4
+ begin
5
+ yield
6
+ rescue Exception => error
7
+ @error = error
8
+ end
9
+ end
10
+
11
+ Given /^I haven't configured Nervion$/ do
12
+ Nervion::Configuration.instance_variable_set '@configured', nil
13
+ end
14
+
15
+ When /^I try to start streaming$/ do
16
+ capture_errors_in { Nervion.sample { |status| puts status } }
17
+ end
18
+
19
+ When /^I try to start streaming the (.*?) endpoint$/ do |endpoint_name|
20
+ params = { stall_warnings: true }
21
+ capture_errors_in { Nervion.send(endpoint_name.to_sym, params) }
22
+ end
23
+
24
+ Then /^I get an error pointing me to the readme file$/ do
25
+ @error.message.should match /#{AUTHENTICATION_README_URL}/
26
+ end
@@ -1,3 +1,4 @@
1
+ KNOWN_STATUS_COUNT = 100
1
2
  TEST_HOST = '0.0.0.0'
2
3
  TEST_PORT = '9000'
3
4
 
@@ -12,7 +13,16 @@ def test_client_with(server_version)
12
13
  EM.run do
13
14
  EM.start_server(TEST_HOST, TEST_PORT, server_version)
14
15
  EM.add_timer(0) { Nervion.sample { |status| @statuses << status } }
15
- EM.add_timer(0.1) { EM.stop }
16
+ EM.add_timer(0.3) { EM.stop }
17
+ end
18
+ end
19
+
20
+ Given /^Nervion has been configured$/ do
21
+ Nervion.configure do |config|
22
+ config.consumer_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
23
+ config.consumer_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
24
+ config.access_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
25
+ config.access_token_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
16
26
  end
17
27
  end
18
28
 
@@ -42,7 +52,7 @@ When /^a network error occurs$/ do
42
52
  end
43
53
 
44
54
  Then /^Nervion calls the status callback with it$/ do
45
- @statuses.count.should eq 100
55
+ @statuses.count.should eq KNOWN_STATUS_COUNT
46
56
  end
47
57
 
48
58
  Then /^Nervion calls the HTTP error callback$/ do
data/lib/nervion.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  $: << File.join(File.dirname(__FILE__), '..')
2
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
3
 
3
4
  require 'nervion/facade'
4
5
  require 'nervion/version'
@@ -1,5 +1,3 @@
1
- require 'nervion/configuration'
2
- require 'nervion/request'
3
1
  require 'nervion/stream'
4
2
  require 'nervion/stream_handler'
5
3
 
@@ -11,12 +9,12 @@ module Nervion
11
9
  end
12
10
 
13
11
  def stream(request, callbacks)
14
- @stream_handler = StreamHandler.new(callbacks)
15
- EM.run { EM.connect @host, @port, Stream, request, @stream_handler }
12
+ handler = StreamHandler.new(callbacks)
13
+ EM.run { @stream = EM.connect @host, @port, Stream, request, handler }
16
14
  end
17
15
 
18
16
  def stop
19
- @stream_handler.close_stream
17
+ @stream.close
20
18
  EM.stop
21
19
  end
22
20
  end
@@ -1,12 +1,19 @@
1
1
  module Nervion
2
2
 
3
+ # Allows to configure Nervion.
4
+ #
5
+ # @yieldparam [Configuration] config the configuration object.
3
6
  def self.configure
7
+ Configuration.configured!
4
8
  yield Configuration
5
9
  end
6
10
 
7
11
  class Configuration
8
12
  UNCONFIGURED_SETTING = ''
9
13
 
14
+ # Configures the consumer key
15
+ #
16
+ # @param [String] consumer_key the consumer key
10
17
  def self.consumer_key=(consumer_key)
11
18
  @consumer_key = consumer_key
12
19
  end
@@ -15,6 +22,9 @@ module Nervion
15
22
  @consumer_key || UNCONFIGURED_SETTING
16
23
  end
17
24
 
25
+ # Configures the consumer secret
26
+ #
27
+ # @param [String] consumer_secret the consumer secret
18
28
  def self.consumer_secret=(consumer_secret)
19
29
  @consumer_secret = consumer_secret
20
30
  end
@@ -23,6 +33,9 @@ module Nervion
23
33
  @consumer_secret || UNCONFIGURED_SETTING
24
34
  end
25
35
 
36
+ # Configures the access token
37
+ #
38
+ # @param [String] access_token the access token
26
39
  def self.access_token=(access_token)
27
40
  @access_token = access_token
28
41
  end
@@ -31,6 +44,9 @@ module Nervion
31
44
  @access_token || UNCONFIGURED_SETTING
32
45
  end
33
46
 
47
+ # Configures the access token secret
48
+ #
49
+ # @param [String] access_token_secret the access token secret
34
50
  def self.access_token_secret=(access_token_secret)
35
51
  @access_token_secret = access_token_secret
36
52
  end
@@ -46,5 +62,13 @@ module Nervion
46
62
  def self.fetch(setting)
47
63
  send setting.to_sym
48
64
  end
65
+
66
+ def self.configured?
67
+ @configured
68
+ end
69
+
70
+ def self.configured!
71
+ @configured = true
72
+ end
49
73
  end
50
74
  end
@@ -4,31 +4,91 @@ require 'nervion/request'
4
4
  require 'nervion/configuration'
5
5
 
6
6
  module Nervion
7
- STREAM_API_HOST = 'stream.twitter.com'
8
- STREAM_API_PORT = 443
9
- SAMPLE_ENDPOINT = "https://#{STREAM_API_HOST}/1/statuses/sample.json"
10
- FILTER_ENDPOINT = "https://#{STREAM_API_HOST}/1/statuses/filter.json"
11
-
7
+ # Sets up the callback to be called upon HTTP errors (when the response from
8
+ # Twitter's Streaming API has a status above 200).
9
+ #
10
+ # @param [Proc] callback the callback
11
+ # @return [self] to allow callback setup chaining
12
12
  def self.on_http_error(&callback)
13
13
  callback_table[:http_error] = callback
14
14
  self
15
15
  end
16
16
 
17
+ # Sets up the callback to be called upon network errors or unexpected
18
+ # disconnection.
19
+ #
20
+ # @param [Proc] callback the callback
21
+ # @return [self] to allow callback setup chaining
17
22
  def self.on_network_error(&callback)
18
23
  callback_table[:network_error] = callback
19
24
  self
20
25
  end
21
26
 
27
+ # Sets up the message callback and starts streaming the sample endpoint.
28
+ #
29
+ # @see https://dev.twitter.com/docs/api/1/get/statuses/sample
30
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#delimited
31
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#stall_warnings
32
+ #
33
+ # @param [hash] params the parameters submitted to the sample endpoint
34
+ # @option params [Boolean] :delimited specifies whether messages should be
35
+ # length-delimited.
36
+ # @option params [Boolean] :stall_warnings specifies whether stall warnings
37
+ # should be delivered.
38
+ # @param [Proc] callback the callback
22
39
  def self.sample(params = {}, &callback)
23
- callback_table[:status] = callback
24
- new_client.tap { |c| c.stream sample_endpoint(params), callback_table }
40
+ stream sample_endpoint(params), callback
25
41
  end
26
42
 
43
+ # Sets up the message callback and starts streaming the filter endpoint.
44
+ #
45
+ # @note At least one predicate parameter (follow, locations, or track) must be
46
+ # specified.
47
+ #
48
+ # @see https://dev.twitter.com/docs/api/1/get/statuses/filter
49
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#follow
50
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#track
51
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#locations
52
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#delimited
53
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#stall_warnings
54
+ #
55
+ # @param [hash] params the parameters submitted to the sample endpoint
56
+ # @option params [String] :follow a comma separated list of user IDs,
57
+ # indicating the users to return statuses for in the stream.
58
+ # @option params [String] :track keywords to track. Phrases of keywords are
59
+ # specified by a comma-separated list.
60
+ # @option params [String] :locations Specifies a set of bounding boxes to track.
61
+ # @option params [Boolean] :delimited specifies whether messages should be
62
+ # length-delimited.
63
+ # @option params [Boolean] :stall_warnings specifies whether stall warnings
64
+ # should be delivered.
65
+ # @param [Proc] callback the callback
27
66
  def self.filter(params, &callback)
28
- callback_table[:status] = callback
29
- new_client.tap { |c| c.stream filter_endpoint(params), callback_table }
67
+ stream filter_endpoint(params), callback
68
+ end
69
+
70
+ # Sets up the message callback and starts streaming the firehose endpoint.
71
+ #
72
+ # @note This endpoint requires a special access level.
73
+ # @since 0.0.2
74
+ #
75
+ # @see https://dev.twitter.com/docs/api/1/get/statuses/firehose
76
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#count
77
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#delimited
78
+ # @see https://dev.twitter.com/docs/streaming-apis/parameters#stall_warnings
79
+ #
80
+ # @param [hash] params the parameters submitted to the sample endpoint
81
+ # @option params [Integer] :count the number of messages to backfill.
82
+ # @option params [Boolean] :delimited specifies whether messages should be
83
+ # length-delimited.
84
+ # @option params [Boolean] :stall_warnings specifies whether stall warnings
85
+ # should be delivered.
86
+ # @param [Proc] callback the callback
87
+ def self.firehose(params = {}, &callback)
88
+ stream firehose_endpoint(params), callback
30
89
  end
31
90
 
91
+ # Stops streaming
32
92
  def self.stop
33
93
  raise 'Nervion is not running' if @client.nil?
34
94
  @client.stop
@@ -40,15 +100,44 @@ module Nervion
40
100
  @callback_table ||= CallbackTable.new
41
101
  end
42
102
 
103
+ def self.stream(endpoint, callback)
104
+ raise_not_configured_error unless Configuration.configured?
105
+ raise_no_message_callback_error if callback.nil?
106
+ callback_table[:message] = callback
107
+ new_client.tap { |c| c.stream endpoint, callback_table }
108
+ end
109
+
43
110
  def self.new_client
44
111
  @client = Client.new(STREAM_API_HOST, STREAM_API_PORT)
45
112
  end
46
113
 
47
114
  def self.sample_endpoint(params)
48
- get SAMPLE_ENDPOINT, params, Configuration
115
+ get SAMPLE_ENDPOINT, params, Configuration
49
116
  end
50
117
 
51
118
  def self.filter_endpoint(params)
52
119
  post FILTER_ENDPOINT, params, Configuration
53
120
  end
121
+
122
+ def self.firehose_endpoint(params)
123
+ get FIREHOSE_ENDPOINT, params, Configuration
124
+ end
125
+
126
+ def self.raise_not_configured_error
127
+ raise "You need to setup the authentication information for Nervion to work. Please, check out #{AUTHENTICATION_README_URL}"
128
+ end
129
+
130
+ def self.raise_no_message_callback_error
131
+ raise "You have to setup a message callback. Please, check out #{MSG_CALLBACK_README_URL}"
132
+ end
133
+
134
+ STREAM_API_HOST = 'stream.twitter.com'
135
+ STREAM_API_PORT = 443
136
+ SAMPLE_ENDPOINT = "https://#{STREAM_API_HOST}/1/statuses/sample.json"
137
+ FILTER_ENDPOINT = "https://#{STREAM_API_HOST}/1/statuses/filter.json"
138
+ FIREHOSE_ENDPOINT = "https://#{STREAM_API_HOST}/1/statuses/firehose.json"
139
+
140
+ AUTHENTICATION_README_URL = 'https://github.com/jacegu/nervion#authentication'
141
+ MSG_CALLBACK_README_URL = 'https://github.com/jacegu/nervion#message-callback'
142
+
54
143
  end
@@ -1,14 +1,7 @@
1
1
  require_relative 'oauth_header'
2
+ require_relative 'percent_encoder'
2
3
 
3
4
  module Nervion
4
- def self.get(uri, params = {}, oauth_params)
5
- Get.new uri, params, oauth_params
6
- end
7
-
8
- def self.post(uri, params = {}, oauth_params)
9
- Post.new uri, params, oauth_params
10
- end
11
-
12
5
  module Request
13
6
  attr_reader :params, :oauth_params
14
7
 
@@ -73,7 +66,6 @@ module Nervion
73
66
 
74
67
  class Post
75
68
  include Request
76
- include PercentEncoder
77
69
 
78
70
  def to_s
79
71
  "#{request_line}\r\n#{headers.join("\r\n")}\r\n\r\n#{body}\r\n"
@@ -96,4 +88,15 @@ module Nervion
96
88
  percent_encode params
97
89
  end
98
90
  end
91
+
92
+ private
93
+
94
+ def self.get(uri, params = {}, oauth_params)
95
+ Get.new uri, params, oauth_params
96
+ end
97
+
98
+ def self.post(uri, params = {}, oauth_params)
99
+ Post.new uri, params, oauth_params
100
+ end
101
+
99
102
  end
@@ -1,5 +1,5 @@
1
1
  require 'eventmachine'
2
- require 'nervion/http_parser'
2
+ require 'nervion/stream_parser'
3
3
  require 'nervion/reconnection_scheduler'
4
4
 
5
5
  module Nervion
@@ -33,29 +33,37 @@ module Nervion
33
33
  end
34
34
 
35
35
  def unbind
36
- handle_closed_stream unless @handler.stream_close_requested?
36
+ handle_closed_stream unless close_requested?
37
37
  end
38
38
 
39
39
  def http_error_occurred?
40
40
  not http_error.nil?
41
41
  end
42
42
 
43
+ def close_requested?
44
+ @close_stream ||= false
45
+ end
46
+
47
+ def close
48
+ @close_stream = true
49
+ end
50
+
43
51
  private
44
52
 
45
53
  def handle_closed_stream
46
54
  if http_error_occurred?
47
- handle_http_error_and_reopen_stream
55
+ handle_http_error_and_retry
48
56
  else
49
- handle_network_error_and_reopen_stream
57
+ handle_network_error_and_retry
50
58
  end
51
59
  end
52
60
 
53
- def handle_http_error_and_reopen_stream
61
+ def handle_http_error_and_retry
54
62
  @handler.handle_http_error http_error
55
63
  @scheduler.reconnect_after_http_error_in self
56
64
  end
57
65
 
58
- def handle_network_error_and_reopen_stream
66
+ def handle_network_error_and_retry
59
67
  @handler.handle_network_error
60
68
  @scheduler.reconnect_after_network_error_in self
61
69
  end
@@ -1,42 +1,24 @@
1
- require 'yajl'
2
- require 'nervion/http_parser'
1
+ require 'nervion/stream_parser'
3
2
 
4
3
  module Nervion
5
4
  class StreamHandler
6
-
7
- def initialize(callbacks)
8
- @callbacks = callbacks
9
- @http_parser = HttpParser.new(setup_json_parser)
5
+ def initialize(callbacks, stream_parser = StreamParser.new)
6
+ @callbacks, @stream_parser = callbacks, stream_parser
7
+ @stream_parser.on_json_parsed = @callbacks[:message]
10
8
  end
11
9
 
12
10
  def <<(data)
13
- @http_parser << data
11
+ @stream_parser << data
14
12
  end
15
13
 
16
14
  def handle_http_error(error)
17
- @http_parser.reset!
15
+ @stream_parser.reset!
18
16
  @callbacks[:http_error].call(error.status, error.body)
19
17
  end
20
18
 
21
19
  def handle_network_error
22
- @http_parser.reset!
20
+ @stream_parser.reset!
23
21
  @callbacks[:network_error].call
24
22
  end
25
-
26
- def stream_close_requested?
27
- @close_stream ||= false
28
- end
29
-
30
- def close_stream
31
- @close_stream = true
32
- end
33
-
34
- private
35
-
36
- def setup_json_parser
37
- Yajl::Parser.new(symbolize_keys: true).tap do |json_parser|
38
- json_parser.on_parse_complete = @callbacks[:status]
39
- end
40
- end
41
23
  end
42
24
  end
@@ -1,12 +1,18 @@
1
+ require 'yajl'
1
2
  require 'http/parser'
2
3
 
3
4
  module Nervion
4
- class HttpParser
5
+ class StreamParser
5
6
  attr_reader :json_parser, :http_parser
6
7
 
7
- def initialize(json_parser)
8
- @json_parser = json_parser
9
- @http_parser = setup_http_parser
8
+ def initialize(parsers = {})
9
+ @http_parser = parsers[:http_parser] || Http::Parser.new
10
+ @json_parser = parsers[:json_parser] || Yajl::Parser.new(symbolize_keys: true)
11
+ @http_parser.on_body = method(:process)
12
+ end
13
+
14
+ def on_json_parsed=(callback)
15
+ @json_parser.on_parse_complete = callback
10
16
  end
11
17
 
12
18
  def <<(http_stream)
@@ -19,10 +25,6 @@ module Nervion
19
25
 
20
26
  private
21
27
 
22
- def setup_http_parser
23
- Http::Parser.new.tap { |parser| parser.on_body = method(:process) }
24
- end
25
-
26
28
  def process(chunk)
27
29
  if request_successful?
28
30
  parse_json_from chunk
@@ -1,3 +1,3 @@
1
1
  module Nervion
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/nervion.gemspec CHANGED
@@ -18,7 +18,9 @@ Gem::Specification.new do |gem|
18
18
  gem.add_runtime_dependency 'eventmachine', '~> 1.0.0.beta.4'
19
19
  gem.add_runtime_dependency 'http_parser.rb', '~> 0.5.3'
20
20
  gem.add_runtime_dependency 'yajl-ruby', '~> 1.1.0'
21
- gem.add_development_dependency 'rspec'
22
21
  gem.add_development_dependency 'cucumber'
22
+ gem.add_development_dependency 'rake'
23
+ gem.add_development_dependency 'rspec'
23
24
  gem.add_development_dependency 'simplecov'
25
+ gem.add_development_dependency 'yard'
24
26
  end
@@ -5,6 +5,7 @@ describe Nervion::Client do
5
5
  subject { described_class.new('http://twitter.com', 443) }
6
6
  let(:request) { stub :request }
7
7
  let(:callbacks) { stub :callbacks }
8
+ let(:stream) { mock :stream }
8
9
  let(:stream_handler) { stub :stream_handler }
9
10
 
10
11
  before(:all) do
@@ -43,7 +44,8 @@ describe Nervion::Client do
43
44
  end
44
45
 
45
46
  it 'stops streaming' do
46
- stream_handler.should_receive(:close_stream).ordered
47
+ EM.stub(:connect).and_return(stream)
48
+ stream.should_receive(:close).ordered
47
49
  EM.should_receive(:stop).ordered
48
50
  subject.stream(request, callbacks)
49
51
  subject.stop
@@ -2,11 +2,25 @@ require 'nervion/configuration'
2
2
 
3
3
  describe Nervion::Configuration do
4
4
 
5
+ before do
6
+ %w{
7
+ consumer_key consumer_secret access_token access_token_secret configured
8
+ }.each do |variable|
9
+ described_class.instance_variable_set "@#{variable}", nil
10
+ end
11
+ end
12
+
5
13
  it 'allows configuration from the top level' do
6
14
  Nervion::Configuration.should_receive(:access_key=).with 'access_key'
7
15
  Nervion.configure { |config| config.access_key = 'access_key' }
8
16
  end
9
17
 
18
+ it 'knows if Nervion has been configured' do
19
+ Nervion::Configuration.should_not be_configured
20
+ Nervion.configure { |config| }
21
+ Nervion::Configuration.should be_configured
22
+ end
23
+
10
24
  context 'when it has not been configured' do
11
25
  it 'has an empty string as consumer_key' do
12
26
  described_class.consumer_key.should eq ''
@@ -1,8 +1,10 @@
1
1
  require 'nervion/facade'
2
2
 
3
+ class Callable; def call; end; end;
4
+
3
5
  describe "Facade that exposes Nervion's API" do
4
6
  let(:callback_table) { mock(:callback_table).as_null_object }
5
- let(:status_callback) { lambda { :status_callback } }
7
+ let(:message_callback) { lambda { :message_callback } }
6
8
  let(:http_callback) { lambda { :http_error_callback } }
7
9
  let(:network_callback) { lambda { :network_error_callback } }
8
10
 
@@ -40,43 +42,65 @@ describe "Facade that exposes Nervion's API" do
40
42
  let(:request) { stub :request }
41
43
 
42
44
  before do
45
+ Nervion.configure { |config| }
43
46
  Nervion::Client.stub(:new).
44
47
  with(Nervion::STREAM_API_HOST, Nervion::STREAM_API_PORT).
45
48
  and_return(client)
46
49
  end
47
50
 
48
- context 'sample endpoint' do
49
- it 'sets up the status callback' do
50
- callback_table.should_receive(:[]=).with(:status, status_callback)
51
- Nervion.sample(&status_callback)
51
+ shared_examples_for 'an endpoint' do
52
+ it 'sets up the message callback' do
53
+ callback_table.should_receive(:[]=).with(:message, message_callback)
54
+ Nervion.send(method_name, params, &message_callback)
52
55
  end
53
56
 
54
57
  it 'starts the streaming to the sample endpoint' do
55
- Nervion.stub(:get).with(Nervion::SAMPLE_ENDPOINT, params, config).
58
+ Nervion.stub(http_method).with(endpoint, params, config).
56
59
  and_return(request)
57
60
  client.should_receive(:stream).with(request, callback_table)
58
- Nervion.sample(params, &status_callback)
61
+ Nervion.send(method_name, params, &message_callback)
59
62
  end
60
- end
61
63
 
62
- context 'filter endpoint' do
63
- it 'sets up the status callback' do
64
- callback_table.should_receive(:[]=).with(:status, status_callback)
65
- Nervion.filter(params, &status_callback)
64
+ it 'raises an error if Nervion was not configured' do
65
+ expect do
66
+ Nervion::Configuration.instance_variable_set(:@configured, nil)
67
+ Nervion.send(method_name, params, &message_callback)
68
+ end.to raise_error
66
69
  end
67
70
 
68
- it 'starts the streaming to the filter endpoint' do
69
- Nervion.stub(:post).with(Nervion::FILTER_ENDPOINT, params, config).
70
- and_return(request)
71
- client.should_receive(:stream).with(request, callback_table)
72
- Nervion.filter(params, &status_callback)
71
+ it 'raises an error if no message callback was provided' do
72
+ expect { Nervion.send(method_name, params) }.to raise_error
73
73
  end
74
74
  end
75
75
 
76
+ context 'sample endpoint' do
77
+ let(:http_method) { :get }
78
+ let(:endpoint) { Nervion::SAMPLE_ENDPOINT }
79
+ let(:method_name) { :sample }
80
+
81
+ it_behaves_like 'an endpoint'
82
+ end
83
+
84
+ context 'filter endpoint' do
85
+ let(:http_method) { :post }
86
+ let(:endpoint) { Nervion::FILTER_ENDPOINT }
87
+ let(:method_name) { :filter }
88
+
89
+ it_behaves_like 'an endpoint'
90
+ end
91
+
92
+ context 'firehose endpoint' do
93
+ let(:http_method) { :get }
94
+ let(:endpoint) { Nervion::FIREHOSE_ENDPOINT }
95
+ let(:method_name) { :firehose }
96
+
97
+ it_behaves_like 'an endpoint'
98
+ end
99
+
76
100
  context 'stoping' do
77
101
  it 'can stop the streaming' do
78
102
  client.should_receive(:stop)
79
- Nervion.sample(->{})
103
+ Nervion.sample{}
80
104
  Nervion.stop
81
105
  end
82
106
 
@@ -59,7 +59,6 @@ describe Nervion::Request do
59
59
  subject.path.should eq '/endpoint?p1=param%20value&p2=%24%26'
60
60
  end
61
61
 
62
-
63
62
  it 'has an string representation' do
64
63
  Nervion::OAuthHeader.stub(:for).with(subject).and_return 'OAuth xxx'
65
64
  subject.to_s.should eq EXPECTED_GET_REQUEST
@@ -3,27 +3,25 @@ require 'nervion/stream_handler'
3
3
  describe Nervion::StreamHandler do
4
4
  subject { described_class.new callbacks }
5
5
  let(:http_parser) { mock(:http_parser).as_null_object }
6
- let(:json_parser) { mock(:json_parser).as_null_object }
7
6
 
8
7
  let(:callbacks) do
9
8
  {
10
- status: status_callback,
9
+ message: message_callback,
11
10
  http_error: http_error_callback,
12
11
  network_error: network_error_callback
13
12
  }
14
13
  end
15
14
 
16
- let(:status_callback) { mock :status_callback }
15
+ let(:message_callback) { mock :message_callback }
17
16
  let(:http_error_callback) { mock(:http_error_callback).as_null_object }
18
17
  let(:network_error_callback) { mock(:network_error_callback).as_null_object }
19
18
 
20
19
  before do
21
- Yajl::Parser.stub(:new).with(symbolize_keys: true).and_return(json_parser)
22
- Nervion::HttpParser.stub(:new).with(json_parser).and_return(http_parser)
20
+ Nervion::StreamParser.stub(:new).and_return(http_parser)
23
21
  end
24
22
 
25
- it 'sets up the status received callback' do
26
- json_parser.should_receive(:on_parse_complete=).with(status_callback)
23
+ it 'sets up the message received callback' do
24
+ http_parser.should_receive(:on_json_parsed=).with(message_callback)
27
25
  described_class.new callbacks
28
26
  end
29
27
 
@@ -33,12 +31,6 @@ describe Nervion::StreamHandler do
33
31
  subject << data
34
32
  end
35
33
 
36
- it 'can be told to close the stream' do
37
- subject.stream_close_requested?.should be_false
38
- subject.close_stream
39
- subject.stream_close_requested?.should be_true
40
- end
41
-
42
34
  context 'handling HTTP errors' do
43
35
  let(:http_error) { stub(:http_error, status: 401, body: 'Unauthorized') }
44
36
 
@@ -0,0 +1,44 @@
1
+ require 'nervion/stream_parser'
2
+ require 'fixtures/responses'
3
+
4
+ describe Nervion::StreamParser do
5
+ subject { described_class.new(json_parser: json_parser) }
6
+ let(:json_parser) { stub(:json_parser).as_null_object }
7
+
8
+ it 'takes a JSON parser' do
9
+ subject.json_parser.should be json_parser
10
+ end
11
+
12
+ it 'uses Http::Parser as the default HTTP parser' do
13
+ http_parser = stub(:http_parser).as_null_object
14
+ Http::Parser.stub(:new).and_return(http_parser)
15
+ described_class.new.http_parser.should be http_parser
16
+ end
17
+
18
+ it 'uses Yajl with symbolized keys as the default JSON parser' do
19
+ yajl_parser = stub(:yajl_parser)
20
+ Yajl::Parser.stub(:new).with(symbolize_keys: true).and_return(yajl_parser)
21
+ described_class.new.json_parser.should be yajl_parser
22
+ end
23
+
24
+ it 'can be set up with a JSON parse complete callback' do
25
+ callback = lambda {}
26
+ json_parser.should_receive(:on_parse_complete=).with callback
27
+ subject.on_json_parsed = callback
28
+ end
29
+
30
+ it 'can be reset' do
31
+ subject << RESPONSE_200
32
+ subject.reset!
33
+ expect { subject << RESPONSE_200 }.not_to raise_error Http::Parser::Error
34
+ end
35
+
36
+ it 'parses response body if the response status is 200' do
37
+ json_parser.should_receive(:<<).with(BODY_200)
38
+ subject << RESPONSE_200
39
+ end
40
+
41
+ it 'raises an error if the response status is above 200' do
42
+ expect { subject << RESPONSE_401 }.to raise_error Nervion::HttpError
43
+ end
44
+ end
@@ -46,10 +46,15 @@ describe Nervion::Stream do
46
46
  subject.retry
47
47
  end
48
48
 
49
+ it 'can be closed' do
50
+ subject.close_requested?.should be_false
51
+ subject.close
52
+ subject.close_requested?.should be_true
53
+ end
54
+
49
55
  context 'on unbound connections' do
50
56
  context 'due to HTTP errors' do
51
57
  before do
52
- handler.stub(:stream_close_requested?).and_return(false)
53
58
  subject.stub(:http_error).and_return(http_error)
54
59
  end
55
60
 
@@ -67,8 +72,6 @@ describe Nervion::Stream do
67
72
  end
68
73
 
69
74
  context 'due to network errors' do
70
- before { handler.stub(:stream_close_requested?).and_return(false) }
71
-
72
75
  it 'notifies the error' do
73
76
  handler.should_receive(:handle_network_error)
74
77
  scheduler.stub(:reconnect_after_network_error_in)
@@ -84,11 +87,11 @@ describe Nervion::Stream do
84
87
 
85
88
  context 'due to a request to close the stream' do
86
89
  it 'lets the stream to be closed' do
87
- handler.stub(:stream_close_requested?).and_return(true)
88
90
  handler.should_not_receive(:handle_http_error)
89
91
  handler.should_not_receive(:handle_network_error)
90
92
  scheduler.should_not_receive(:reconnect_after_http_error_in)
91
93
  scheduler.should_not_receive(:reconnect_after_network_error_in)
94
+ subject.close
92
95
  subject.unbind
93
96
  end
94
97
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nervion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-19 00:00:00.000000000 Z
12
+ date: 2012-06-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -60,7 +60,7 @@ dependencies:
60
60
  - !ruby/object:Gem::Version
61
61
  version: 1.1.0
62
62
  - !ruby/object:Gem::Dependency
63
- name: rspec
63
+ name: cucumber
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
@@ -76,7 +76,23 @@ dependencies:
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  - !ruby/object:Gem::Dependency
79
- name: cucumber
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
80
96
  requirement: !ruby/object:Gem::Requirement
81
97
  none: false
82
98
  requirements:
@@ -107,6 +123,22 @@ dependencies:
107
123
  - - ! '>='
108
124
  - !ruby/object:Gem::Version
109
125
  version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: yard
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
110
142
  description: A minimalistic Twitter Stream API Ruby client
111
143
  email:
112
144
  - j4cegu@gmail.com
@@ -117,13 +149,17 @@ files:
117
149
  - .gitignore
118
150
  - .rspec
119
151
  - .rvmrc
152
+ - .travis.yml
153
+ - CHANGELOG.md
120
154
  - Gemfile
121
155
  - Gemfile.lock
122
156
  - LICENSE
123
157
  - README.md
124
158
  - Rakefile
159
+ - features/callbacks.feature
160
+ - features/client_validation.feature
161
+ - features/step_definitions/client_validation_steps.rb
125
162
  - features/step_definitions/streaming_steps.rb
126
- - features/streaming.feature
127
163
  - features/support/env.rb
128
164
  - features/support/streaming_api_double.rb
129
165
  - fixtures/responses.rb
@@ -133,7 +169,6 @@ files:
133
169
  - lib/nervion/client.rb
134
170
  - lib/nervion/configuration.rb
135
171
  - lib/nervion/facade.rb
136
- - lib/nervion/http_parser.rb
137
172
  - lib/nervion/oauth_header.rb
138
173
  - lib/nervion/oauth_signature.rb
139
174
  - lib/nervion/percent_encoder.rb
@@ -141,19 +176,20 @@ files:
141
176
  - lib/nervion/request.rb
142
177
  - lib/nervion/stream.rb
143
178
  - lib/nervion/stream_handler.rb
179
+ - lib/nervion/stream_parser.rb
144
180
  - lib/nervion/version.rb
145
181
  - nervion.gemspec
146
182
  - spec/nervion/callback_table_spec.rb
147
183
  - spec/nervion/client_spec.rb
148
184
  - spec/nervion/configuration_spec.rb
149
185
  - spec/nervion/facade_spec.rb
150
- - spec/nervion/http_parser_spec.rb
151
186
  - spec/nervion/oauth_header_spec.rb
152
187
  - spec/nervion/oauth_signature_spec.rb
153
188
  - spec/nervion/percent_encoder_spec.rb
154
189
  - spec/nervion/reconnection_scheduler_spec.rb
155
190
  - spec/nervion/request_spec.rb
156
191
  - spec/nervion/stream_handler_spec.rb
192
+ - spec/nervion/stream_parser_spec.rb
157
193
  - spec/nervion/stream_spec.rb
158
194
  - spec/spec_helper.rb
159
195
  homepage: https://github.com/jacegu/nervion
@@ -181,20 +217,23 @@ signing_key:
181
217
  specification_version: 3
182
218
  summary: ''
183
219
  test_files:
220
+ - features/callbacks.feature
221
+ - features/client_validation.feature
222
+ - features/step_definitions/client_validation_steps.rb
184
223
  - features/step_definitions/streaming_steps.rb
185
- - features/streaming.feature
186
224
  - features/support/env.rb
187
225
  - features/support/streaming_api_double.rb
188
226
  - spec/nervion/callback_table_spec.rb
189
227
  - spec/nervion/client_spec.rb
190
228
  - spec/nervion/configuration_spec.rb
191
229
  - spec/nervion/facade_spec.rb
192
- - spec/nervion/http_parser_spec.rb
193
230
  - spec/nervion/oauth_header_spec.rb
194
231
  - spec/nervion/oauth_signature_spec.rb
195
232
  - spec/nervion/percent_encoder_spec.rb
196
233
  - spec/nervion/reconnection_scheduler_spec.rb
197
234
  - spec/nervion/request_spec.rb
198
235
  - spec/nervion/stream_handler_spec.rb
236
+ - spec/nervion/stream_parser_spec.rb
199
237
  - spec/nervion/stream_spec.rb
200
238
  - spec/spec_helper.rb
239
+ has_rdoc:
@@ -1,26 +0,0 @@
1
- require 'nervion/http_parser'
2
- require 'fixtures/responses'
3
-
4
- describe Nervion::HttpParser do
5
- subject { described_class.new(json_parser) }
6
- let(:json_parser) { stub(:json_parser).as_null_object }
7
-
8
- it 'takes a JSON parser' do
9
- subject.json_parser.should be json_parser
10
- end
11
-
12
- it 'can be reset' do
13
- subject << RESPONSE_200
14
- subject.reset!
15
- expect { subject << RESPONSE_200 }.not_to raise_error Http::Parser::Error
16
- end
17
-
18
- it 'parses response body if the response status is 200' do
19
- json_parser.should_receive(:<<).with(BODY_200)
20
- subject << RESPONSE_200
21
- end
22
-
23
- it 'raises an error if the response status is above 200' do
24
- expect { subject << RESPONSE_401 }.to raise_error Nervion::HttpError
25
- end
26
- end