eventable 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +32 -3
- data/eventable.gemspec +1 -1
- data/example/example.rb +6 -0
- data/lib/eventable/errors.rb +1 -0
- data/lib/eventable/eventable.rb +19 -9
- data/lib/eventable/version.rb +1 -1
- data/spec/eventable/eventable_spec.rb +42 -0
- metadata +3 -5
- data/_brainstorm/finalizer.rb +0 -48
- data/_brainstorm/splat.rb +0 -27
data/README.markdown
CHANGED
@@ -16,6 +16,19 @@ Eventable will even automatically remove registered listeners when they get garb
|
|
16
16
|
|
17
17
|
Eventable also allows for more fine-grain control than Observable. You can register for specific events instead of just saying, "Hey, let me know when anything changes."
|
18
18
|
|
19
|
+
##Install##
|
20
|
+
|
21
|
+
`$ gem install eventable`
|
22
|
+
|
23
|
+
##Usage Instructions##
|
24
|
+
|
25
|
+
* Include the module
|
26
|
+
* **Important:** If you have an initialize method call `super` as first line (see below). If you don't have an initialize method you don't have to add one. Super is called automatically for you.
|
27
|
+
* Add an event, e.g. `event :your_event`
|
28
|
+
* Fire the event when it should be fired: `fire_event(:your_event)`
|
29
|
+
|
30
|
+
To reiterate you **must** call `super` in your `initialize` method or Eventable won't work and you'll get an error. Eventable needs to create a mutex to make it thread safe, if you don't call `super` the mutex variable won't be created.
|
31
|
+
|
19
32
|
##Examples##
|
20
33
|
This example shows the basics of using Eventable to add an event to a class and listen for that event. (Without threading it's a bit pointless):
|
21
34
|
|
@@ -27,6 +40,9 @@ This example shows the basics of using Eventable to add an event to a class and
|
|
27
40
|
# This is all you have to do to add an event (after you include Eventable)
|
28
41
|
event :stuff_happens
|
29
42
|
|
43
|
+
# There's no initialize method so you do
|
44
|
+
# not have to worry about calling super.
|
45
|
+
|
30
46
|
# don't name your method fire_event, that's taken
|
31
47
|
def do_event
|
32
48
|
puts "firing :stuff_happens"
|
@@ -70,6 +86,12 @@ This example shows you how you might actually use it in a multi-threaded environ
|
|
70
86
|
include Eventable
|
71
87
|
event :stuff_happens
|
72
88
|
event :other_stuff_happens
|
89
|
+
|
90
|
+
def initialize
|
91
|
+
# If you don't call super Eventable will raise an error
|
92
|
+
super # <= VERY important, comment this out to see the error
|
93
|
+
# do your initialize stuff
|
94
|
+
end
|
73
95
|
|
74
96
|
def make_stuff_happen(parent_id)
|
75
97
|
# You handle concurrency however you want, threads or fibers, up to you.
|
@@ -141,16 +163,23 @@ This example shows you how you might actually use it in a multi-threaded environ
|
|
141
163
|
puts "all done"
|
142
164
|
|
143
165
|
|
144
|
-
|
145
166
|
##Version History##
|
146
167
|
|
168
|
+
Ver: 0.1.2
|
169
|
+
|
170
|
+
Design updates/fixes:
|
171
|
+
|
172
|
+
* Renamed most instance variables to help avoid name collisions.
|
173
|
+
* Threadsafe mutex creation. Make sure you call `super` in your class's initialize method!
|
174
|
+
|
147
175
|
**2011.06.10**
|
148
176
|
Ver: 0.1.1
|
149
177
|
|
150
|
-
Features:
|
178
|
+
Features:
|
151
179
|
If events fired specifically returns true and returns false if it can't for whatever reason (e.g. no listeners registered).
|
152
180
|
|
153
|
-
Fixes:
|
181
|
+
Fixes:
|
182
|
+
|
154
183
|
* Throws error if event is fired and no listeners are registered (Thanks for bug report Benjamin Yu)
|
155
184
|
* Workaround for RubyGems pre 1.8.3 date bug that locks up all of RubyGems (Thanks again Benjamin Yu)
|
156
185
|
|
data/eventable.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.email = ["mikbe.tk@gmail.com"]
|
14
14
|
s.homepage = "http://mikbe.tk/projects#eventable"
|
15
15
|
s.summary = %q{An incredibly simple and easy to use event mixin module.}
|
16
|
-
s.description = %q{Provides an easy to use and understand event model. If you want a simple, light-weight way to add events to your classes
|
16
|
+
s.description = %q{Provides an easy to use and understand event model. If you want a simple, light-weight way to add events to your classes this is the solution for you.}
|
17
17
|
|
18
18
|
s.add_development_dependency('rspec', "~>2.6")
|
19
19
|
|
data/example/example.rb
CHANGED
@@ -6,6 +6,12 @@ class EventedClass
|
|
6
6
|
event :stuff_happens
|
7
7
|
event :other_stuff_happens
|
8
8
|
|
9
|
+
def initialize
|
10
|
+
# If you don't call super Eventable will raise an error
|
11
|
+
super # <= VERY important, comment this out to see the error
|
12
|
+
# do your initialize stuff
|
13
|
+
end
|
14
|
+
|
9
15
|
def make_stuff_happen(parent_id)
|
10
16
|
# You handle concurrency however you want, threads or fibers, up to you.
|
11
17
|
Thread.new{
|
data/lib/eventable/errors.rb
CHANGED
data/lib/eventable/eventable.rb
CHANGED
@@ -15,13 +15,13 @@ module Eventable
|
|
15
15
|
|
16
16
|
# register an event
|
17
17
|
def event(event_name)
|
18
|
-
@
|
19
|
-
@
|
18
|
+
@eventable_events ||= []
|
19
|
+
@eventable_events << event_name unless @eventable_events.include? event_name
|
20
20
|
end
|
21
21
|
|
22
22
|
# returns a list of registered events
|
23
23
|
def events
|
24
|
-
@
|
24
|
+
@eventable_events.clone
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
@@ -30,11 +30,15 @@ module Eventable
|
|
30
30
|
self.class.events
|
31
31
|
end
|
32
32
|
|
33
|
+
def initialize
|
34
|
+
@eventable_mutex = Mutex.new
|
35
|
+
end
|
36
|
+
|
33
37
|
# When the event happens the class where it happens runs this
|
34
38
|
def fire_event(event, *return_value, &block)
|
35
39
|
# We don't want the callback array being altered when we're trying to read it
|
36
|
-
|
37
|
-
@
|
40
|
+
check_mutex
|
41
|
+
@eventable_mutex.synchronize {
|
38
42
|
|
39
43
|
return false unless @callbacks && @callbacks[event] && !@callbacks[event].empty?
|
40
44
|
|
@@ -61,8 +65,8 @@ module Eventable
|
|
61
65
|
raise Errors::UnknownEvent unless events.include? event
|
62
66
|
|
63
67
|
# Make access to the callback cache threadsafe
|
64
|
-
|
65
|
-
@
|
68
|
+
check_mutex
|
69
|
+
@eventable_mutex.synchronize {
|
66
70
|
@callbacks ||= {}
|
67
71
|
@callbacks[event] ||= {}
|
68
72
|
|
@@ -84,8 +88,8 @@ module Eventable
|
|
84
88
|
|
85
89
|
# Allows objects to stop listening to events
|
86
90
|
def unregister_for_event(args)
|
87
|
-
|
88
|
-
@
|
91
|
+
check_mutex
|
92
|
+
@eventable_mutex.synchronize {
|
89
93
|
event = args[:event]
|
90
94
|
return unless @callbacks && @callbacks[event]
|
91
95
|
|
@@ -98,6 +102,12 @@ module Eventable
|
|
98
102
|
}
|
99
103
|
end
|
100
104
|
|
105
|
+
private
|
106
|
+
|
107
|
+
def check_mutex
|
108
|
+
raise Errors::SuperNotCalledInInitialize, "You must include super in your class's initialize method" unless @eventable_mutex
|
109
|
+
end
|
110
|
+
|
101
111
|
# Wrapper for the finalize proc. You have to call a method
|
102
112
|
# from define_finalizer; you can't just put this proc in there.
|
103
113
|
def unregister_finalizer(event, listener_id, callback)
|
data/lib/eventable/version.rb
CHANGED
@@ -7,6 +7,48 @@ describe Eventable do
|
|
7
7
|
@listener = ListenClass.new
|
8
8
|
end
|
9
9
|
|
10
|
+
context "when inheriting eventable" do
|
11
|
+
|
12
|
+
it "should not raise an error if class has no initialize method" do
|
13
|
+
lambda{
|
14
|
+
class Foo
|
15
|
+
include Eventable
|
16
|
+
event :do_stuff
|
17
|
+
end
|
18
|
+
f = Foo.new
|
19
|
+
f.fire_event(:do_stuff)
|
20
|
+
}.should_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not raise an error if super is called in initialize" do
|
24
|
+
lambda{
|
25
|
+
class Foo
|
26
|
+
include Eventable
|
27
|
+
event :do_stuff
|
28
|
+
def initialize
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
f = Foo.new
|
33
|
+
f.fire_event(:do_stuff)
|
34
|
+
}.should_not raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should raise an error if super is not called in initialize" do
|
38
|
+
lambda{
|
39
|
+
class Foo
|
40
|
+
include Eventable
|
41
|
+
event :do_stuff
|
42
|
+
def initialize
|
43
|
+
end
|
44
|
+
end
|
45
|
+
f = Foo.new
|
46
|
+
f.fire_event(:do_stuff)
|
47
|
+
}.should raise_error(Eventable::Errors::SuperNotCalledInInitialize)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
10
52
|
context "when specifiying an event" do
|
11
53
|
|
12
54
|
it 'should list the event from the class' do
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: eventable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mike Bethany
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-18 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -23,7 +23,7 @@ dependencies:
|
|
23
23
|
version: "2.6"
|
24
24
|
type: :development
|
25
25
|
version_requirements: *id001
|
26
|
-
description: Provides an easy to use and understand event model. If you want a simple, light-weight way to add events to your classes
|
26
|
+
description: Provides an easy to use and understand event model. If you want a simple, light-weight way to add events to your classes this is the solution for you.
|
27
27
|
email:
|
28
28
|
- mikbe.tk@gmail.com
|
29
29
|
executables: []
|
@@ -38,8 +38,6 @@ files:
|
|
38
38
|
- LICENSE.txt
|
39
39
|
- README.markdown
|
40
40
|
- Rakefile
|
41
|
-
- _brainstorm/finalizer.rb
|
42
|
-
- _brainstorm/splat.rb
|
43
41
|
- autotest/discover.rb
|
44
42
|
- eventable.gemspec
|
45
43
|
- example/example.rb
|
data/_brainstorm/finalizer.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# how does the finalizer work?
|
2
|
-
# I need to unregister the object when the finalizer
|
3
|
-
# is called but will it be called if I'm holding a reference to it?
|
4
|
-
|
5
|
-
class Foo
|
6
|
-
def self.finalize(object_id)
|
7
|
-
proc {puts "finalize me: #{object_id}"}
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
ObjectSpace.define_finalizer( self, self.class.finalize(self.object_id))
|
12
|
-
end
|
13
|
-
|
14
|
-
def hello
|
15
|
-
puts "hello: #{self.object_id}"
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
@y = []
|
21
|
-
def external_finalizer(object_id)
|
22
|
-
proc do
|
23
|
-
puts "external finalizer: #{object_id}"
|
24
|
-
@y.delete(object_id)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
(0..4).each do |i|
|
29
|
-
f = Foo.new
|
30
|
-
ObjectSpace.define_finalizer(f, external_finalizer(f.object_id))
|
31
|
-
GC.start
|
32
|
-
@y << f.object_id
|
33
|
-
puts "i: #{i}"
|
34
|
-
end
|
35
|
-
|
36
|
-
@y.each do |object_id|
|
37
|
-
begin
|
38
|
-
obj = ObjectSpace._id2ref(object_id)
|
39
|
-
obj.hello
|
40
|
-
rescue RangeError => e
|
41
|
-
puts "das error: #{!!e.message.match(/is recycled object/)}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
puts "all done : note the finalizers firing AFTER this..."
|
46
|
-
|
47
|
-
|
48
|
-
|
data/_brainstorm/splat.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
def foo(a,b,c)
|
2
|
-
puts
|
3
|
-
puts "foo"
|
4
|
-
puts "a:#{a}; b: #{b}; c: #{c};"
|
5
|
-
end
|
6
|
-
|
7
|
-
def foo_explicit_block(a, b, c, &block)
|
8
|
-
puts
|
9
|
-
puts "foo_with_block"
|
10
|
-
puts "a:#{a}; b: #{b}; c: #{c};"
|
11
|
-
puts block.inspect
|
12
|
-
end
|
13
|
-
|
14
|
-
def foo_implied_block(a,b,c)
|
15
|
-
puts
|
16
|
-
puts "foo_implied_block"
|
17
|
-
puts "a:#{a}; b: #{b}; c: #{c};"
|
18
|
-
yield [a,b,c]
|
19
|
-
end
|
20
|
-
|
21
|
-
def bar(*args, &block)
|
22
|
-
foo(*args, &block)
|
23
|
-
foo_explicit_block(*args, &block)
|
24
|
-
foo_implied_block(*args, &block)
|
25
|
-
end
|
26
|
-
|
27
|
-
bar(1,2,3) {|x| puts x}
|