floormanager 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -19,7 +19,7 @@ See the examples for more advanced usage.
19
19
 
20
20
  == TODO
21
21
 
22
- * Write the tests and examples
22
+ * Write the tests
23
23
 
24
24
  == Copyright
25
25
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
@@ -0,0 +1,61 @@
1
+ require 'httparty'
2
+ require 'floormanager'
3
+
4
+ # = Example Twitter client with robust concurrent search.
5
+ #
6
+ # Will handle rate limiting and errors gracefully, optionally
7
+ # retrying for a number of times before failing.
8
+ #
9
+ # == Usage:
10
+ #
11
+ # twitter = Twitter.new(:concurrency => 10, :retries => 5, :retry_delay => 10)
12
+ # results = twitter.concurrent_search(['ruby', 'httparty', 'floormanager'])
13
+ # results.each do |search_string, tweets|
14
+ # unless tweets.failed?
15
+ # puts tweets.inspect
16
+ # end
17
+ # end
18
+
19
+ class Twitter
20
+ include HTTParty
21
+
22
+ def initialize(options={})
23
+ @concurrency = options[:concurrency] || 20
24
+ @retries = options[:retries] || 0
25
+ @retry_delay = options[:retry_delay] || 2.0
26
+ end
27
+ attr_accessor :concurrency, :retries, :retry_delay
28
+
29
+ base_uri 'http://search.twitter.com'
30
+ default_params :rpp => '100'
31
+ format :json
32
+
33
+ def concurrent_search(query_strings)
34
+ queue = FloorManager::Queue.new(query_strings)
35
+ workers = FloorManager::Workers.new(queue)
36
+ workers.perform(:threads => @concurrency) do |query_string|
37
+ retries = 0
38
+ begin
39
+ results = self.class.get('/search.json', :query => {:q => "\"#{query_string}\""})
40
+ # Handle rate limiting
41
+ if results.code == 420
42
+ if result.headers['retry-after']
43
+ retry_delay = result.headers['retry-after'].first.to_i
44
+ else
45
+ retry_delay = 60
46
+ end
47
+ workers.halt(retry_delay) # Halt all workers for the retry delay
48
+ retry
49
+ else
50
+ results['results']
51
+ end
52
+ rescue Exception => error
53
+ if retries < @retries # If at first you don't succeed, try and try again
54
+ retries += 1
55
+ sleep(@retry_delay) and retry
56
+ end
57
+ workers.failed(error) # Return a failed result after 5 tries
58
+ end
59
+ end
60
+ end
61
+ end
data/floormanager.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{floormanager}
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Inge J\303\270rgensen"]
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  "README.rdoc",
24
24
  "Rakefile",
25
25
  "VERSION",
26
+ "examples/twitter.rb",
26
27
  "floormanager.gemspec",
27
28
  "lib/floormanager.rb",
28
29
  "lib/floormanager/queue.rb",
@@ -40,7 +41,8 @@ Gem::Specification.new do |s|
40
41
  s.summary = %q{Handle threaded workers like a champ}
41
42
  s.test_files = [
42
43
  "spec/floormanager_spec.rb",
43
- "spec/spec_helper.rb"
44
+ "spec/spec_helper.rb",
45
+ "examples/twitter.rb"
44
46
  ]
45
47
 
46
48
  if s.respond_to? :specification_version then
@@ -1,22 +1,16 @@
1
1
  module FloorManager
2
2
  class Result < FloorManager::BasicObject
3
3
  attr_accessor :result, :state
4
- attr_reader :delegate
5
4
 
6
- def initialize(delegate, result, state=States::SUCCESS)
7
- @delegate = delegate
5
+ def initialize(result, state=States::SUCCESS)
8
6
  @result = result
9
7
  @state = state
10
8
  end
11
9
 
12
10
  def method_missing(name, *args, &block)
13
- @delegate.send(name, *args, &block)
11
+ @result.send(name, *args, &block)
14
12
  end
15
13
 
16
- def state
17
- @state
18
- end
19
-
20
14
  def failed?
21
15
  @state == States::FAILED
22
16
  end
@@ -15,7 +15,7 @@ module FloorManager
15
15
  until queue.done?
16
16
  if item = checkout
17
17
  result = yield(item)
18
- result = Result.new(result, result, (result.state rescue States::SUCCESS))
18
+ result = Result.new(result, (result.state rescue States::SUCCESS))
19
19
  checkin(item, result, result.state)
20
20
  else
21
21
  Thread.pass
@@ -28,11 +28,11 @@ module FloorManager
28
28
  end
29
29
 
30
30
  def checkout
31
- @mutex.synchronize{@queue.checkout}
31
+ synchronize{@queue.checkout}
32
32
  end
33
33
 
34
34
  def checkin(*args)
35
- @mutex.synchronize{@queue.checkin(*args)}
35
+ synchronize{@queue.checkin(*args)}
36
36
  end
37
37
 
38
38
  def synchronize
@@ -40,15 +40,19 @@ module FloorManager
40
40
  end
41
41
  alias :exclusively :synchronize
42
42
 
43
+ def halt(time)
44
+ synchronize{sleep(time)}
45
+ end
46
+
43
47
  def result(result, state=States::SUCCESS)
44
- Result.new(result, result, state)
48
+ Result.new(result, state)
45
49
  end
46
50
 
47
51
  def success(result)
48
52
  result(result, States::SUCCESS)
49
53
  end
50
54
 
51
- def fail(result)
55
+ def failed(result=nil)
52
56
  result(result, States::FAILED)
53
57
  end
54
58
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 0
9
- version: 0.2.0
8
+ - 1
9
+ version: 0.2.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Inge J\xC3\xB8rgensen"
@@ -47,6 +47,7 @@ files:
47
47
  - README.rdoc
48
48
  - Rakefile
49
49
  - VERSION
50
+ - examples/twitter.rb
50
51
  - floormanager.gemspec
51
52
  - lib/floormanager.rb
52
53
  - lib/floormanager/queue.rb
@@ -89,3 +90,4 @@ summary: Handle threaded workers like a champ
89
90
  test_files:
90
91
  - spec/floormanager_spec.rb
91
92
  - spec/spec_helper.rb
93
+ - examples/twitter.rb