weeter 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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