eventable 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
 
@@ -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 without a bunch of unrelated IO stuff this is the solution for you. (If you want to monitor IO events check out EventMachine)}
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
 
@@ -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{
@@ -1,5 +1,6 @@
1
1
  module Eventable
2
2
  module Errors
3
3
  UnknownEvent = Class.new(StandardError)
4
+ SuperNotCalledInInitialize = Class.new(ScriptError)
4
5
  end
5
6
  end
@@ -15,13 +15,13 @@ module Eventable
15
15
 
16
16
  # register an event
17
17
  def event(event_name)
18
- @events ||= []
19
- @events << event_name unless @events.include? event_name
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
- @events.clone
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
- @mutex ||= Mutex.new
37
- @mutex.synchronize{
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
- @mutex ||= Mutex.new
65
- @mutex.synchronize {
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
- @mutex ||= Mutex.new
88
- @mutex.synchronize {
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)
@@ -1,3 +1,3 @@
1
1
  module Eventable
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -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.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-10 00:00:00 Z
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 without a bunch of unrelated IO stuff this is the solution for you. (If you want to monitor IO events check out EventMachine)
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
@@ -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
-
@@ -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}