eventable 0.1.0.beta1 → 0.1.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -8,7 +8,9 @@ Provides an easy to use and understand event model. Other systems did way too mu
8
8
 
9
9
  If you want a simple way to add events to your classes without a bunch of other unrelated IO stuff this is the solution for you. (If you want to monitor IO events check out EventMachine)
10
10
 
11
- You don't have to worry about memory leaks either because Eventable only make a reference to the listening object when it needs to talk to it then it disposes of that reference. Best of all it will automatically remove registered listeners when they get garbage collected.
11
+ You might be saying, "What about Observable? Why not just use that?" The problem with observable is that it saves a reference to the observing object. If you drop and add a bunch of them you've got the potential for a huge memory leak. With Eventable you don't have to worry about memory leaks because Eventable only make a reference to the listening object when it needs to talk to it and when it's done it disposes of that reference. Eventable will even automatically remove registered listeners when they get garbage collected. You can set up a listener and not worry about removing your event hook yourself, it's done for you.
12
+
13
+ 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."
12
14
 
13
15
  Eventable couldn't be easier to use.
14
16
 
@@ -31,10 +31,19 @@ module Eventable
31
31
  # When the event happens the class where it happens runs this
32
32
  def fire_event(event, *return_value, &block)
33
33
  return false unless @callbacks[event] && !@callbacks[event].empty?
34
- @callbacks[event].each do |listener_id, callbacks|
35
- listener = ObjectSpace._id2ref(listener_id)
36
- callbacks.each {|callback| listener.send callback, *return_value, &block}
37
- end
34
+
35
+ # We don't want the callback array being altered when we're trying to read it
36
+ @mutex.synchronize{
37
+ @callbacks[event].each do |listener_id, callbacks|
38
+ begin
39
+ listener = ObjectSpace._id2ref(listener_id)
40
+ callbacks.each {|callback| listener.send callback, *return_value, &block}
41
+ rescue RangeError => re
42
+ # Don't bubble up a missing recycled object, I don't care if it's not there, I just won't call it
43
+ raise re unless re.message.match(/is recycled object/)
44
+ end
45
+ end
46
+ }
38
47
  end
39
48
 
40
49
  # Allows an object to listen for an event and have a callback run when the event happens
@@ -45,23 +54,27 @@ module Eventable
45
54
 
46
55
  event = args[:event]
47
56
  raise Errors::UnknownEvent unless events.include? event
48
- @callbacks ||= {}
49
- @callbacks[event] ||= {}
50
57
 
51
- listener = args[:listener]
52
- listener_id = listener.object_id
53
- callback = args[:callback]
58
+ # Make access to the callback cache threadsafe
59
+ @mutex ||= Mutex.new
60
+ @mutex.synchronize {
61
+ @callbacks ||= {}
62
+ @callbacks[event] ||= {}
54
63
 
55
- # save the callback info without creating a reference to the object
56
- @callbacks[event][listener_id] ||= []
57
- @callbacks[event][listener_id] << callback
58
-
59
- # will remove the object from the callback list if it is destroyed
60
- ObjectSpace.define_finalizer(
61
- listener,
62
- unregister_finalizer(event, listener_id, callback)
63
- )
64
+ listener = args[:listener]
65
+ listener_id = listener.object_id
66
+ callback = args[:callback]
67
+
68
+ # save the callback info without creating a reference to the object
69
+ @callbacks[event][listener_id] ||= []
70
+ @callbacks[event][listener_id] << callback
64
71
 
72
+ # will remove the object from the callback list if it is destroyed
73
+ ObjectSpace.define_finalizer(
74
+ listener,
75
+ unregister_finalizer(event, listener_id, callback)
76
+ )
77
+ }
65
78
  end
66
79
 
67
80
  # Allows objects to stop listening to events
@@ -72,10 +85,12 @@ module Eventable
72
85
  listener_id = args[:listener_id] || args[:listener].object_id
73
86
  callback = args[:callback]
74
87
 
75
- @callbacks[event].delete_if do |listener, callbacks|
76
- callbacks.delete(callback) if listener == listener_id
77
- callbacks.empty?
78
- end
88
+ @mutex.synchronize {
89
+ @callbacks[event].delete_if do |listener, callbacks|
90
+ callbacks.delete(callback) if listener == listener_id
91
+ callbacks.empty?
92
+ end
93
+ }
79
94
  end
80
95
 
81
96
  # Wrapper for the finalize proc. You have to call a method
@@ -1,3 +1,3 @@
1
1
  module Eventable
2
- VERSION = "0.1.0.beta1"
2
+ VERSION = "0.1.0.beta2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta1
4
+ version: 0.1.0.beta2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-06-05 00:00:00.000000000Z
12
+ date: 2011-06-06 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &2156146420 !ruby/object:Gem::Requirement
16
+ requirement: &2156717840 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '2.6'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2156146420
24
+ version_requirements: *2156717840
25
25
  description: Provides an easy to use and understand event model. If you want a simple
26
26
  way to add events to your classes without a bunch of other unrelated IO stuff this
27
27
  is the solution for you. (If you want to monitor IO events check out EventMachine)