event_utils 0.2.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.
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +34 -0
- data/Rakefile +48 -0
- data/VERSION.yml +4 -0
- data/event_utils.gemspec +50 -0
- data/lib/event_utils.rb +7 -0
- data/lib/event_utils/evented_loop.rb +93 -0
- data/test/deferred_loop_test.rb +83 -0
- data/test/test_helper.rb +11 -0
- metadata +66 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Paolo Negri
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= event_utils
|
2
|
+
|
3
|
+
EventUtils is meant to provide modules and classes to help building services
|
4
|
+
on top of EventMachine without having to cope with some of the mechnics of
|
5
|
+
eventmachine itself.
|
6
|
+
|
7
|
+
the first implemented facility is EventUtils::DeferredLoop
|
8
|
+
|
9
|
+
it makes possible to perform action on groups of deferrable objects in an
|
10
|
+
intuitive way, and without having to take care of starting/stopping the
|
11
|
+
EventMachine reactor
|
12
|
+
|
13
|
+
example:
|
14
|
+
|
15
|
+
d1 and d2 are two deferrables
|
16
|
+
and we want to compare them but the comparaison is only feasible when
|
17
|
+
d1 and d2 have both deferred status set.
|
18
|
+
|
19
|
+
In this case the code will look like
|
20
|
+
|
21
|
+
require 'event_utils'
|
22
|
+
include EventUtils
|
23
|
+
|
24
|
+
in_deferred_loop do
|
25
|
+
waiting_for d1, d2 do
|
26
|
+
d1 > d2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Check http://assertbuggy.blogspot.com for further informations and tutorials
|
31
|
+
|
32
|
+
== Copyright
|
33
|
+
|
34
|
+
Copyright (c) 2009 Paolo Negri. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "event_utils"
|
8
|
+
gem.summary = %Q{provides various facilities to help building tools on top of eventmachine}
|
9
|
+
gem.email = "hungryblank@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/hungryblank/event_utils"
|
11
|
+
gem.authors = ["Paolo Negri"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'event_utils'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README*')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = false
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/*_test.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
task :default => :test
|
data/VERSION.yml
ADDED
data/event_utils.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{event_utils}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Paolo Negri"]
|
12
|
+
s.date = %q{2010-02-20}
|
13
|
+
s.email = %q{hungryblank@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION.yml",
|
24
|
+
"event_utils.gemspec",
|
25
|
+
"lib/event_utils.rb",
|
26
|
+
"lib/event_utils/evented_loop.rb",
|
27
|
+
"test/deferred_loop_test.rb",
|
28
|
+
"test/test_helper.rb"
|
29
|
+
]
|
30
|
+
s.homepage = %q{http://github.com/hungryblank/event_utils}
|
31
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.3.5}
|
34
|
+
s.summary = %q{provides various facilities to help building tools on top of eventmachine}
|
35
|
+
s.test_files = [
|
36
|
+
"test/test_helper.rb",
|
37
|
+
"test/deferred_loop_test.rb"
|
38
|
+
]
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
45
|
+
else
|
46
|
+
end
|
47
|
+
else
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/event_utils.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module EventUtils
|
2
|
+
|
3
|
+
class DeferredChildFailure < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class DeferredLoop
|
7
|
+
|
8
|
+
def self.main_loop
|
9
|
+
@main_loop ||= new(:main)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
attr_accessor :success, :failure
|
14
|
+
|
15
|
+
include EM::Deferrable
|
16
|
+
|
17
|
+
def initialize(main=false)
|
18
|
+
self.class.main_loop.wait_for(self) unless main
|
19
|
+
@success, @failure = 0, 0
|
20
|
+
@waiting_for = []
|
21
|
+
end
|
22
|
+
|
23
|
+
#takes a list of deferrables to wait for before executing the callback
|
24
|
+
def waiting_for(*deferrables, &block)
|
25
|
+
deferrables.each { |d| wait_for(d) }.size
|
26
|
+
callback { block.call } if block_given?
|
27
|
+
errback { raise DeferredChildFailure, "#{failure} deferred entities failed" }
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
#callback used by deferrables the loop is waiting for, it increases failure or
|
32
|
+
#success depending by the child outcome
|
33
|
+
def child_returned(outcome)
|
34
|
+
send(outcome.to_s + '=', send(outcome) + 1)
|
35
|
+
terminate if complete?
|
36
|
+
end
|
37
|
+
|
38
|
+
#add a deferrable to the list of deferrables to wait for
|
39
|
+
def wait_for(deferrable)
|
40
|
+
@waiting_for << deferrable
|
41
|
+
deferrable.callback { self.child_returned :success }
|
42
|
+
deferrable.errback { self.child_returned :failure }
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def complete?
|
48
|
+
@waiting_for.size == success + failure
|
49
|
+
end
|
50
|
+
|
51
|
+
#sets the deferred status depending by outcomes of children
|
52
|
+
#it fails if one or more children failed
|
53
|
+
def terminate
|
54
|
+
failure == 0 ? self.succeed : self.fail
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
#Wraps the clode in the provided block in an EM loop if needed
|
60
|
+
#
|
61
|
+
# in_deferred_loop do
|
62
|
+
# your code using deferrables here
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
def in_deferred_loop(&block)
|
66
|
+
drive_reactor = !EM.reactor_running?
|
67
|
+
if drive_reactor
|
68
|
+
EM.run do
|
69
|
+
DeferredLoop.main_loop.callback { EM.stop }
|
70
|
+
DeferredLoop.main_loop.errback { EM.stop }
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
else
|
74
|
+
yield
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#waits until all the deferrables have the deferred status set and then
|
79
|
+
#executes the code in the provided block
|
80
|
+
#
|
81
|
+
# in_deferred_loop do
|
82
|
+
# waiting_for deferrable_1, deferrable_2, ..., deferrable_n do
|
83
|
+
# code that needs all the deferrable deferred status set here
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
def waiting_for(*deferrables, &block)
|
88
|
+
deferred_loop = DeferredLoop.new
|
89
|
+
deferred_loop.waiting_for(*deferrables, &block)
|
90
|
+
deferred_loop
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
include EventUtils
|
4
|
+
|
5
|
+
class DeferredLoopTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
should "add callback end errback to deferrables it's waiting for" do
|
8
|
+
deferrable = Mocha::Mock.new
|
9
|
+
deferrable.expects(:callback)
|
10
|
+
deferrable.expects(:errback)
|
11
|
+
deferred_loop = DeferredLoop.new
|
12
|
+
deferred_loop.wait_for deferrable
|
13
|
+
end
|
14
|
+
|
15
|
+
should "evaluate completion on child returned" do
|
16
|
+
deferred_loop = DeferredLoop.new
|
17
|
+
deferred_loop.expects(:complete?)
|
18
|
+
deferred_loop.child_returned(:success)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "complete when number of success + failures equal waiting for" do
|
22
|
+
deferred_loop = DeferredLoop.new
|
23
|
+
deferred_loop.instance_variable_set('@waiting_for', [1, 2, 3])
|
24
|
+
deferred_loop.success = 2
|
25
|
+
assert !deferred_loop.send(:complete?)
|
26
|
+
deferred_loop.failure = 1
|
27
|
+
assert deferred_loop.send(:complete?)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "increase success and failure on child_returned" do
|
31
|
+
deferred_loop = DeferredLoop.new
|
32
|
+
success, failure = deferred_loop.success, deferred_loop.failure
|
33
|
+
deferred_loop.child_returned(:success)
|
34
|
+
assert_equal success + 1, deferred_loop.success
|
35
|
+
assert_equal failure, deferred_loop.failure
|
36
|
+
deferred_loop.child_returned(:failure)
|
37
|
+
assert_equal failure + 1, deferred_loop.failure
|
38
|
+
end
|
39
|
+
|
40
|
+
should "fail if there are failures" do
|
41
|
+
deferred_loop = DeferredLoop.new
|
42
|
+
deferred_loop.instance_variable_set('@waiting_for', [1])
|
43
|
+
deferred_loop.child_returned(:failure)
|
44
|
+
deferred_loop.expects(:fail)
|
45
|
+
deferred_loop.send(:terminate)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "succeed if there aren't failures" do
|
49
|
+
deferred_loop = DeferredLoop.new
|
50
|
+
deferred_loop.instance_variable_set('@waiting_for', [1])
|
51
|
+
deferred_loop.child_returned(:success)
|
52
|
+
deferred_loop.expects(:succeed)
|
53
|
+
deferred_loop.send(:terminate)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "add callback to main loop when EM reactor is not running" do
|
57
|
+
EM.expects(:run)
|
58
|
+
main_loop = Mocha::Mock.new
|
59
|
+
DeferredLoop.stubs(:main_loop).returns(main_loop)
|
60
|
+
main_loop.expects(:callback)
|
61
|
+
in_deferred_loop {}
|
62
|
+
end
|
63
|
+
|
64
|
+
should "wait for all the deferrables passed to waiting for" do
|
65
|
+
EM.stubs(:reactor_running?).returns(true)
|
66
|
+
ev_loop = DeferredLoop.new
|
67
|
+
a = 1
|
68
|
+
b = 2
|
69
|
+
ev_loop.expects(:wait_for).with(a)
|
70
|
+
ev_loop.expects(:wait_for).with(b)
|
71
|
+
ev_loop.waiting_for a, b
|
72
|
+
end
|
73
|
+
|
74
|
+
should "instantiate a new loop on class waiting_for" do
|
75
|
+
a = b = nil
|
76
|
+
l = lambda { 'bla' }
|
77
|
+
deferred_loop = Mocha::Mock.new
|
78
|
+
DeferredLoop.expects(:new).returns(deferred_loop)
|
79
|
+
deferred_loop.expects(:waiting_for).with(a, b, l)
|
80
|
+
EventUtils.waiting_for(a, b, l)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: event_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paolo Negri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-20 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: hungryblank@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- .gitignore
|
27
|
+
- LICENSE
|
28
|
+
- README.rdoc
|
29
|
+
- Rakefile
|
30
|
+
- VERSION.yml
|
31
|
+
- event_utils.gemspec
|
32
|
+
- lib/event_utils.rb
|
33
|
+
- lib/event_utils/evented_loop.rb
|
34
|
+
- test/deferred_loop_test.rb
|
35
|
+
- test/test_helper.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://github.com/hungryblank/event_utils
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --charset=UTF-8
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: provides various facilities to help building tools on top of eventmachine
|
64
|
+
test_files:
|
65
|
+
- test/test_helper.rb
|
66
|
+
- test/deferred_loop_test.rb
|