tweedle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rdoc_options ADDED
@@ -0,0 +1,16 @@
1
+ --- !ruby/object:RDoc::Options
2
+ encoding: UTF-8
3
+ static_path: []
4
+ rdoc_include:
5
+ - .
6
+ charset: UTF-8
7
+ exclude: ["test"]
8
+ hyperlink_all: false
9
+ line_numbers: true
10
+ main_page: README.rdoc
11
+ markup: tomdoc
12
+ show_hash: false
13
+ tab_width: 8
14
+ title: Tweedle
15
+ visibility: :protected
16
+ webcvs:
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ruby-head
6
+ - jruby-19mode
7
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem "rake"
5
+ end
6
+
7
+ group :test do
8
+ gem "minitest", "~> 2.12.1"
9
+ gem "mocha", "~> 0.11.2"
10
+ gem "simplecov", "~> 0.6.2"
11
+ gem "fakeweb", "~> 1.3.0"
12
+ end
13
+
14
+ # Specify your gem's dependencies in tweedle.gemspec
15
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Tobias Svensson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,137 @@
1
+ = Tweedle
2
+
3
+ Lightweight wrapper for the Twitter Streaming API.
4
+
5
+ ---
6
+
7
+ Tweedle is a lightweight wrapper for the
8
+ {Twitter Streaming API}[https://dev.twitter.com/docs/streaming-api],
9
+ written out of the need for a library that does not depend on
10
+ {EventMachine}[http://rubyeventmachine.com/].
11
+
12
+ The library currently only supports the regular
13
+ {Streaming API Methods}[https://dev.twitter.com/docs/streaming-api/methods].
14
+ {User Streams}[https://dev.twitter.com/docs/streaming-api/user-streams] and
15
+ {Site Streams}[https://dev.twitter.com/docs/streaming-api/site-streams] are
16
+ currently not implemented.
17
+
18
+ == Installation
19
+
20
+ The best way to install Tweedle is with RubyGems:
21
+
22
+ $ [sudo] gem install tweedle
23
+
24
+ Or add it to your Gemfile:
25
+
26
+ gem 'foo'
27
+
28
+ And then execute:
29
+
30
+ $ bundle install
31
+
32
+ If you're installing from source, you can use Bundler to pick up all the gems,
33
+ including those required for running the tests and creating coverage reports:
34
+
35
+ $ bundle install
36
+
37
+ Consult the online documentation for more information on
38
+ {Bundler}[http://gembundler.com/]
39
+
40
+ == Dependencies
41
+
42
+ The goal is to keep Tweedle's dependencies to a minimum. However, in
43
+ order to keep the source as simple as possible, it requires the
44
+ following gems:
45
+
46
+ * {OAuth}[http://github.com/pelle/oauth] to authenticate with Twitter
47
+ and sign the requests.
48
+ * {multi_json}[http://github.com/intridea/multi_json] to parse the
49
+ response bodies.
50
+
51
+ == Getting started
52
+
53
+ First, setup the library to use the desired OAuth credentials:
54
+
55
+ Tweedle.configure do |config|
56
+ config.consumer_key = "the_consumer_key"
57
+ config.consumer_secret = "the_consumer_secret"
58
+ config.oauth_token = "the_oauth_token"
59
+ config.oauth_secret = "the_oauth_secret"
60
+ end
61
+
62
+ Then, create a client:
63
+
64
+ client = Tweedle.new
65
+
66
+ Try things out by streaming Twitter's sample stream:
67
+
68
+ client.statuses.sample do |tweet|
69
+ next unless text = tweet[:text]
70
+ puts "#{tweet[:user][:screen_name]}: #{text}"
71
+ end
72
+
73
+ HTTP parameters are supported, too:
74
+
75
+ client.statuses.sample(stall_warnings: true, count: 1000) do |tweet|
76
+ next unless text = tweet[:text]
77
+ puts "#{tweet[:user][:screen_name]}: #{text}"
78
+ end
79
+
80
+ And the wrapper for the filter stream uses POST requsts, as
81
+ recommended by Twitter:
82
+
83
+ predicates = {
84
+ locations: [-122.75, 36.8, -121.75, 37.8, -74,40, -73,41],
85
+ track: ["ruby", "tweedle"]
86
+ }
87
+
88
+ client.statuses.filter(stall_warnings: true, predicates: predicates) do |tweet|
89
+ next unless text = tweet[:text]
90
+ puts "#{tweet[:user][:screen_name]}: #{text}"
91
+ end
92
+
93
+ The full API documentation is available
94
+ {online}[http://rdoc.info/github/tobiassvn/tweedle/master/frames].
95
+
96
+ == Contributing
97
+
98
+ If you'd like to contribute to Tweedle, start by forking the repo on GitHub:
99
+
100
+ {http://github.com/tobiassvn/tweedle}[http://github.com/tobiassvn/tweedle]
101
+
102
+ To get all of the dependencies, install the gem first. The best way to
103
+ getyour changes merged back into core is as follows:
104
+
105
+ * Clone down your fork.
106
+ * Create a thoughtfully named topic branch to contain your change.
107
+ * Hack away.
108
+ * Add tests and make sure everything still passes by running rake.
109
+ * If you are adding new functionality, document it in the README.
110
+ * If you add new attributes, classes, constants or methods, document
111
+ in the {TomDoc}[http://tomdoc.org/] format.
112
+ * Do not change the version number, I will do that on my end.
113
+ * If necessary, rebase your commits into logical chunks, without errors
114
+ * Push the branch up to GitHub
115
+ * Send a pull request to the tobiassvn/tweedle project.
116
+
117
+ == License
118
+
119
+ Copyright (c) 2012 Tobias Svensson.
120
+
121
+ Permission is hereby granted, free of charge, to any person obtaining a copy
122
+ of this software and associated documentation files (the "Software"), to deal
123
+ in the Software without restriction, including without limitation the rights
124
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
125
+ copies of the Software, and to permit persons to whom the Software is
126
+ furnished to do so, subject to the following conditions:
127
+
128
+ The above copyright notice and this permission notice shall be included in
129
+ all copies or substantial portions of the Software.
130
+
131
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
132
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
133
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
134
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
135
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
136
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
137
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "test/test_*.rb"
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,18 @@
1
+ require "tweedle"
2
+
3
+ Tweedle.configure do |config|
4
+ config.consumer_key = "the_consumer_key"
5
+ config.consumer_secret = "the_consumer_secret"
6
+ config.oauth_token = "the_oauth_token"
7
+ config.oauth_secret = "the_oauth_secret"
8
+ end
9
+
10
+ predicates = {
11
+ locations: [-122.75, 36.8, -121.75, 37.8, -74,40, -73,41],
12
+ track: ["ruby", "tweedle"]
13
+ }
14
+
15
+ Tweedle.new.statuses.filter(predicates: predicates) do |tweet|
16
+ next unless text = tweet[:text]
17
+ puts "#{tweet[:user][:screen_name]}: #{text}"
18
+ end
@@ -0,0 +1,13 @@
1
+ require "tweedle"
2
+
3
+ Tweedle.configure do |config|
4
+ config.consumer_key = "the_consumer_key"
5
+ config.consumer_secret = "the_consumer_secret"
6
+ config.oauth_token = "the_oauth_token"
7
+ config.oauth_secret = "the_oauth_secret"
8
+ end
9
+
10
+ Tweedle.new.statuses.sample do |tweet|
11
+ next unless text = tweet[:text]
12
+ puts "#{tweet[:user][:screen_name]}: #{text}"
13
+ end
@@ -0,0 +1,268 @@
1
+ module Tweedle
2
+ # Public: The Tweedle::Client class wraps methods for accessing
3
+ # sections of the Twitter streaming API and handles all client ->
4
+ # server requests.
5
+ class Client
6
+ # Public: The configuration used by the Tweedle::Client instance.
7
+ attr_reader :config
8
+
9
+ # Initializes a new Tweedle::Client.
10
+ #
11
+ # config - Options object for the Tweedle client. By default uses
12
+ # the global Tweedle configuarion (default: Tweedle.config).
13
+ #
14
+ # Examples
15
+ #
16
+ # Tweedle::Client.new
17
+ # # => Tweedle::Client
18
+ #
19
+ # Tweedle::Client.new(config_object)
20
+ # # => Tweedle::Client
21
+ #
22
+ # Returns a Tweedle::Client instance.
23
+ def initialize(config = Tweedle.config)
24
+ @config = config
25
+ end
26
+
27
+ # Returns a new Tweedle::Statuses instance associated with the
28
+ # client.
29
+ #
30
+ # Examples
31
+ #
32
+ # client = Tweedle.new
33
+ # client.statuses
34
+ # # => Tweedle::Statuses
35
+ #
36
+ # Returns a Tweedle::Statuses instance.
37
+ def statuses
38
+ Tweedle::Statuses.new(self)
39
+ end
40
+
41
+ # Internal: Sends a GET request to the given stream.
42
+ #
43
+ # uri - A String containing the request URI.
44
+ # block - Optional block to yield the response body to.
45
+ # params - Optional request parameters (default: empty Hash)
46
+ #
47
+ # Examples
48
+ #
49
+ # get(URI.parse("http://www.google.com/") do |body|
50
+ # puts body
51
+ # end
52
+ #
53
+ # Returns nothing.
54
+ # Raises Tweedle::ConnectionError if the server response is not an
55
+ # Net::HTTPSuccess.
56
+ def get(uri, params = {}, &block)
57
+ uri = build_uri(uri, params)
58
+ http = build_http(uri)
59
+ request = build_get_request(uri, http, params)
60
+
61
+ begin
62
+ http.request(request) { |response| handle_response(response, &block) }
63
+ rescue *[Timeout::Error, Errno::ECONNRESET, EOFError]
64
+ retry # reconnect
65
+ ensure
66
+ http.finish
67
+ end
68
+ end
69
+
70
+ # Internal: Sends a POST request to the given stream.
71
+ #
72
+ # uri - A String containing the request URI.
73
+ # block - Optional block to yield the response body to.
74
+ # post_data - Object responding to #to_s containing the data for
75
+ # the POST request
76
+ # params - Optional request parameters (default: empty Hash)
77
+ #
78
+ # Examples
79
+ #
80
+ # post(URI.parse("http://www.google.com/", "follow=12") do |body|
81
+ # puts body
82
+ # end
83
+ #
84
+ # Returns nothing.
85
+ # Raises Tweedle::ConnectionError if the server response is not an
86
+ # Net::HTTPSuccess.
87
+ def post(uri, post_data, params = {}, &block)
88
+ uri = build_uri(uri, params)
89
+ http = build_http(uri)
90
+ request = build_post_request(uri, http, post_data, params)
91
+
92
+ begin
93
+ http.request(request) { |response| handle_response(response, &block) }
94
+ rescue *[Timeout::Error, Errno::ECONNRESET, EOFError]
95
+ retry # reconnect
96
+ ensure
97
+ http.finish
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ # Private: Reads the streaming body of a given HTTP response and
104
+ # yields a parsed JSON object to the given block for each received chunk.
105
+ #
106
+ # response - A Net::HTTPResponse object.
107
+ #
108
+ # Examples
109
+ #
110
+ # handle_response(response_object) do |body|
111
+ # puts body
112
+ # end
113
+ #
114
+ # Returns nothing.
115
+ # Raises Tweedle::ConnectionError if the server response is not an
116
+ # Net::HTTPSuccess.
117
+ def handle_response(response)
118
+ unless response.kind_of?(Net::HTTPSuccess)
119
+ msg = "#{response.code}: #{response.message}\n#{response.body}"
120
+ raise Tweedle::ConnectionError.new(msg)
121
+ end
122
+
123
+ response.read_body do |body|
124
+ begin
125
+ yield MultiJson.load(body, symbolize_keys: true) if block_given?
126
+ rescue
127
+ # Wrap this to not die on keep alive data sent by the
128
+ # Streaming API.
129
+ end
130
+ end
131
+ end
132
+
133
+ # Private: Returns the OAuth consumer object.
134
+ #
135
+ # Examples
136
+ #
137
+ # consumer
138
+ # # => Oauth::Consumer
139
+ #
140
+ # Returns a OAuth::Consumer instance.
141
+ def consumer
142
+ @consumer ||= OAuth::Consumer.new(@config.consumer_key,
143
+ @config.consumer_secret)
144
+ end
145
+
146
+ # Private: Returns the OAuth access token.
147
+ #
148
+ # Examples
149
+ #
150
+ # access_token
151
+ # # => Oauth::Token
152
+ #
153
+ # Returns a OAuth::Token instance.
154
+ def access_token
155
+ @access_token ||= OAuth::Token.new(@config.oauth_token,
156
+ @config.oauth_secret)
157
+ end
158
+
159
+ # Private: Builds a new HTTP client object with SSL enabled for the given URI.
160
+ #
161
+ # uri - A URI instance.
162
+ #
163
+ # Examples
164
+ #
165
+ # build_http URI.parse("http://www.google.com/")
166
+ # # => Net::HTTP
167
+ #
168
+ # Returns a Net::HTTP instance.
169
+ def build_http(uri)
170
+ Net::HTTP.new(uri.host, uri.port).tap do |http|
171
+ http.use_ssl = true
172
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
173
+ http.start
174
+ end
175
+ end
176
+
177
+ # Private: Builds a Net::HTTP::Get request objext for the given
178
+ # URI and performs an OAuth sign using the given Net::HTTP instance.
179
+ #
180
+ # uri - A String containing the request URI.
181
+ # http - A Net:HTTP instance.
182
+ # params - Optional request parameters (default: empty Hash).
183
+ #
184
+ # Examples
185
+ #
186
+ # uri = URI.parse("http://www.google.com/")
187
+ # build_get_request(uri, build_http(uri))
188
+ # # => Net::HTTP::Get
189
+ #
190
+ # Returns a Net::HTTP::Get instance.
191
+ def build_get_request(uri, http, params = {})
192
+ Net::HTTP::Get.new(uri.request_uri).tap do |request|
193
+ request.oauth!(http, consumer, access_token)
194
+ end
195
+ end
196
+
197
+ # Private: Builds a Net::HTTP::Post request objext for the given
198
+ # URI and performs an OAuth sign using the given Net::HTTP instance.
199
+ #
200
+ # uri - A String containing the request URI.
201
+ # http - A Net:HTTP instance.
202
+ # post_data - Object containing the POST data (converted using #encode_params)
203
+ # params - Optional request parameters (default: empty Hash).
204
+ #
205
+ # Examples
206
+ #
207
+ # uri = URI.parse("http://www.google.com/")
208
+ # build_post_request(uri, "follow=12",build_http(uri))
209
+ # # => Net::HTTP::Post
210
+ #
211
+ # Returns a Net::HTTP::Post instance.
212
+ def build_post_request(uri, http, post_data, params = {})
213
+ Net::HTTP::Post.new(uri.request_uri).tap do |request|
214
+ request["content-type"] = "application/x-www-form-urlencoded"
215
+ request.body = encode_params(post_data)
216
+ request.oauth!(http, consumer, access_token)
217
+ end
218
+ end
219
+
220
+ # Private: Builds a URI object for a given URI String and a
221
+ # parameter hash.
222
+ #
223
+ # uri - String containing the request URI.
224
+ # params - Optional request parameters to encode.
225
+ #
226
+ # Examples
227
+ #
228
+ # build_uri("http://www.google.com/search", q: "test search")
229
+ # # => #<URI::HTTP URL:http://www.google.com/search?q=test+search>
230
+ #
231
+ # Returns a URI instance.
232
+ def build_uri(uri, params)
233
+ full_path = params.empty? ? uri : "#{uri}?#{encode_params(params)}"
234
+ URI.parse(full_path)
235
+ end
236
+
237
+ # Private: Encodes a parameter hash.
238
+ #
239
+ # params - The parameter hash to encode.
240
+ #
241
+ # Examples
242
+ #
243
+ # encode_params(foo: "bar")
244
+ # # => "foo=bar"
245
+ #
246
+ # encode_params(foo: "bar", baz: 42)
247
+ # # => "foo=bar&baz=42"
248
+ #
249
+ # encode_params(follow: [1, 2, 3], baz: 42)
250
+ # # => "follow=1,2,3&baz=42"
251
+ #
252
+ # encode_params(q: "test search")
253
+ # # => "q=test+search"
254
+ #
255
+ # Returns a String.
256
+ def encode_params(params)
257
+ params.map do |key, value|
258
+ escaped = if value.kind_of?(Array)
259
+ value.map { |val| CGI::escape(val.to_s) }.join(",")
260
+ else
261
+ CGI::escape(value.to_s)
262
+ end
263
+ "#{key}=#{escaped}"
264
+ end.join("&")
265
+ end
266
+ end
267
+ end
268
+
@@ -0,0 +1,6 @@
1
+ module Tweedle
2
+ # Public: A ConnectionError is raised by all Tweedle methods if the
3
+ # server does not response with an HTTP success.
4
+ class ConnectionError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,160 @@
1
+ module Tweedle
2
+ # Public: Wraps all generic {Twitter Streaming API methods}[https://dev.twitter.com/docs/streaming-api/methods].
3
+ class Statuses
4
+ # Public: The Twitter Stream server used by Tweedle::Statuses.
5
+ SERVER = "https://stream.twitter.com"
6
+
7
+ # Public: The Tweedle::Client used by the Tweedle::Statuses instance.
8
+ attr_reader :client
9
+
10
+ # Initializes a new Tweedle::Statuses instance.
11
+ #
12
+ # client - The Tweedle::Client used by the instance.
13
+ #
14
+ # Examples
15
+ #
16
+ # Tweedle::Statuses.new
17
+ # # => Tweedle::Statuses
18
+ #
19
+ # Tweedle::Statuses.new(client_instance)
20
+ # # => Tweedle::Statuses
21
+ #
22
+ # Returns a Tweedle::Statuses instance.
23
+ def initialize(client)
24
+ @client = client
25
+ end
26
+
27
+ # Returns all statuses containing http: and https:. The links
28
+ # stream is not a generally available resource.
29
+ #
30
+ # params - Hash containing request parameters (default: empty Hash).
31
+ #
32
+ # Examples
33
+ #
34
+ # links(stall_warnings: true) do |body|
35
+ # next unless text = tweet[:text]
36
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
37
+ # end
38
+ #
39
+ # Returns nothing.
40
+ # Raises Tweedle::ConnectionError if the server response is not an
41
+ # Net::HTTPSuccess.
42
+ def links(params = {})
43
+ get("/1/statuses/links.json", params) do |body|
44
+ yield body if block_given?
45
+ end
46
+ end
47
+
48
+ # Returns a random sample of all public statuses.
49
+ #
50
+ # params - Hash containing request parameters (default: empty Hash).
51
+ #
52
+ # Examples
53
+ #
54
+ # sample(stall_warnings: true) do |body|
55
+ # next unless text = tweet[:text]
56
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
57
+ # end
58
+ #
59
+ # Returns nothing.
60
+ # Raises Tweedle::ConnectionError if the server response is not an
61
+ # Net::HTTPSuccess.
62
+ def sample(params = {})
63
+ get("/1/statuses/sample.json", params) do |body|
64
+ yield body if block_given?
65
+ end
66
+ end
67
+
68
+ # Returns all public statuses. The Firehose is not a generally
69
+ # available resource.
70
+ #
71
+ # params - Hash containing request parameters (default: empty Hash).
72
+ #
73
+ # Examples
74
+ #
75
+ # firehose(stall_warnings: true) do |body|
76
+ # next unless text = tweet[:text]
77
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
78
+ # end
79
+ #
80
+ # Returns nothing.
81
+ # Raises Tweedle::ConnectionError if the server response is not an
82
+ # Net::HTTPSuccess.
83
+ def firehose(params = {})
84
+ get("/1/statuses/firehose.json", params) do |body|
85
+ yield body if block_given?
86
+ end
87
+ end
88
+
89
+ # Returns all retweets. The retweet stream is not a generally
90
+ # available resource.
91
+ #
92
+ # params - Hash containing request parameters (default: empty Hash).
93
+ #
94
+ # Examples
95
+ #
96
+ # retweet(stall_warnings: true) do |body|
97
+ # next unless text = tweet[:text]
98
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
99
+ # end
100
+ #
101
+ # Returns nothing.
102
+ # Raises Tweedle::ConnectionError if the server response is not an
103
+ # Net::HTTPSuccess.
104
+ def retweet(params = {})
105
+ get("/1/statuses/retweet.json", params) do |body|
106
+ yield body if block_given?
107
+ end
108
+ end
109
+
110
+ # Returns public statuses that match one or more filter
111
+ # predicates. At least one predicate parameter, follow,
112
+ # locations, or track must be specified. Multiple parameters
113
+ # may be specified.
114
+ #
115
+ # The default access level allows up to 400 track keywords, 5,000
116
+ # follow userids and 25 0.1-360 degree location boxes.
117
+ #
118
+ # This method uses a POST request to submit the filter predicates
119
+ # to the Twitter Streaming API.
120
+ #
121
+ # params - Hash containing the request parameters and filter predicates.
122
+ #
123
+ # Examples:
124
+ #
125
+ # predicates = {
126
+ # locations: [-122.75, 36.8, -121.75, 37.8, -74,40, -73,41],
127
+ # track: ["ruby", "tweedle"]
128
+ # }
129
+ #
130
+ # filter(predicates: predicates) do |body|
131
+ # next unless text = tweet[:text]
132
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
133
+ # end
134
+ #
135
+ # filter(predicates: predicates, count: 100, stall_warnings: true) do |body|
136
+ # next unless text = tweet[:text]
137
+ # puts "#{tweet[:user][:screen_name]}: #{text}"
138
+ # end
139
+ #
140
+ # Returns nothing.
141
+ # Raises Tweedle::ConnectionError if the server response is not an
142
+ # Net::HTTPSuccess.
143
+ def filter(params)
144
+ predicates = params.delete(:predicates)
145
+ post("/1/statuses/filter.json", predicates, params) do |body|
146
+ yield body if block_given?
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def post(path, post_data, params, &block)
153
+ @client.post(SERVER + path, post_data, params, &block)
154
+ end
155
+
156
+ def get(path, params, &block)
157
+ @client.get(SERVER + path, params, &block)
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,4 @@
1
+ module Tweedle
2
+ # Public: The current Tweedle version.
3
+ VERSION = "0.1.0"
4
+ end
data/lib/tweedle.rb ADDED
@@ -0,0 +1,58 @@
1
+ # gems
2
+ require "multi_json"
3
+ require "oauth"
4
+
5
+ # stdlib
6
+ require "ostruct"
7
+ require "cgi"
8
+
9
+ # internal
10
+ require "tweedle/version"
11
+ require "tweedle/client"
12
+ require "tweedle/statuses"
13
+ require "tweedle/errors"
14
+
15
+ # Public: The Tweedle namespace.
16
+ module Tweedle
17
+ class << self
18
+ # Public: Holds the global Tweedle configuration OpenStruct object.
19
+ attr_accessor :config
20
+
21
+ # Yields the global configuration OpenStruct object to the passed
22
+ # block. Will assign a new OpenStruct object if none has been set.
23
+ #
24
+ # Examples
25
+ #
26
+ # Tweedle.configure do |config|
27
+ # config.consumer_key = "the_consumer_key"
28
+ # config.consumer_secret = "the_consumer_secret"
29
+ # config.oauth_token = "the_oauth_token"
30
+ # config.oauth_secret = "the_oauth_secret"
31
+ # end
32
+ #
33
+ # Returns nothing.
34
+ def configure
35
+ @config ||= OpenStruct.new
36
+ yield @config if block_given?
37
+ end
38
+
39
+ # Initializes a new Tweedle::Client.
40
+ #
41
+ # config - Options object for the Tweedle client. By default uses
42
+ # the global Tweedle configuarion (default: Tweedle.config).
43
+ #
44
+ # Examples
45
+ #
46
+ # Tweedle.new
47
+ # # => Tweedle::Client
48
+ #
49
+ # Tweedle.new(config_object)
50
+ # # => Tweedle::Client
51
+ #
52
+ # Returns a Tweedle::Client instance.
53
+ def new(config = Tweedle.config)
54
+ Tweedle::Client.new(config)
55
+ end
56
+ end
57
+ end
58
+
data/test/helper.rb ADDED
@@ -0,0 +1,19 @@
1
+ if ENV['COVERAGE'] && (RUBY_ENGINE == "ruby")
2
+ require 'simplecov'
3
+ SimpleCov.start { add_filter "/test/" }
4
+ end
5
+
6
+ require 'minitest/autorun'
7
+ require "mocha"
8
+ require "fakeweb"
9
+ require "tweedle"
10
+
11
+ FakeWeb.allow_net_connect = false
12
+
13
+ Tweedle.configure do |config|
14
+ config.consumer_key = "abc"
15
+ config.consumer_secret = "def"
16
+ config.oauth_token = "ghi"
17
+ config.oauth_secret = "jkl"
18
+ end
19
+
@@ -0,0 +1,136 @@
1
+ require_relative "helper"
2
+
3
+ class TestClient < MiniTest::Unit::TestCase
4
+ def setup
5
+ @uri = "https://www.google.com"
6
+
7
+ FakeWeb.register_uri :get,
8
+ @uri,
9
+ body: "[ \"ok\" ]"
10
+
11
+ FakeWeb.register_uri :get,
12
+ @uri + "?foo=bar",
13
+ body: "[ \"foo=bar\" ]"
14
+
15
+ FakeWeb.register_uri :get,
16
+ @uri + "?foo=bar,baz",
17
+ body: "[ \"foo=bar,baz\" ]"
18
+
19
+ FakeWeb.register_uri :get,
20
+ @uri + "?foo=bar&baz=42",
21
+ body: "[ \"foo=bar&baz=42\" ]"
22
+
23
+ FakeWeb.register_uri :post,
24
+ @uri,
25
+ body: "[ \"post\" ]"
26
+
27
+ FakeWeb.register_uri :post,
28
+ @uri + "?bar=baz",
29
+ body: "[ \"post bar=baz\" ]"
30
+
31
+ FakeWeb.register_uri :post,
32
+ @uri + "?bar=baz,42",
33
+ body: "[ \"post bar=baz,42\" ]"
34
+
35
+ FakeWeb.register_uri :post,
36
+ @uri + "?bar=baz&ok=42",
37
+ body: "[ \"post bar=baz&ok=42\" ]"
38
+
39
+ @invalid = "https://www.invalid.com"
40
+
41
+ FakeWeb.register_uri :get,
42
+ @invalid,
43
+ body: "[ \"error\" ]",
44
+ status: ["404", "Not Found"]
45
+
46
+ FakeWeb.register_uri :post,
47
+ @invalid,
48
+ body: "[ \"error\" ]",
49
+ status: ["404", "Not Found"]
50
+ end
51
+
52
+ def teardown
53
+ FakeWeb.clean_registry
54
+ end
55
+
56
+ def test_config
57
+ assert_equal :foo, Tweedle::Client.new(:foo).config
58
+ end
59
+
60
+ def test_default_config
61
+ assert_equal Tweedle.config, Tweedle::Client.new.config
62
+ end
63
+
64
+ def test_statuses
65
+ client = Tweedle.new
66
+ statuses = client.statuses
67
+ assert_instance_of Tweedle::Statuses, statuses
68
+ assert_equal client, statuses.client
69
+ end
70
+
71
+ def test_get
72
+ Tweedle.new.get(@uri) { |body| assert_equal ["ok"], body }
73
+ end
74
+
75
+ def test_post
76
+ Tweedle.new.post(@uri, foo: "bar") do |body|
77
+ assert_equal ["post"], body
78
+ end
79
+ assert_equal "foo=bar", FakeWeb.last_request.body
80
+
81
+ Tweedle.new.post(@uri, foo: ["bar", "baz"]) do |body|
82
+ assert_equal ["post"], body
83
+ end
84
+ assert_equal "foo=bar,baz", FakeWeb.last_request.body
85
+
86
+ Tweedle.new.post(@uri, foo: "bar", baz: 42) do |body|
87
+ assert_equal ["post"], body
88
+ end
89
+ assert_equal "foo=bar&baz=42", FakeWeb.last_request.body
90
+ end
91
+
92
+ def test_get_with_params
93
+ Tweedle.new.get(@uri, foo: "bar") do |body|
94
+ assert_equal ["foo=bar"], body
95
+ end
96
+
97
+ Tweedle.new.get(@uri, foo: ["bar", "baz"]) do |body|
98
+ assert_equal ["foo=bar,baz"], body
99
+ end
100
+
101
+ Tweedle.new.get(@uri, foo: "bar", baz: 42) do |body|
102
+ assert_equal ["foo=bar&baz=42"], body
103
+ end
104
+ end
105
+
106
+
107
+ def test_post_with_params
108
+ Tweedle.new.post(@uri, { foo: "bar" }, { bar: "baz" }) do |body|
109
+ assert_equal ["post bar=baz"], body
110
+ end
111
+ assert_equal "foo=bar", FakeWeb.last_request.body
112
+
113
+ Tweedle.new.post(@uri, { foo: "bar" }, { bar: ["baz", 42] }) do |body|
114
+ assert_equal ["post bar=baz,42"], body
115
+ end
116
+ assert_equal "foo=bar", FakeWeb.last_request.body
117
+
118
+ Tweedle.new.post(@uri, { foo: "bar" }, { bar: "baz", ok: 42 }) do |body|
119
+ assert_equal ["post bar=baz&ok=42"], body
120
+ end
121
+ assert_equal "foo=bar", FakeWeb.last_request.body
122
+ end
123
+
124
+ def test_get_with_invalid_response
125
+ assert_raises(Tweedle::ConnectionError) do
126
+ Tweedle.new.get(@invalid)
127
+ end
128
+ end
129
+
130
+ def test_post_with_invalid_response
131
+ assert_raises(Tweedle::ConnectionError) do
132
+ Tweedle.new.post(@invalid, foo: "bar")
133
+ end
134
+ end
135
+ end
136
+
@@ -0,0 +1,147 @@
1
+ require_relative "helper"
2
+
3
+ class TestStatuses < MiniTest::Unit::TestCase
4
+ def statuses
5
+ Tweedle.new.statuses
6
+ end
7
+
8
+ def setup
9
+ %w(firehose retweet links sample).each do |req|
10
+ FakeWeb.register_uri :get,
11
+ Tweedle::Statuses::SERVER + "/1/statuses/#{req}.json",
12
+ body: "[\"ok\"]"
13
+
14
+ FakeWeb.register_uri :get,
15
+ Tweedle::Statuses::SERVER + "/1/statuses/#{req}.json?count=100",
16
+ body: "[\"single\"]"
17
+
18
+ FakeWeb.register_uri :get,
19
+ Tweedle::Statuses::SERVER + "/1/statuses/#{req}.json?count=100,200",
20
+ body: "[\"array\"]"
21
+
22
+ FakeWeb.register_uri :get,
23
+ Tweedle::Statuses::SERVER + "/1/statuses/#{req}.json?count=1&foo=true",
24
+ body: "[\"multi\"]"
25
+ end
26
+
27
+ FakeWeb.register_uri :post,
28
+ Tweedle::Statuses::SERVER + "/1/statuses/filter.json",
29
+ body: "[\"post\"]"
30
+
31
+ FakeWeb.register_uri :post,
32
+ Tweedle::Statuses::SERVER + "/1/statuses/filter.json?foo=42,43&bar=true",
33
+ body: "[\"post with params\"]"
34
+ end
35
+
36
+ def teardown
37
+ FakeWeb.clean_registry
38
+ end
39
+
40
+ def test_filter
41
+ predicates = {
42
+ locations: [-122.75, 36.8, -121.75, 37.8],
43
+ track: ["ruby", "tweedle"]
44
+ }
45
+
46
+ statuses.filter(predicates: predicates) do |body|
47
+ assert_equal ["post"], body
48
+ end
49
+
50
+ assert_equal "locations=-122.75,36.8,-121.75,37.8&track=ruby,tweedle",
51
+ FakeWeb.last_request.body
52
+ end
53
+
54
+ def test_filter_with_params
55
+ predicates = {
56
+ locations: [-122.75, 36.8, -121.75, 37.8],
57
+ track: ["ruby", "tweedle"]
58
+ }
59
+
60
+ statuses.filter(predicates: predicates, foo: [42, 43], bar: true) do |body|
61
+ assert_equal ["post with params"], body
62
+ end
63
+
64
+ assert_equal "locations=-122.75,36.8,-121.75,37.8&track=ruby,tweedle",
65
+ FakeWeb.last_request.body
66
+ end
67
+
68
+ def test_firehose
69
+ statuses.firehose do |body|
70
+ assert_equal ["ok"], body
71
+ end
72
+ end
73
+
74
+ def test_firehose_with_params
75
+ statuses.firehose(count: 100) do |body|
76
+ assert_equal ["single"], body
77
+ end
78
+
79
+ statuses.firehose(count: [100, 200]) do |body|
80
+ assert_equal ["array"], body
81
+ end
82
+
83
+ statuses.firehose(count: 1, foo: true) do |body|
84
+ assert_equal ["multi"], body
85
+ end
86
+ end
87
+
88
+ def test_retweet
89
+ statuses.retweet do |body|
90
+ assert_equal ["ok"], body
91
+ end
92
+ end
93
+
94
+ def test_retweet_with_params
95
+ statuses.retweet(count: 100) do |body|
96
+ assert_equal ["single"], body
97
+ end
98
+
99
+ statuses.retweet(count: [100, 200]) do |body|
100
+ assert_equal ["array"], body
101
+ end
102
+
103
+ statuses.retweet(count: 1, foo: true) do |body|
104
+ assert_equal ["multi"], body
105
+ end
106
+ end
107
+
108
+ def test_links
109
+ statuses.links do |body|
110
+ assert_equal ["ok"], body
111
+ end
112
+ end
113
+
114
+ def test_links_with_params
115
+ statuses.links(count: 100) do |body|
116
+ assert_equal ["single"], body
117
+ end
118
+
119
+ statuses.links(count: [100, 200]) do |body|
120
+ assert_equal ["array"], body
121
+ end
122
+
123
+ statuses.links(count: 1, foo: true) do |body|
124
+ assert_equal ["multi"], body
125
+ end
126
+ end
127
+
128
+ def test_sample
129
+ statuses.sample do |body|
130
+ assert_equal ["ok"], body
131
+ end
132
+ end
133
+
134
+ def test_sample_with_params
135
+ statuses.sample(count: 100) do |body|
136
+ assert_equal ["single"], body
137
+ end
138
+
139
+ statuses.sample(count: [100, 200]) do |body|
140
+ assert_equal ["array"], body
141
+ end
142
+
143
+ statuses.sample(count: 1, foo: true) do |body|
144
+ assert_equal ["multi"], body
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "helper"
2
+
3
+ class TestTweedle < MiniTest::Unit::TestCase
4
+ def setup
5
+ @old_config = Tweedle.config
6
+ end
7
+
8
+ def teardown
9
+ Tweedle.config = @old_config
10
+ end
11
+
12
+ def test_new
13
+ assert_instance_of Tweedle::Client, Tweedle.new
14
+ end
15
+
16
+ def test_new_passes_arguments
17
+ Tweedle::Client.expects(:new).with(:foo)
18
+ Tweedle.new(:foo)
19
+ end
20
+
21
+ def test_configure
22
+ Tweedle.configure { |config| config.foo = :bar }
23
+ assert_equal :bar, Tweedle.config.foo
24
+ end
25
+ end
26
+
data/tweedle.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/tweedle/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Tobias Svensson"]
6
+ gem.email = ["tob@tobiassvensson.co.uk"]
7
+ gem.description = %q{Lightweight wrapper for the Twitter Streaming API}
8
+ gem.summary = gem.description
9
+ gem.homepage = "http://github.com/tobiassvn/tweedle"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "tweedle"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Tweedle::VERSION
17
+
18
+ gem.add_dependency "multi_json", "~> 1.3.2"
19
+ gem.add_dependency "oauth", "~> 0.4.6"
20
+ gem.add_dependency "jruby-openssl", "~> 0.7.6.1" if RUBY_PLATFORM =~ /java/
21
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tweedle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tobias Svensson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: multi_json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.3.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.3.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: oauth
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.4.6
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.4.6
46
+ description: Lightweight wrapper for the Twitter Streaming API
47
+ email:
48
+ - tob@tobiassvensson.co.uk
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rdoc_options
55
+ - .travis.yml
56
+ - Gemfile
57
+ - LICENSE
58
+ - README.rdoc
59
+ - Rakefile
60
+ - examples/statuses.filter.rb
61
+ - examples/statuses.sample.rb
62
+ - lib/tweedle.rb
63
+ - lib/tweedle/client.rb
64
+ - lib/tweedle/errors.rb
65
+ - lib/tweedle/statuses.rb
66
+ - lib/tweedle/version.rb
67
+ - test/helper.rb
68
+ - test/test_client.rb
69
+ - test/test_statuses.rb
70
+ - test/test_tweedle.rb
71
+ - tweedle.gemspec
72
+ homepage: http://github.com/tobiassvn/tweedle
73
+ licenses: []
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ segments:
85
+ - 0
86
+ hash: 2043315067158047274
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ segments:
94
+ - 0
95
+ hash: 2043315067158047274
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.23
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Lightweight wrapper for the Twitter Streaming API
102
+ test_files:
103
+ - test/helper.rb
104
+ - test/test_client.rb
105
+ - test/test_statuses.rb
106
+ - test/test_tweedle.rb