fire_poll 1.0.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.
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ doc
5
+ .yardoc
@@ -0,0 +1 @@
1
+ --markup markdown --readme README.md
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fire_poll.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ (the MIT license)
2
+ Copyright 2011 by Atomic Object
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
@@ -0,0 +1,77 @@
1
+ Description
2
+ ===========
3
+ `FirePoll.poll` is a method for knowing when something is ready. When your block yields true, execution continues. When your block yields false, poll keeps trying until it gives up and raises an error.
4
+
5
+ Examples
6
+ --------
7
+ I'm writing a system test for a web application. My test simulates uploading a large file, which isn't instantaneous. I need to know when the file has finished uploading so I can start making assertions.
8
+ def wait_for_file(filename)
9
+ FirePoll.poll do
10
+ FileStore.file_ready?(filename)
11
+ end
12
+ end
13
+
14
+ def test_files_are_saved
15
+ upload_file "blue.txt"
16
+ assert_nothing_raised { wait_for_file "blue.txt" }
17
+ assert_equal "blue is the best color", read_saved_file("blue.txt")
18
+ end
19
+
20
+ I just fired up a fake web service to respond to my client application. I want to know when the service is online before I start the client tests. I'm willing to wait 10 seconds before giving up.
21
+ class TestHelper
22
+ include FirePoll
23
+
24
+ def wait_for_server
25
+ poll("server didn't come online quick enough", 10) do
26
+ begin
27
+ TCPSocket.new(SERVER_IP, SERVER_PORT)
28
+ true
29
+ rescue Exception
30
+ false
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ Usage
37
+ -----
38
+ Pass a block to `FirePoll.poll`. Return `true` when your need is met. Return `false` when it isn't. `poll` will raise an exception after too many failed attempts.
39
+
40
+ The `poll` method takes two optional parameters: a specific message to raise on failure and the number of seconds to wait. By default, `poll` will try for two seconds. `poll` runs every tenth of a second.
41
+ FirePoll.poll { ... } # raises an error after two seconds
42
+ FirePoll.poll("new data hasn't arrived from the device") { ... } # raises a friendlier error message
43
+ FirePoll.poll("waited for too long!", 7) { ... } # raises an error after seven seconds with a specific error message
44
+ FirePoll.poll(nil, 88) { ... } # raises an error after eighty-eight seconds with the generic error message
45
+
46
+ The `FirePoll` module may be mixed into your class; this makes it a little faster to type the method name.
47
+ class TestHelper
48
+ include FirePoll
49
+ def helper_method
50
+ poll do
51
+ ...
52
+ end
53
+ end
54
+ end
55
+
56
+ Implementation
57
+ --------------
58
+ `FirePoll.poll`'s implementation isn't partcilarly accurate with respect to time. The method will run your block (number of seconds * 10) times. It sleeps for a tenth of a second between attempts. Since it doesn't keep track of time, if your timing needs require accuracy, you'll need to look elsewhere.
59
+
60
+ Motivation
61
+ ----------
62
+ We frequently need to wait for something to happen - usually in tests. And we usually don't have any strict time requirements - as long as something happens in _about_ [x] seconds, we're happy. `FirePoll.poll` meets our need nicely.
63
+
64
+ On a related note, `Timer::Timeout` is known to be [busted](http://ph7spot.com/musings/system-timer) and [unreliable](http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html). `FirePoll.poll` doesn't employ any threads or timers, so we don't worry about whether it will work or not.
65
+
66
+ TODO
67
+ ----
68
+ * Nice to have: hook into Test::Unit and RSpec instead of raising a Ruby exception
69
+ * Nice to have: pass options as a hash instead of two parameters. This will look nice with Ruby 1.9's hash syntax.
70
+
71
+ Authors
72
+ =======
73
+ * Matt Fletcher (fletcher@atomicobject.com)
74
+ * David Crosby (crosby@atomicobject.com)
75
+ * Micah Alles (alles@atomicobject.com)
76
+ * © 2011 [Atomic Object](http://www.atomicobject.com/)
77
+ * More Atomic Object [open source](http://www.atomicobject.com/pages/Software+Commons) projects
@@ -0,0 +1,19 @@
1
+ require "bundler"
2
+ require "rake/testtask"
3
+ require "rake/clean"
4
+ require "yard"
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.test_files = FileList["test/test*.rb"]
9
+ end
10
+
11
+ YARD::Rake::YardocTask.new do |t|
12
+ t.files = %w[ lib/fire_poll.rb ]
13
+ end
14
+
15
+ CLEAN.include "pkg"
16
+ CLEAN.include "doc"
17
+ CLEAN.include ".yardoc"
18
+
19
+ task :default => :test
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fire_poll/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fire_poll"
7
+ s.version = FirePoll::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Matt Fletcher", "David Crosby", "Micah Alles"]
10
+ s.email = ["fletcher@atomicobject.com", "crosby@atomicobject.com", "alles@atomicobject.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Simple, brute-force method for knowing when something is ready}
13
+ s.description = %q{Simple, brute-force method for knowing when something is ready}
14
+
15
+ s.rubyforge_project = "fire_poll"
16
+
17
+ s.add_development_dependency("bundler", ">= 1.0.0")
18
+ s.add_development_dependency("rake", ">= 0.8.0")
19
+ s.add_development_dependency("yard", "~> 0.6.4")
20
+ s.add_development_dependency("bluecloth", "~> 2.0.11")
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,22 @@
1
+ # see the {file:README.md README file} for instruction on how to use this library
2
+ module FirePoll
3
+ # @param [String] msg a custom message raised when polling fails
4
+ # @param [Numeric] seconds number of seconds to poll
5
+ # @yield a block that determines whether polling should continue
6
+ # @yieldreturn false if polling should continue
7
+ # @yieldreturn true if polling is complete
8
+ # @raise [RuntimeError] when polling fails
9
+ # @return [NilClass]
10
+ # @since 1.0.0
11
+ def poll(msg=nil, seconds=2.0)
12
+ (seconds * 10).to_i.times do
13
+ return if yield
14
+ sleep 0.1
15
+ end
16
+ msg ||= "polling failed after #{seconds} seconds"
17
+ raise msg
18
+ nil
19
+ end
20
+
21
+ module_function :poll
22
+ end
@@ -0,0 +1,3 @@
1
+ module FirePoll
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,67 @@
1
+ require "test/unit"
2
+ require "fire_poll"
3
+
4
+ class FirePollTest < Test::Unit::TestCase
5
+ def test_raises_when_block_does_not_yield_true
6
+ assert_raise RuntimeError do
7
+ FirePoll.poll { false }
8
+ end
9
+ end
10
+
11
+ def test_does_not_raise_when_block_yields_true
12
+ assert_nothing_raised do
13
+ FirePoll.poll { true }
14
+ end
15
+ end
16
+
17
+ def test_does_not_raise_when_block_eventually_yields_true
18
+ assert_nothing_raised do
19
+ count = 0
20
+ FirePoll.poll do
21
+ count += 1
22
+ count > 5 ? true : false
23
+ end
24
+ end
25
+ end
26
+
27
+ def test_can_take_an_optional_number_of_seconds_to_poll
28
+ # default 2 seconds = 20 calls to the block
29
+ assert_nothing_raised do
30
+ count1 = 0
31
+ FirePoll.poll do
32
+ count1 += 1
33
+ count1 > 11 ? true : false
34
+ end
35
+ end
36
+
37
+ # 1 second = 10 calls to the block
38
+ assert_raise RuntimeError do
39
+ count = 0
40
+ FirePoll.poll(nil, 1) do
41
+ count += 1
42
+ count > 11 ? true : false
43
+ end
44
+ end
45
+ end
46
+
47
+ def test_can_take_an_optional_message
48
+ # anyone know a better way to do this with straight-up Test::Unit?
49
+ begin
50
+ FirePoll.poll("custom message") { false }
51
+ rescue RuntimeError => ex
52
+ assert_equal "custom message", ex.message
53
+ return
54
+ end
55
+ flunk "should have raised"
56
+ end
57
+ end
58
+
59
+ class TestFirePollMixin < Test::Unit::TestCase
60
+ include FirePoll
61
+
62
+ def test_can_be_mixed_in
63
+ assert_nothing_raised do
64
+ poll { true }
65
+ end
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fire_poll
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Matt Fletcher
13
+ - David Crosby
14
+ - Micah Alles
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-02-23 00:00:00 -05:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: bundler
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 0
47
+ - 8
48
+ - 0
49
+ version: 0.8.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: yard
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ - 6
63
+ - 4
64
+ version: 0.6.4
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: bluecloth
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 2
77
+ - 0
78
+ - 11
79
+ version: 2.0.11
80
+ type: :development
81
+ version_requirements: *id004
82
+ description: Simple, brute-force method for knowing when something is ready
83
+ email:
84
+ - fletcher@atomicobject.com
85
+ - crosby@atomicobject.com
86
+ - alles@atomicobject.com
87
+ executables: []
88
+
89
+ extensions: []
90
+
91
+ extra_rdoc_files: []
92
+
93
+ files:
94
+ - .gitignore
95
+ - .yardopts
96
+ - Gemfile
97
+ - LICENSE
98
+ - README.md
99
+ - Rakefile
100
+ - fire_poll.gemspec
101
+ - lib/fire_poll.rb
102
+ - lib/fire_poll/version.rb
103
+ - test/test_fire_poll.rb
104
+ has_rdoc: true
105
+ homepage: ""
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options: []
110
+
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ requirements: []
130
+
131
+ rubyforge_project: fire_poll
132
+ rubygems_version: 1.3.7
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Simple, brute-force method for knowing when something is ready
136
+ test_files:
137
+ - test/test_fire_poll.rb