weeter 0.15.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 13c5cd768b0f83d96e1a67b87a505e3e99ae4b18
4
+ data.tar.gz: 47f1550576846acc61ad07c1323702e4b1ad60cd
5
+ SHA512:
6
+ metadata.gz: cf47012d1be61abcfc9a8800d8b46229f6c62a967515dfa1477891e86243cf31329c1e05e554612441c25320d2e18070d4e4d39536ca8e17c85a5db7e7324761
7
+ data.tar.gz: 959ae16e71443ff6b561240f2b8432ec3f291b472a272f7373fffc2f663dd15e635671972efedf1899dcfb4e03dbf8a7cb7fa32c96001351cbd43c530c1a7ba8
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.6
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  bundler_args: --without debug
3
3
  rvm:
4
- - 1.9.3
4
+ - 2.1.8
5
5
  script: bundle exec rspec spec
@@ -4,8 +4,11 @@ require 'hashie'
4
4
  module Weeter
5
5
  class Configuration
6
6
  class ClientAppConfig < Hashie::Mash
7
- def subscription_updates_port
8
- self['subscription_updates_port'] || 7337
7
+ DEFAULT_SUBSCRIPTIONS_UPDATE_PORT = 7337
8
+ InvalidConfiguration = Class.new(StandardError)
9
+
10
+ def verify_redis_namespace_config
11
+ !!self.redis_namespace || raise(InvalidConfiguration, 'missing `redis-namespace` config')
9
12
  end
10
13
  end
11
14
  end
@@ -1,5 +1,5 @@
1
1
  require 'singleton'
2
- require 'active_support/core_ext/numeric'
2
+ require 'active_support/core_ext/numeric/time'
3
3
 
4
4
  module Weeter
5
5
  class Configuration
@@ -8,7 +8,7 @@ module Weeter
8
8
  def self.get(config, url, params = {})
9
9
  request(config, :get, url, params)
10
10
  end
11
-
11
+
12
12
  def self.put(config, url, params = {})
13
13
  request(config, :put, url, params)
14
14
  end
@@ -16,11 +16,11 @@ module Weeter
16
16
  def self.post(config, url, params = {})
17
17
  request(config, :post, url, params)
18
18
  end
19
-
19
+
20
20
  def self.delete(config, url, params = {})
21
21
  request(config, :delete, url, params)
22
22
  end
23
-
23
+
24
24
  def self.request(config, method, url, params = {})
25
25
  if method == :post
26
26
  request_options = {:body => params}
@@ -32,9 +32,9 @@ module Weeter
32
32
  end
33
33
 
34
34
  def self.oauth_header(config, uri, params, http_method)
35
- ::SimpleOauth::Header.new(http_method, uri, params, config.oauth).to_s
35
+ ::SimpleOAuth::Header.new(http_method, uri, params, config.oauth).to_s
36
36
  end
37
37
  end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -9,19 +9,19 @@ module Weeter
9
9
  end
10
10
 
11
11
  def publish_tweet(tweet_item)
12
- resque_job = %Q|{"class":"WeeterPublishTweetJob","args":[#{tweet_item.to_json}]}|
12
+ resque_job = %Q|{"class":"WeeterPublishTweetJob","args":[#{tweet_item.to_json}],"jid": "#{SecureRandom.hex(12)}"}|
13
13
  Weeter.logger.info("Publishing tweet #{tweet_item['id']} from user #{tweet_item['user']['id_str']}: #{tweet_item['text']}")
14
14
  enqueue(resque_job)
15
15
  end
16
16
 
17
17
  def delete_tweet(tweet_item)
18
- resque_job = %Q|{"class":"WeeterDeleteTweetJob","args":[#{tweet_item.to_json}]}|
18
+ resque_job = %Q|{"class":"WeeterDeleteTweetJob","args":[#{tweet_item.to_json}],"jid": "#{SecureRandom.hex(12)}"}|
19
19
  Weeter.logger.info("Deleting tweet #{tweet_item['id']} for user #{tweet_item['user']['id_str']}")
20
20
  enqueue(resque_job)
21
21
  end
22
22
 
23
23
  def notify_missed_tweets(tweet_item)
24
- resque_job = %Q|{"class":"WeeterMissedTweetsJob","args":[#{tweet_item.to_json}]}|
24
+ resque_job = %Q|{"class":"WeeterMissedTweetsJob","args":[#{tweet_item.to_json}],"jid": "#{SecureRandom.hex(12)}"}|
25
25
  Weeter.logger.info("Notifying of missed tweets (#{tweet_item.missed_tweets_count}).")
26
26
  enqueue(resque_job)
27
27
  end
@@ -29,7 +29,7 @@ module Weeter
29
29
  def notify_rate_limiting_initiated(tweet_item, limited_keys)
30
30
  payload = tweet_item.to_hash.merge(:limited_keys => limited_keys)
31
31
  payload_json = MultiJson.encode(payload)
32
- resque_job = %Q|{"class":"WeeterRateLimitingInitiatedJob","args":[#{payload_json}]}|
32
+ resque_job = %Q|{"class":"WeeterRateLimitingInitiatedJob","args":[#{payload_json}],"jid": "#{SecureRandom.hex(12)}"}|
33
33
  Weeter.logger.info("Initiated rate limiting with tweet: #{payload_json}")
34
34
  enqueue(resque_job)
35
35
  end
@@ -37,7 +37,10 @@ module Weeter
37
37
  protected
38
38
 
39
39
  def redis
40
- @redis ||= create_redis_client
40
+ @redis ||= begin
41
+ @config.verify_redis_namespace_config
42
+ create_redis_client
43
+ end
41
44
  end
42
45
 
43
46
  def enqueue(job)
@@ -45,7 +48,7 @@ module Weeter
45
48
  end
46
49
 
47
50
  def queue_key
48
- "resque:queue:#{@config.queue}"
51
+ "#{@config.redis_namespace}:#{@config.queue}"
49
52
  end
50
53
  end
51
54
  end
@@ -23,11 +23,12 @@ module Weeter
23
23
  end
24
24
 
25
25
  def listen_for_filter_update(tweet_consumer)
26
- EM.start_server('localhost', @config.subscription_updates_port, UpdateServer) do |conn|
26
+ port = @config.subscription_updates_port || Weeter::Configuration::ClientAppConfig::DEFAULT_SUBSCRIPTIONS_UPDATE_PORT
27
+ EM.start_server('localhost', port, UpdateServer) do |conn|
27
28
  conn.tweet_consumer = tweet_consumer
28
29
  end
29
30
  end
30
-
31
+
31
32
  class UpdateServer < EM::Connection
32
33
  include EM::HttpServer
33
34
  attr_accessor :tweet_consumer
@@ -42,4 +43,4 @@ module Weeter
42
43
  end
43
44
  end
44
45
  end
45
- end
46
+ end
@@ -23,8 +23,8 @@ module Weeter
23
23
  end
24
24
 
25
25
  def listen_for_filter_update(tweet_consumer)
26
- pub_sub_redis.subscribe(@config.subscriptions_changed_channel)
27
- pub_sub_redis.on(:message) do |channel, message|
26
+ channel = @config.subscriptions_changed_channel
27
+ pub_sub_redis.subscribe(channel) do |message|
28
28
  Weeter.logger.info [:message, channel, message]
29
29
  Weeter.logger.info("Retrieving updated filters from redis")
30
30
  get_initial_filters do |filter_params|
@@ -41,7 +41,7 @@ module Weeter
41
41
  end
42
42
 
43
43
  def pub_sub_redis
44
- @pub_sub_redis ||= create_redis_client
44
+ @pub_sub_redis ||= create_redis_client.pubsub
45
45
  end
46
46
 
47
47
  end
@@ -1,4 +1,4 @@
1
- require 'twitter/json_stream'
1
+ require 'em-twitter'
2
2
  require 'multi_json'
3
3
 
4
4
  module Weeter
@@ -23,18 +23,22 @@ module Weeter
23
23
  def connect(filter_params)
24
24
  filter_params = limit_filter_params(filter_params)
25
25
  filter_params = clean_filter_params(filter_params)
26
-
27
-
28
- connect_options = {
29
- ssl: true,
30
- params: filter_params,
31
- method: 'POST'
32
- }.merge(@config.auth_options)
26
+ oauth_options = @config.auth_options[:oauth]
27
+
28
+ options = {
29
+ :path => '/1.1/statuses/filter.json',
30
+ :params => filter_params,
31
+ :oauth => {
32
+ :consumer_key => oauth_options[:consumer_key],
33
+ :consumer_secret => oauth_options[:consumer_secret],
34
+ :token => oauth_options[:access_key],
35
+ :token_secret => oauth_options[:access_secret]
36
+ }
37
+ }
33
38
 
34
39
  Weeter.logger.info("Connecting to Twitter stream...")
35
- @stream = ::Twitter::JSONStream.connect(connect_options)
36
-
37
- @stream.each_item do |item|
40
+ @client = EM::Twitter::Client.connect(options)
41
+ @client.each do |item|
38
42
  begin
39
43
  tweet_item = TweetItem.new(MultiJson.decode(item))
40
44
 
@@ -52,18 +56,50 @@ module Weeter
52
56
  end
53
57
  end
54
58
 
55
- @stream.on_error do |msg|
59
+ @client.on_unauthorized do |msg|
60
+ Weeter.logger.debug("on_unauthorized: #{msg}")
61
+ end
62
+
63
+ @client.on_forbidden do |msg|
64
+ Weeter.logger.debug("on_forbidden: #{msg}")
65
+ end
66
+
67
+ @client.on_not_found do |msg|
68
+ Weeter.logger.debug("on_not_found: #{msg}")
69
+ end
70
+
71
+ @client.on_not_acceptable do |msg|
72
+ Weeter.logger.debug("on_not_acceptable: #{msg}")
73
+ end
74
+
75
+ @client.on_too_long do |msg|
76
+ Weeter.logger.debug("on_too_long: #{msg}")
77
+ end
78
+
79
+ @client.on_range_unacceptable do |msg|
80
+ Weeter.logger.debug("on_range_unacceptable: #{msg}")
81
+ end
82
+
83
+ @client.on_enhance_your_calm do |msg| # rate-limited
84
+ Weeter.logger.debug("on_enhance_your_calm: #{msg}")
85
+ end
86
+
87
+ @client.on_error do |msg|
56
88
  Weeter.logger.error("Twitter stream error: #{msg}. Connect options were #{connect_options.inspect}")
57
89
  end
58
90
 
59
- @stream.on_max_reconnects do |timeout, retries|
91
+ @client.on_reconnect do |msg|
92
+ Weeter.logger.debug("on_reconnect: #{msg}")
93
+ end
94
+
95
+ @client.on_max_reconnects do |timeout, retries|
60
96
  Weeter.logger.error("Twitter stream max-reconnects reached: timeout=#{timeout}, retries=#{retries}")
61
97
  end
62
98
  end
63
99
 
64
100
  def reconnect(filter_params)
65
- @stream.stop
66
- @stream.unbind
101
+ @client.stop
102
+ @client.unbind
67
103
  connect(filter_params)
68
104
  end
69
105
 
@@ -1,3 +1,3 @@
1
1
  module Weeter
2
- VERSION = "0.15.0"
2
+ VERSION = "0.17.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -8,4 +8,6 @@ RSpec.configure do |config|
8
8
  config.before(:all) do
9
9
  Weeter::Configuration.instance.log_path = 'log/test.log'
10
10
  end
11
+ config.filter_run focus: true
12
+ config.run_all_when_everything_filtered = true
11
13
  end
@@ -2,17 +2,13 @@ require 'spec_helper'
2
2
 
3
3
  describe Weeter::Configuration::ClientAppConfig do
4
4
  %w{delete_url subscriptions_url oauth}.each do |setting|
5
- it "should accept setting for #{setting}" do
5
+ it "accepts setting for #{setting}" do
6
6
  Weeter.configure do |conf|
7
7
  conf.client_app do |app|
8
8
  app.send("#{setting}=", "testvalue")
9
9
  end
10
10
  end
11
- Weeter::Configuration.instance.client_app.send(setting).should == "testvalue"
11
+ expect(Weeter::Configuration.instance.client_app.send(setting)).to eq("testvalue")
12
12
  end
13
13
  end
14
-
15
- it "should default subscription_updates_port" do
16
- Weeter::Configuration.instance.client_app.subscription_updates_port.should == 7337
17
- end
18
14
  end
@@ -2,38 +2,38 @@ require 'spec_helper'
2
2
 
3
3
  describe Weeter::Configuration::TwitterConfig do
4
4
  %w{basic_auth oauth}.each do |setting|
5
- it "should accept setting for #{setting}" do
5
+ it "accepts setting for #{setting}" do
6
6
  Weeter.configure do |conf|
7
7
  conf.twitter do |app|
8
8
  app.send("#{setting}=", "testvalue")
9
9
  end
10
10
  end
11
- Weeter::Configuration::TwitterConfig.instance.send(setting).should == "testvalue"
11
+ expect(Weeter::Configuration::TwitterConfig.instance.send(setting)).to eq("testvalue")
12
12
  end
13
13
  end
14
-
14
+
15
15
  describe "auth_options" do
16
-
16
+
17
17
  before do
18
18
  Weeter::Configuration::TwitterConfig.instance.oauth = nil
19
19
  Weeter::Configuration::TwitterConfig.instance.basic_auth = nil
20
20
  end
21
-
22
- it "should return the oauth settings with a oauth credentials" do
21
+
22
+ it "returns the oauth settings with a oauth credentials" do
23
23
  Weeter::Configuration::TwitterConfig.instance.oauth = {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}
24
- Weeter::Configuration::TwitterConfig.instance.auth_options.should == {:oauth => {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}}
24
+ expect(Weeter::Configuration::TwitterConfig.instance.auth_options).to eq({:oauth => {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}})
25
25
  end
26
-
27
- it "should return the basic auth settings separated by a colon" do
26
+
27
+ it "returns the basic auth settings separated by a colon" do
28
28
  Weeter::Configuration::TwitterConfig.instance.basic_auth = {:username => "bob", :password => "s3cr3t"}
29
- Weeter::Configuration::TwitterConfig.instance.auth_options.should == {:auth => "bob:s3cr3t"}
29
+ expect(Weeter::Configuration::TwitterConfig.instance.auth_options).to eq({:auth => "bob:s3cr3t"})
30
30
  end
31
-
32
- it "should prefer oauth over basic auth" do
31
+
32
+ it "prefers oauth over basic auth" do
33
33
  Weeter::Configuration::TwitterConfig.instance.basic_auth = {:username => "bob", :password => "s3cr3t"}
34
34
  Weeter::Configuration::TwitterConfig.instance.oauth = {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}
35
- Weeter::Configuration::TwitterConfig.instance.auth_options.should == {:oauth => {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}}
35
+ expect(Weeter::Configuration::TwitterConfig.instance.auth_options).to eq({:oauth => {:consumer_key => 'consumer_key', :consumer_secret => 'consumer_secret', :access_key => 'acces_key', :access_secret => 'access_secret'}})
36
36
  end
37
37
  end
38
-
39
- end
38
+
39
+ end
@@ -2,14 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe Weeter::Configuration do
4
4
  describe "#twitter" do
5
- it "should return the instance" do
6
- Weeter::Configuration.instance.twitter.should == Weeter::Configuration::TwitterConfig.instance
5
+ it "returns the instance" do
6
+ expect(Weeter::Configuration.instance.twitter).to eq(Weeter::Configuration::TwitterConfig.instance)
7
7
  end
8
8
 
9
- it "should yield the instance when a block is provided" do
9
+ it "yields the instance when a block is provided" do
10
10
  Weeter::Configuration.instance.twitter do |twitter_config|
11
- twitter_config.should == Weeter::Configuration::TwitterConfig.instance
11
+ expect(twitter_config).to eq(Weeter::Configuration::TwitterConfig.instance)
12
12
  end
13
13
  end
14
14
  end
15
- end
15
+ end
@@ -14,7 +14,7 @@ describe Weeter::Limitator do
14
14
  let(:keys) { ['key'] }
15
15
 
16
16
  describe '.new' do
17
- it { limitator.should be }
17
+ it { expect(limitator).to be }
18
18
  end
19
19
 
20
20
  describe '#limit_status' do
@@ -25,38 +25,38 @@ describe Weeter::Limitator do
25
25
 
26
26
  context 'max: 0' do
27
27
  let(:max) { 0 }
28
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
29
- its(:limited_keys) { should == keys }
28
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
29
+ it { expect(subject.limited_keys).to eq(keys) }
30
30
 
31
31
  context 'no keys' do
32
32
  let(:keys) { [] }
33
- its(:status) { should == Weeter::Limitator::DO_NOT_LIMIT }
34
- its(:limited_keys) { should == nil }
33
+ it { expect(subject.status).to eq(Weeter::Limitator::DO_NOT_LIMIT) }
34
+ it { expect(subject.limited_keys).to be_nil }
35
35
  end
36
36
 
37
37
  context 'two keys' do
38
38
  let(:keys) { ['key', 'key2'] }
39
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
40
- its(:limited_keys) { should == keys }
39
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
40
+ it { expect(subject.limited_keys).to eq(keys) }
41
41
  end
42
42
  end
43
43
 
44
44
  context 'max: 1' do
45
45
  let(:max) { 1 }
46
46
 
47
- its(:status) { should == Weeter::Limitator::DO_NOT_LIMIT }
48
- its(:limited_keys) { should == nil }
47
+ it { expect(subject.status).to eq(Weeter::Limitator::DO_NOT_LIMIT) }
48
+ it { expect(subject.limited_keys).to be_nil }
49
49
 
50
50
  context 'two keys within max' do
51
51
  let(:keys) { ['key', 'key2'] }
52
52
 
53
- its(:status) { should == Weeter::Limitator::DO_NOT_LIMIT }
53
+ it { expect(subject.status).to eq(Weeter::Limitator::DO_NOT_LIMIT) }
54
54
  end
55
55
 
56
56
  context 'no keys' do
57
57
  let(:keys) { [] }
58
- its(:status) { should == Weeter::Limitator::DO_NOT_LIMIT }
59
- its(:limited_keys) { should == nil }
58
+ it { expect(subject.status).to eq(Weeter::Limitator::DO_NOT_LIMIT) }
59
+ it { expect(subject.limited_keys).to be_nil }
60
60
  end
61
61
 
62
62
  context 'one key just outside max' do
@@ -66,8 +66,8 @@ describe Weeter::Limitator do
66
66
  end
67
67
  end
68
68
 
69
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
70
- its(:limited_keys) { should == keys }
69
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
70
+ it { expect(subject.limited_keys).to eq(keys) }
71
71
 
72
72
  context 'outside duration' do
73
73
  let(:some_time_after_duration) do
@@ -75,11 +75,11 @@ describe Weeter::Limitator do
75
75
  end
76
76
 
77
77
  before do
78
- limitator.stub(:now).and_return(some_time_after_duration)
78
+ expect(limitator).to receive(:now).and_return(some_time_after_duration).at_least(:once)
79
79
  end
80
80
 
81
- its(:status) { should == Weeter::Limitator::DO_NOT_LIMIT }
82
- its(:limited_keys) { should == nil }
81
+ it { expect(subject.status).to eq(Weeter::Limitator::DO_NOT_LIMIT) }
82
+ it { expect(subject.limited_keys).to be_nil }
83
83
  end
84
84
  end
85
85
 
@@ -90,8 +90,8 @@ describe Weeter::Limitator do
90
90
  limitator.process(*keys)
91
91
  end
92
92
 
93
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
94
- its(:limited_keys) { should == keys }
93
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
94
+ it { expect(subject.limited_keys).to eq(keys) }
95
95
  end
96
96
 
97
97
  context 'two keys past max' do
@@ -102,8 +102,8 @@ describe Weeter::Limitator do
102
102
  limitator.process(*keys)
103
103
  end
104
104
 
105
- its(:status) { should == Weeter::Limitator::CONTINUE_LIMITING }
106
- its(:limited_keys) { should == keys }
105
+ it { expect(subject.status).to eq(Weeter::Limitator::CONTINUE_LIMITING) }
106
+ it { expect(subject.limited_keys).to eq(keys) }
107
107
  end
108
108
 
109
109
  context 'one key just past max: 1, one key within max: 1' do
@@ -114,8 +114,8 @@ describe Weeter::Limitator do
114
114
  limitator.process(keys.first)
115
115
  end
116
116
 
117
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
118
- its(:limited_keys) { should == [keys.first] }
117
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
118
+ it { expect(subject.limited_keys).to eq([keys.first]) }
119
119
  end
120
120
 
121
121
  context 'one key past max: 1, one key within max: 1' do
@@ -127,8 +127,8 @@ describe Weeter::Limitator do
127
127
  limitator.process(keys.first)
128
128
  end
129
129
 
130
- its(:status) { should == Weeter::Limitator::CONTINUE_LIMITING }
131
- its(:limited_keys) { should == [keys.first] }
130
+ it { expect(subject.status).to eq(Weeter::Limitator::CONTINUE_LIMITING) }
131
+ it { expect(subject.limited_keys).to eq([keys.first]) }
132
132
  end
133
133
 
134
134
  context 'one key past max: 1, one key just past max: 1' do
@@ -140,8 +140,8 @@ describe Weeter::Limitator do
140
140
  limitator.process(*[keys.first, keys.last])
141
141
  end
142
142
 
143
- its(:status) { should == Weeter::Limitator::INITIATE_LIMITING }
144
- its(:limited_keys) { should == keys }
143
+ it { expect(subject.status).to eq(Weeter::Limitator::INITIATE_LIMITING) }
144
+ it { expect(subject.limited_keys).to eq(keys) }
145
145
  end
146
146
  end
147
147
  end
@@ -4,14 +4,14 @@ module Weeter
4
4
  module Plugins
5
5
  describe NotificationPlugin do
6
6
  describe "#publish_tweet" do
7
- it "should delegate to the configured plugin" do
7
+ it "delegates to the configured plugin" do
8
8
  client_app_config = Hashie::Mash.new(:notification_plugin => :http)
9
9
  tweet_item = TweetItem.new({})
10
-
11
- mock_plugin = mock(Notification::Http)
12
- Notification::Http.should_receive(:new).and_return(mock_plugin)
13
-
14
- mock_plugin.should_receive(:publish_tweet).with(tweet_item)
10
+
11
+ mock_plugin = double(Notification::Http)
12
+ expect(Notification::Http).to receive(:new).and_return(mock_plugin)
13
+
14
+ expect(mock_plugin).to receive(:publish_tweet).with(tweet_item)
15
15
 
16
16
  plugin = NotificationPlugin.new(client_app_config)
17
17
  plugin.publish_tweet(tweet_item)
@@ -5,26 +5,26 @@ module Weeter
5
5
  describe Http::UpdateServer do
6
6
  before(:each) do
7
7
  @new_ids = [1,2,3]
8
- @tweet_consumer = mock('TweetConsumer', :reconnect => nil)
8
+ @tweet_consumer = double('TweetConsumer', :reconnect => nil)
9
9
  @tweet_server = Http::UpdateServer.new(nil)
10
10
  @tweet_server.instance_variable_set('@http_post_content', MultiJson.encode(@new_ids))
11
11
  @tweet_server.tweet_consumer = @tweet_consumer
12
- @response = mock('DelegatedHttpResponse', :send_response => nil)
13
- EM::DelegatedHttpResponse.stub!(:new).and_return(@response)
12
+ @response = double('DelegatedHttpResponse', :send_response => nil)
13
+ expect(EM::DelegatedHttpResponse).to receive(:new).and_return(@response)
14
14
  end
15
-
15
+
16
16
  after(:each) do
17
17
  @tweet_server.process_http_request
18
18
  end
19
-
20
- it "should process http request" do
21
- @tweet_consumer.should_receive(:reconnect).with(@new_ids)
19
+
20
+ it "processes http request" do
21
+ expect(@tweet_consumer).to receive(:reconnect).with(@new_ids)
22
22
  end
23
-
24
- it "should send response" do
25
- @response.should_receive(:send_response)
23
+
24
+ it "sends the response" do
25
+ expect(@response). to receive(:send_response)
26
26
  end
27
27
  end
28
28
  end
29
29
  end
30
- end
30
+ end
@@ -4,17 +4,17 @@ module Weeter
4
4
  module Plugins
5
5
  describe SubscriptionPlugin do
6
6
  describe "#get_initial_filters" do
7
- it "should delegate to the configured plugin" do
7
+ it "delegates to the configured plugin" do
8
8
  client_app_config = Hashie::Mash.new(:subscription_plugin => :http)
9
-
10
- mock_plugin = mock(Subscription::Http)
11
- Subscription::Http.should_receive(:new).and_return(mock_plugin)
12
-
13
- mock_plugin.should_receive(:get_initial_filters).and_yield([{'foo' => 'bar'}])
9
+
10
+ mock_plugin = double(Subscription::Http)
11
+ expect(Subscription::Http).to receive(:new).and_return(mock_plugin)
12
+
13
+ expect(mock_plugin).to receive(:get_initial_filters).and_yield([{'foo' => 'bar'}])
14
14
 
15
15
  plugin = SubscriptionPlugin.new(client_app_config)
16
16
  plugin.get_initial_filters do |filter_params|
17
- filter_params.should == [{'foo' => 'bar'}]
17
+ expect(filter_params).to eq([{'foo' => 'bar'}])
18
18
  end
19
19
  end
20
20
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'em-twitter'
2
3
 
3
4
  describe Weeter::Twitter::TweetConsumer do
4
5
  let(:limiter) do
@@ -9,20 +10,25 @@ describe Weeter::Twitter::TweetConsumer do
9
10
  end
10
11
 
11
12
  describe "auth" do
12
- it 'should use connect to JSON stream with auth options for the configuration' do
13
- @mock_stream = mock('JSONStream', :each_item => nil, :on_error => nil, :on_max_reconnects => nil, :on_close => nil)
14
- Twitter::JSONStream.stub!(:connect).and_return(@mock_stream)
15
-
16
- Weeter::Configuration::TwitterConfig.instance.stub!(:auth_options).and_return(:foo => :bar)
17
- consumer = Weeter::Twitter::TweetConsumer.new(Weeter::Configuration::TwitterConfig.instance, mock('NotificationPlugin'), limiter)
18
- Twitter::JSONStream.should_receive(:connect).with(hash_including(:foo => :bar))
13
+ it 'connects to JSON stream with auth options for the configuration' do
14
+ mock_client = double('EM::Twitter::Client', on_error: nil, on_unauthorized: nil, on_forbidden: nil, on_not_found: nil,
15
+ on_not_acceptable: nil, on_range_unacceptable: nil, on_too_long: nil, on_enhance_your_calm: nil, on_reconnect: nil,
16
+ on_max_reconnects: nil,
17
+ each: nil)
18
+ expect(Weeter::Configuration::TwitterConfig.instance).to receive(:auth_options).and_return(:oauth => { :foo => :bar }).at_least(:once)
19
+ expect(EM::Twitter::Client).to receive(:connect).with(hash_including(
20
+ :path => "/1.1/statuses/filter.json",
21
+ :params => { 'follow' => [1, 2] }
22
+ )).and_return(mock_client)
23
+
24
+ consumer = Weeter::Twitter::TweetConsumer.new(Weeter::Configuration::TwitterConfig.instance, double('NotificationPlugin'), limiter)
19
25
  consumer.connect({'follow' => ['1','2']})
20
26
  end
21
27
  end
22
28
 
23
29
  describe '#limit_filter_params' do
24
30
 
25
- let(:client_proxy) { mock('NotificationPlugin', :publish_tweet => nil) }
31
+ let(:client_proxy) { double('NotificationPlugin', :publish_tweet => nil) }
26
32
  let(:consumer) do
27
33
  Weeter::Twitter::TweetConsumer.new(Weeter::Configuration::TwitterConfig.instance, client_proxy, limiter)
28
34
  end
@@ -40,8 +46,8 @@ describe Weeter::Twitter::TweetConsumer do
40
46
  context 'limit not reached' do
41
47
  it 'leaves the values alone' do
42
48
  result = consumer.send(:limit_filter_params, params)
43
- result.fetch('track').length.should == 0
44
- result.fetch('follow').length.should == 0
49
+ expect(result.fetch('track').length).to eq(0)
50
+ expect(result.fetch('follow').length).to eq(0)
45
51
  end
46
52
  end
47
53
 
@@ -50,8 +56,8 @@ describe Weeter::Twitter::TweetConsumer do
50
56
 
51
57
  it 'it limits follows, but not tracks' do
52
58
  result = consumer.send(:limit_filter_params, params)
53
- result.fetch('follow').length.should == 5000
54
- result.fetch('track').length.should == 0
59
+ expect(result.fetch('follow').length).to eq(5000)
60
+ expect(result.fetch('track').length).to eq(0)
55
61
  end
56
62
  end
57
63
 
@@ -60,8 +66,8 @@ describe Weeter::Twitter::TweetConsumer do
60
66
 
61
67
  it 'limits tracks, but not follows' do
62
68
  result = consumer.send(:limit_filter_params, params)
63
- result.fetch('track').length.should == 400
64
- result.fetch('follow').length.should == 0
69
+ expect(result.fetch('track').length).to eq(400)
70
+ expect(result.fetch('follow').length).to eq(0)
65
71
  end
66
72
  end
67
73
 
@@ -72,8 +78,8 @@ describe Weeter::Twitter::TweetConsumer do
72
78
  it 'limits both' do
73
79
 
74
80
  result = consumer.send(:limit_filter_params, params)
75
- result.fetch('track').length.should == 400
76
- result.fetch('follow').length.should == 5000
81
+ expect(result.fetch('track').length).to eq(400)
82
+ expect(result.fetch('follow').length).to eq(5000)
77
83
  end
78
84
  end
79
85
  end
@@ -83,20 +89,27 @@ describe Weeter::Twitter::TweetConsumer do
83
89
  let(:tweet_values) {
84
90
  [@tweet_hash]
85
91
  }
86
- let(:mock_stream) {
87
- mock_stream = mock('JSONStream', :on_error => nil, :on_max_reconnects => nil, :on_close => nil)
88
- each_item_stub = mock_stream.stub!(:each_item)
92
+ let(:mock_client) {
93
+ client = double('EM::Twitter::Client', on_error: nil, on_unauthorized: nil, on_forbidden: nil, on_not_found: nil,
94
+ on_not_acceptable: nil, on_range_unacceptable: nil, on_too_long: nil, on_enhance_your_calm: nil, on_reconnect: nil,
95
+ on_max_reconnects: nil,
96
+ each: nil)
97
+ client_expectation = expect(client).to receive(:each)
89
98
  tweet_values.each do |t|
90
- each_item_stub.and_yield(MultiJson.encode(t))
99
+ client_expectation.and_yield(MultiJson.encode(t))
91
100
  end
92
- mock_stream
101
+ client
93
102
  }
94
103
  before(:each) do
95
- @filter_params = {'follow' => ['1','2','3']}
96
- Weeter::Configuration::TwitterConfig.instance.stub!(:auth_options).and_return(:foo => :bar)
97
104
  @tweet_hash = {'text' => "Hey", 'id_str' => "123", 'user' => {'id_str' => "1"}}
98
- Twitter::JSONStream.stub!(:connect).and_return(mock_stream)
99
- @client_proxy = mock('NotificationPlugin', :publish_tweet => nil)
105
+ expect(EM::Twitter::Client).to receive(:connect).with(hash_including(
106
+ :path => "/1.1/statuses/filter.json",
107
+ :params => { 'follow' => [1, 2, 3] }
108
+ )).and_return(mock_client)
109
+
110
+ @filter_params = {'follow' => ['1','2','3']}
111
+ expect(Weeter::Configuration::TwitterConfig.instance).to receive(:auth_options).and_return(:oauth => { :foo => :bar }).at_least(:once)
112
+ @client_proxy = double('NotificationPlugin', :publish_tweet => nil)
100
113
  @consumer = Weeter::Twitter::TweetConsumer.new(Weeter::Configuration::TwitterConfig.instance, @client_proxy, limiter)
101
114
  end
102
115
 
@@ -104,50 +117,45 @@ describe Weeter::Twitter::TweetConsumer do
104
117
  @consumer.connect(@filter_params)
105
118
  end
106
119
 
107
- it "should instantiate a TweetItem" do
120
+ it "instantiates a TweetItem" do
108
121
  tweet_item = Weeter::TweetItem.new(@tweet_hash)
109
- Weeter::TweetItem.should_receive(:new).with({'text' => "Hey", 'id_str' => "123", 'user' => {'id_str' => "1"}}).and_return(tweet_item)
110
- end
111
-
112
- it "should connect to a Twitter JSON stream" do
113
- Twitter::JSONStream.should_receive(:connect).
114
- with(:ssl => true, :foo => :bar, :params => {'follow' => [1,2,3]}, :method => 'POST')
122
+ expect(Weeter::TweetItem).to receive(:new).with({'text' => "Hey", 'id_str' => "123", 'user' => {'id_str' => "1"}}).and_return(tweet_item)
115
123
  end
116
124
 
117
- it "should publish new tweet if publishable" do
118
- mock_tweet = mock('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => [])
119
- Weeter::TweetItem.stub!(:new).and_return(mock_tweet)
120
- @client_proxy.should_receive(:publish_tweet).with(mock_tweet)
125
+ it "publishes new tweet if publishable" do
126
+ mock_tweet = double('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => [])
127
+ expect(Weeter::TweetItem).to receive(:new).and_return(mock_tweet)
128
+ expect(@client_proxy).to receive(:publish_tweet).with(mock_tweet)
121
129
  end
122
130
 
123
- it "should not publish unpublishable tweets" do
124
- mock_tweet = mock('tweet', :deletion? => false, :publishable? => false, :limit_notice? => false, :[] => '', :limiting_facets => [], :disconnect_notice? => false)
125
- Weeter::TweetItem.stub!(:new).and_return mock_tweet
126
- @client_proxy.should_not_receive(:publish_tweet).with(mock_tweet)
131
+ it "does not publish unpublishable tweets" do
132
+ mock_tweet = double('tweet', :deletion? => false, :publishable? => false, :limit_notice? => false, :[] => '', :limiting_facets => [], :disconnect_notice? => false)
133
+ expect(Weeter::TweetItem).to receive(:new).and_return mock_tweet
134
+ expect(@client_proxy).to_not receive(:publish_tweet).with(mock_tweet)
127
135
  end
128
136
 
129
- it "should delete deletion tweets" do
130
- mock_tweet = mock('tweet', :deletion? => true, :publishable? => false, :limit_notice? => false, :limiting_facets => [])
131
- Weeter::TweetItem.stub!(:new).and_return mock_tweet
132
- @client_proxy.should_receive(:delete_tweet).with(mock_tweet)
137
+ it "deletes deletion tweets" do
138
+ mock_tweet = double('tweet', :deletion? => true, :publishable? => false, :limit_notice? => false, :limiting_facets => [])
139
+ expect(Weeter::TweetItem).to receive(:new).and_return mock_tweet
140
+ expect(@client_proxy).to receive(:delete_tweet).with(mock_tweet)
133
141
  end
134
142
 
135
- it "should notify when stream is limited by Twitter" do
143
+ it "notifies when stream is limited by Twitter" do
136
144
  tweet_item = Weeter::TweetItem.new({'limit' => { 'track' => 65 } })
137
- Weeter::TweetItem.stub!(:new).and_return(tweet_item)
138
- @client_proxy.should_receive(:notify_missed_tweets).with(tweet_item)
145
+ expect(Weeter::TweetItem).to receive(:new).and_return(tweet_item)
146
+ expect(@client_proxy).to receive(:notify_missed_tweets).with(tweet_item)
139
147
  end
140
148
 
141
149
  context "when weeter is initiating rate-limiting on a facet" do
142
150
  let(:tweet_values) {
143
151
  [@tweet_hash, @tweet_hash]
144
152
  }
145
- it "should notify that rate limiting is being initiated" do
146
- tweet_item1 = mock('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => ['key'], :[] => '1')
147
- tweet_item2 = mock('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => ['key'], :[] => '2')
148
- Weeter::TweetItem.stub!(:new).and_return(tweet_item1, tweet_item2)
153
+ it "notifies that rate limiting is being initiated" do
154
+ tweet_item1 = double('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => ['key'], :[] => '1')
155
+ tweet_item2 = double('tweet', :deletion? => false, :publishable? => true, :limit_notice? => false, :limiting_facets => ['key'], :[] => '2')
156
+ expect(Weeter::TweetItem).to receive(:new).and_return(tweet_item1, tweet_item2)
149
157
 
150
- @client_proxy.should_receive(:notify_rate_limiting_initiated).with(tweet_item2, ['key'])
158
+ expect(@client_proxy).to receive(:notify_rate_limiting_initiated).with(tweet_item2, ['key'])
151
159
  end
152
160
  end
153
161
  end
@@ -6,77 +6,77 @@ describe Weeter::TweetItem do
6
6
  }
7
7
 
8
8
  describe "deletion?" do
9
- it "should be true if it is a deletion request" do
9
+ it "is true if it is a deletion request" do
10
10
  item = Weeter::TweetItem.new({"delete"=>{"status"=>{"id"=>234, "user_id"=>34555}}})
11
- item.should be_deletion
11
+ expect(item).to be_deletion
12
12
  end
13
13
 
14
- it "should be false if it is not a deletion request" do
14
+ it "is false if it is not a deletion request" do
15
15
  item = Weeter::TweetItem.new({'text' => "Hey", 'id_str' => "123", 'user' => {'id_str' => "1"}})
16
- item.should_not be_deletion
16
+ expect(item).to_not be_deletion
17
17
  end
18
18
  end
19
19
 
20
20
  describe "publishable" do
21
21
 
22
22
 
23
- it "should be publishable if not a reply or a retweet" do
23
+ it "is publishable if not a reply or a retweet" do
24
24
  item = Weeter::TweetItem.new(tweet_json)
25
- item.should be_publishable
25
+ expect(item).to be_publishable
26
26
  end
27
27
 
28
- it "should not be publishable if implicitly retweeted" do
28
+ it "is not publishable if implicitly retweeted" do
29
29
  item = Weeter::TweetItem.new(tweet_json.merge({'text' => 'RT @joe Hey'}))
30
- item.should_not be_publishable
30
+ expect(item).to_not be_publishable
31
31
  end
32
32
 
33
- it "should not be publishable if explicitly retweeted" do
33
+ it "is not publishable if explicitly retweeted" do
34
34
  item = Weeter::TweetItem.new(tweet_json.merge('retweeted_status' => {'id_str' => '111', 'text' => 'Hey', 'user' => {'id_str' => "1"}}))
35
- item.should_not be_publishable
35
+ expect(item).to_not be_publishable
36
36
  end
37
37
 
38
- it "should not be publishable if implicit reply" do
38
+ it "is not publishable if implicit reply" do
39
39
  item = Weeter::TweetItem.new(tweet_json.merge('text' => '@joe Hey'))
40
- item.should_not be_publishable
40
+ expect(item).to_not be_publishable
41
41
  end
42
42
 
43
- it "should not be publishable if explicit reply" do
43
+ it "is not publishable if explicit reply" do
44
44
  item = Weeter::TweetItem.new(tweet_json.merge('text' => '@joe Hey', 'in_reply_to_user_id_str' => '1'))
45
- item.should_not be_publishable
45
+ expect(item).to_not be_publishable
46
46
  end
47
47
 
48
- it "should not be publishable if disconnect message" do
48
+ it "is not publishable if disconnect message" do
49
49
  item = Weeter::TweetItem.new({"disconnect" => {"code" => 7,"stream_name" => "YappBox-statuses668638","reason" => "admin logout"}})
50
- item.should_not be_publishable
50
+ expect(item).to_not be_publishable
51
51
  end
52
52
 
53
53
  end
54
54
 
55
55
  describe "limit_notice?" do
56
- it "should be true if it's a limit notice" do
56
+ it "is true if it's a limit notice" do
57
57
  item = Weeter::TweetItem.new({ 'limit' => { 'track' => 65 }})
58
- item.should be_limit_notice
59
- item.missed_tweets_count.should == 65
58
+ expect(item).to be_limit_notice
59
+ expect(item.missed_tweets_count).to eq(65)
60
60
  end
61
- it "should not be true if it's a limit notice" do
61
+ it "is not be true if it's a limit notice" do
62
62
  item = Weeter::TweetItem.new(tweet_json)
63
- item.should_not be_limit_notice
64
- lambda {
63
+ expect(item).to_not be_limit_notice
64
+ expect(lambda {
65
65
  item.missed_tweets_count
66
- }.should_not raise_error
66
+ }).to_not raise_error
67
67
  end
68
68
  end
69
69
 
70
70
  describe "json attributes" do
71
71
 
72
- it "should delegate hash calls to its json" do
72
+ it "delegates hash calls to its json" do
73
73
  item = Weeter::TweetItem.new({'text' => "Hey"})
74
- item['text'].should == "Hey"
74
+ expect(item['text']).to eq("Hey")
75
75
  end
76
76
 
77
- it "should retrieve nested attributes" do
77
+ it "retrieves nested attributes" do
78
78
  item = Weeter::TweetItem.new({'text' => "Hey", 'id_str' => "123", 'user' => {'id_str' => '1'}})
79
- item['user']['id_str'].should == "1"
79
+ expect(item['user']['id_str']).to eq("1")
80
80
  end
81
81
 
82
82
  end
data/weeter.gemspec CHANGED
@@ -19,17 +19,18 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency('eventmachine')
23
- s.add_dependency('eventmachine_httpserver', '>= 0.2.1')
24
- s.add_dependency('em-hiredis', '>= 0.1.0')
25
- s.add_dependency('multi_json', '>= 1.0.2')
26
- s.add_dependency('hashie', '>= 1.1.0')
27
- s.add_dependency('em-http-request', '>= 1.0.0')
28
- s.add_dependency('i18n', "~> 0.6.0")
29
- s.add_dependency('activesupport', ">= 3.1.1")
30
- s.add_dependency("simple_oauth", '>= 0.1.5')
31
- s.add_dependency('lukemelia-twitter-stream', '~> 0.1.15')
22
+ s.add_dependency('eventmachine', '~> 1.2.0')
23
+ s.add_dependency('eventmachine_httpserver', '~> 0.2.1')
24
+ s.add_dependency('em-hiredis', '~> 0.3.1')
25
+ s.add_dependency('multi_json', '~> 1.3.0')
26
+ s.add_dependency('hashie', '>= 2.0.5')
27
+ s.add_dependency('em-http-request', '~> 1.1.5')
28
+ s.add_dependency('i18n', "~> 0.6.11")
29
+ s.add_dependency('activesupport', ">= 3.2.22")
30
+ s.add_dependency("simple_oauth", '~> 0.3.1')
31
+ s.add_dependency('em-twitter', '~> 0.3.5')
32
32
 
33
- s.add_development_dependency 'rspec', '~> 2.6.0'
33
+ s.add_development_dependency 'rspec', '~> 3.4.0'
34
+ s.add_development_dependency 'byebug', '~> 2.4.1'
34
35
  s.add_development_dependency 'ZenTest'
35
36
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weeter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
5
- prerelease:
4
+ version: 0.17.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Luke Melia
@@ -11,200 +10,190 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2013-02-19 00:00:00.000000000 Z
13
+ date: 2017-07-21 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: eventmachine
18
- prerelease: false
19
17
  requirement: !ruby/object:Gem::Requirement
20
18
  requirements:
21
- - - ! '>='
19
+ - - "~>"
22
20
  - !ruby/object:Gem::Version
23
- version: '0'
24
- none: false
21
+ version: 1.2.0
25
22
  type: :runtime
23
+ prerelease: false
26
24
  version_requirements: !ruby/object:Gem::Requirement
27
25
  requirements:
28
- - - ! '>='
26
+ - - "~>"
29
27
  - !ruby/object:Gem::Version
30
- version: '0'
31
- none: false
28
+ version: 1.2.0
32
29
  - !ruby/object:Gem::Dependency
33
30
  name: eventmachine_httpserver
34
- prerelease: false
35
31
  requirement: !ruby/object:Gem::Requirement
36
32
  requirements:
37
- - - ! '>='
33
+ - - "~>"
38
34
  - !ruby/object:Gem::Version
39
35
  version: 0.2.1
40
- none: false
41
36
  type: :runtime
37
+ prerelease: false
42
38
  version_requirements: !ruby/object:Gem::Requirement
43
39
  requirements:
44
- - - ! '>='
40
+ - - "~>"
45
41
  - !ruby/object:Gem::Version
46
42
  version: 0.2.1
47
- none: false
48
43
  - !ruby/object:Gem::Dependency
49
44
  name: em-hiredis
50
- prerelease: false
51
45
  requirement: !ruby/object:Gem::Requirement
52
46
  requirements:
53
- - - ! '>='
47
+ - - "~>"
54
48
  - !ruby/object:Gem::Version
55
- version: 0.1.0
56
- none: false
49
+ version: 0.3.1
57
50
  type: :runtime
51
+ prerelease: false
58
52
  version_requirements: !ruby/object:Gem::Requirement
59
53
  requirements:
60
- - - ! '>='
54
+ - - "~>"
61
55
  - !ruby/object:Gem::Version
62
- version: 0.1.0
63
- none: false
56
+ version: 0.3.1
64
57
  - !ruby/object:Gem::Dependency
65
58
  name: multi_json
66
- prerelease: false
67
59
  requirement: !ruby/object:Gem::Requirement
68
60
  requirements:
69
- - - ! '>='
61
+ - - "~>"
70
62
  - !ruby/object:Gem::Version
71
- version: 1.0.2
72
- none: false
63
+ version: 1.3.0
73
64
  type: :runtime
65
+ prerelease: false
74
66
  version_requirements: !ruby/object:Gem::Requirement
75
67
  requirements:
76
- - - ! '>='
68
+ - - "~>"
77
69
  - !ruby/object:Gem::Version
78
- version: 1.0.2
79
- none: false
70
+ version: 1.3.0
80
71
  - !ruby/object:Gem::Dependency
81
72
  name: hashie
82
- prerelease: false
83
73
  requirement: !ruby/object:Gem::Requirement
84
74
  requirements:
85
- - - ! '>='
75
+ - - ">="
86
76
  - !ruby/object:Gem::Version
87
- version: 1.1.0
88
- none: false
77
+ version: 2.0.5
89
78
  type: :runtime
79
+ prerelease: false
90
80
  version_requirements: !ruby/object:Gem::Requirement
91
81
  requirements:
92
- - - ! '>='
82
+ - - ">="
93
83
  - !ruby/object:Gem::Version
94
- version: 1.1.0
95
- none: false
84
+ version: 2.0.5
96
85
  - !ruby/object:Gem::Dependency
97
86
  name: em-http-request
98
- prerelease: false
99
87
  requirement: !ruby/object:Gem::Requirement
100
88
  requirements:
101
- - - ! '>='
89
+ - - "~>"
102
90
  - !ruby/object:Gem::Version
103
- version: 1.0.0
104
- none: false
91
+ version: 1.1.5
105
92
  type: :runtime
93
+ prerelease: false
106
94
  version_requirements: !ruby/object:Gem::Requirement
107
95
  requirements:
108
- - - ! '>='
96
+ - - "~>"
109
97
  - !ruby/object:Gem::Version
110
- version: 1.0.0
111
- none: false
98
+ version: 1.1.5
112
99
  - !ruby/object:Gem::Dependency
113
100
  name: i18n
114
- prerelease: false
115
101
  requirement: !ruby/object:Gem::Requirement
116
102
  requirements:
117
- - - ~>
103
+ - - "~>"
118
104
  - !ruby/object:Gem::Version
119
- version: 0.6.0
120
- none: false
105
+ version: 0.6.11
121
106
  type: :runtime
107
+ prerelease: false
122
108
  version_requirements: !ruby/object:Gem::Requirement
123
109
  requirements:
124
- - - ~>
110
+ - - "~>"
125
111
  - !ruby/object:Gem::Version
126
- version: 0.6.0
127
- none: false
112
+ version: 0.6.11
128
113
  - !ruby/object:Gem::Dependency
129
114
  name: activesupport
130
- prerelease: false
131
115
  requirement: !ruby/object:Gem::Requirement
132
116
  requirements:
133
- - - ! '>='
117
+ - - ">="
134
118
  - !ruby/object:Gem::Version
135
- version: 3.1.1
136
- none: false
119
+ version: 3.2.22
137
120
  type: :runtime
121
+ prerelease: false
138
122
  version_requirements: !ruby/object:Gem::Requirement
139
123
  requirements:
140
- - - ! '>='
124
+ - - ">="
141
125
  - !ruby/object:Gem::Version
142
- version: 3.1.1
143
- none: false
126
+ version: 3.2.22
144
127
  - !ruby/object:Gem::Dependency
145
128
  name: simple_oauth
146
- prerelease: false
147
129
  requirement: !ruby/object:Gem::Requirement
148
130
  requirements:
149
- - - ! '>='
131
+ - - "~>"
150
132
  - !ruby/object:Gem::Version
151
- version: 0.1.5
152
- none: false
133
+ version: 0.3.1
153
134
  type: :runtime
135
+ prerelease: false
154
136
  version_requirements: !ruby/object:Gem::Requirement
155
137
  requirements:
156
- - - ! '>='
138
+ - - "~>"
157
139
  - !ruby/object:Gem::Version
158
- version: 0.1.5
159
- none: false
140
+ version: 0.3.1
160
141
  - !ruby/object:Gem::Dependency
161
- name: lukemelia-twitter-stream
162
- prerelease: false
142
+ name: em-twitter
163
143
  requirement: !ruby/object:Gem::Requirement
164
144
  requirements:
165
- - - ~>
145
+ - - "~>"
166
146
  - !ruby/object:Gem::Version
167
- version: 0.1.15
168
- none: false
147
+ version: 0.3.5
169
148
  type: :runtime
149
+ prerelease: false
170
150
  version_requirements: !ruby/object:Gem::Requirement
171
151
  requirements:
172
- - - ~>
152
+ - - "~>"
173
153
  - !ruby/object:Gem::Version
174
- version: 0.1.15
175
- none: false
154
+ version: 0.3.5
176
155
  - !ruby/object:Gem::Dependency
177
156
  name: rspec
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: 3.4.0
162
+ type: :development
178
163
  prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: 3.4.0
169
+ - !ruby/object:Gem::Dependency
170
+ name: byebug
179
171
  requirement: !ruby/object:Gem::Requirement
180
172
  requirements:
181
- - - ~>
173
+ - - "~>"
182
174
  - !ruby/object:Gem::Version
183
- version: 2.6.0
184
- none: false
175
+ version: 2.4.1
185
176
  type: :development
177
+ prerelease: false
186
178
  version_requirements: !ruby/object:Gem::Requirement
187
179
  requirements:
188
- - - ~>
180
+ - - "~>"
189
181
  - !ruby/object:Gem::Version
190
- version: 2.6.0
191
- none: false
182
+ version: 2.4.1
192
183
  - !ruby/object:Gem::Dependency
193
184
  name: ZenTest
194
- prerelease: false
195
185
  requirement: !ruby/object:Gem::Requirement
196
186
  requirements:
197
- - - ! '>='
187
+ - - ">="
198
188
  - !ruby/object:Gem::Version
199
189
  version: '0'
200
- none: false
201
190
  type: :development
191
+ prerelease: false
202
192
  version_requirements: !ruby/object:Gem::Requirement
203
193
  requirements:
204
- - - ! '>='
194
+ - - ">="
205
195
  - !ruby/object:Gem::Version
206
196
  version: '0'
207
- none: false
208
197
  description: Weeter subscribes to a set of twitter users or search terms using Twitter's
209
198
  streaming API, and notifies your app with each new tweet.
210
199
  email:
@@ -215,8 +204,9 @@ executables:
215
204
  extensions: []
216
205
  extra_rdoc_files: []
217
206
  files:
218
- - .gitignore
219
- - .travis.yml
207
+ - ".gitignore"
208
+ - ".ruby-version"
209
+ - ".travis.yml"
220
210
  - Gemfile
221
211
  - LICENSE
222
212
  - README.md
@@ -263,27 +253,26 @@ files:
263
253
  - weeter.gemspec
264
254
  homepage: http://github.com/lukemelia/weeter
265
255
  licenses: []
256
+ metadata: {}
266
257
  post_install_message:
267
258
  rdoc_options: []
268
259
  require_paths:
269
260
  - lib
270
261
  required_ruby_version: !ruby/object:Gem::Requirement
271
262
  requirements:
272
- - - ! '>='
263
+ - - ">="
273
264
  - !ruby/object:Gem::Version
274
265
  version: '0'
275
- none: false
276
266
  required_rubygems_version: !ruby/object:Gem::Requirement
277
267
  requirements:
278
- - - ! '>='
268
+ - - ">="
279
269
  - !ruby/object:Gem::Version
280
270
  version: '0'
281
- none: false
282
271
  requirements: []
283
272
  rubyforge_project: weeter
284
- rubygems_version: 1.8.24
273
+ rubygems_version: 2.4.8
285
274
  signing_key:
286
- specification_version: 3
275
+ specification_version: 4
287
276
  summary: Consume the Twitter stream and notify your app
288
277
  test_files:
289
278
  - spec/spec_helper.rb