weak_observable 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ bundler_args: --without non_essentials
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.3
5
+ - 1.9.2
6
+ - jruby-19mode
7
+ - rbx-19mode
data/CHANGELOG CHANGED
@@ -1,5 +1,11 @@
1
+ # [v1.0.1][]
2
+
3
+ - Updated README to fix faulty example.
4
+ - Fix Hub throwing warnings when adding an observer.
5
+
1
6
  # [v1.0.0][]
2
7
 
3
8
  Initial release. WeakObservable and Hub!
4
9
 
10
+ [v1.0.1]: https://github.com/Burgestrand/weak_observable/compare/v1.0.0...v1.0.1
5
11
  [v1.0.0]: https://github.com/Burgestrand/weak_observable/tree/v1.0.0
data/Gemfile CHANGED
@@ -1,3 +1,9 @@
1
1
  source :rubygems
2
2
  gemspec
3
- gem 'yard'
3
+
4
+ gem 'rake'
5
+ gem 'ref', :github => 'Burgestrand/ref', :branch => 'fix_ref_mock_gc'
6
+
7
+ group :non_essentials do
8
+ gem 'yard'
9
+ end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # WeakObservable
1
+ # WeakObservable [![Build Status](https://secure.travis-ci.org/Burgestrand/weak_observable.png)](http://travis-ci.org/Burgestrand/weak_observable)
2
2
 
3
3
  WeakObservable is very similar to Observable from ruby’ standard library, but
4
4
  with the very important difference in that it allows it’s subscribers to be
@@ -31,8 +31,7 @@ end
31
31
  observer = Observer.new
32
32
 
33
33
  playlist = Playlist.new
34
- playlist.observers << observer
35
- playlist.observers.count # => 1
34
+ playlist.observers.add(observer)
36
35
 
37
36
  # Notify all observers. Any arguments and given block goes out to them all.
38
37
  playlist.observers.notify(:ping)
@@ -42,10 +41,61 @@ playlist.observers.notify(:ping)
42
41
  observer = nil
43
42
 
44
43
  # Some time passes, ruby garbage collection eventually kicks in, and now…
45
- playlist.observers.count # => 0
46
44
  playlist.observers.notify(:ping) # nothing happens, we have no observers.
47
45
  ```
48
46
 
47
+ There is also the Hub, which is a mix between a WeakObservable and a Hash.
48
+ You add observers by associating them with a key. A key can have multiple
49
+ observers. When you notify observers, you supply the key, and observers on
50
+ that key will be notified, but not any other observers.
51
+
52
+ ```ruby
53
+ require 'weak_observable'
54
+
55
+ hub = WeakObservable::Hub.new
56
+
57
+ class Ninja
58
+ def update(event, *args)
59
+ puts "Ninjas: #{event}"
60
+ end
61
+ end
62
+
63
+ class Pirate
64
+ def update(event, *args)
65
+ puts "Pirates: #{event}"
66
+ end
67
+ end
68
+
69
+ ninja_a = Ninja.new
70
+ ninja_b = Ninja.new
71
+
72
+ pirate_a = Pirate.new
73
+ pirate_b = Pirate.new
74
+
75
+ hub.add(Ninja, ninja_a)
76
+ hub.add(Ninja, ninja_b)
77
+ hub.add(Pirate, pirate_a)
78
+ hub.add(Pirate, pirate_b)
79
+
80
+ hub.notify(Pirate, "Ninjarrrs arrr attacking!")
81
+ # ^ notifies all the pirates that ninjas are attacking.
82
+
83
+ hub.notify(Ninja, "All pirates are down.")
84
+ # ^ notifies all ninjas the pirates are all dead.
85
+ ```
86
+
87
+ When all objects of a given key has been garbage collected, that key will
88
+ also be garbage collected. Because of this property Hubs can be extremely
89
+ useful interfacing with asynchronous C libraries and their callbacks.
90
+
91
+ ## Supported platforms
92
+
93
+ - CRuby 1.9.2, 1.9.3
94
+ - JRuby 1.9-mode
95
+ - Rubinius 1.9-mode
96
+
97
+ I will not be supporting Ruby 1.8.
98
+
49
99
  ## Contributing
50
100
 
51
101
  Please fork the repository and clone it. To get started with development you’ll
data/Rakefile CHANGED
@@ -7,9 +7,12 @@ begin
7
7
  require 'yard'
8
8
  require 'yard/rake/yardoc_task'
9
9
  YARD::Rake::YardocTask.new
10
+ rescue LoadError
10
11
  end
11
12
 
12
13
  require 'rspec/core/rake_task'
13
- RSpec::Core::RakeTask.new
14
+ RSpec::Core::RakeTask.new do |task|
15
+ task.ruby_opts = '-W'
16
+ end
14
17
 
15
18
  task :default => :spec
@@ -82,11 +82,12 @@ class WeakObservable
82
82
  # when all observers are gone, the observables for the address
83
83
  # they are registered to is also eligible for garbage collection.
84
84
  def backrefs_of(object)
85
- # The object may be attached to several hubs, so make sure
86
- # we don’t fuck up by mapping our own object_id first.
87
- ivar = '@__observable__hubs__'
88
- back_hash = object.instance_variable_get(ivar)
89
- back_hash ||= Hash.new
85
+ ivar = :@__observable__hubs__
86
+ back_hash = if object.instance_variable_defined?(ivar)
87
+ object.instance_variable_get(ivar)
88
+ else
89
+ Hash.new
90
+ end
90
91
  object.instance_variable_set(ivar, back_hash)
91
92
 
92
93
  # An object may also be attached to several addresses within
@@ -1,3 +1,3 @@
1
1
  class WeakObservable
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -127,51 +127,28 @@ describe WeakObservable::Hub do
127
127
  end
128
128
 
129
129
  specify "observers can be garbage collected" do
130
- counter = 0
131
- finalizer = lambda { |_| counter += 1 }
130
+ Ref::Mock.use do
131
+ observer1 = double
132
+ observer2 = double
132
133
 
133
- threshold = 5
134
- stretches = 5
134
+ observer1.should_not_receive(:update)
135
+ observer2.should_receive(:update)
135
136
 
136
- threshold.times do
137
- # stub with return value for method cannot be garbage collected.
138
- observer = OpenStruct.new(:update => nil)
139
- observable.add(key, observer)
140
- ObjectSpace.define_finalizer(observer, finalizer)
141
- end
137
+ observable.add(key, observer1)
138
+ observable.add(key, observer2)
142
139
 
143
- (threshold * stretches).times do
144
- GC.start
145
- sleep 0.001
146
- end
140
+ Ref::Mock.gc(observer1)
147
141
 
148
- # if one is garbage collected, we can expect all to eventually be
149
- # as well
150
- counter.should be > 1
142
+ observable.notify(key)
143
+ end
151
144
  end
152
145
 
153
146
  specify "entire keys can be garbage collected" do
154
- counter = 0
155
- finalizer = lambda { |_| counter += 1 }
147
+ mapping = lambda { |key| observable.instance_eval { @mapping }[key] }
156
148
 
157
- threshold = 5
158
- stretches = 5
159
-
160
- threshold.times do |i|
161
- # stub with return value for method cannot be garbage collected.
162
- observer = OpenStruct.new(:update => nil)
163
- observable.add(key + i, observer)
164
- ObjectSpace.define_finalizer(observer, finalizer)
165
- end
166
-
167
- (threshold * stretches).times do
168
- GC.start
169
- sleep 0.001
170
- end
171
-
172
- # some very intimate introspection here
173
- observable.instance_eval do
174
- @mapping.to_a.length.should < threshold
149
+ Ref::Mock.use do
150
+ observable.add(key, observer)
151
+ expect { Ref::Mock.gc }.to change { mapping[key] }.to(nil)
175
152
  end
176
153
  end
177
154
  end
@@ -85,26 +85,19 @@ describe WeakObservable do
85
85
  end
86
86
 
87
87
  specify "observers can be garbage collected" do
88
- counter = 0
89
- finalizer = lambda { |_| counter += 1 }
88
+ Ref::Mock.use do
89
+ observer1 = double
90
+ observer2 = double
90
91
 
91
- threshold = 5
92
- stretches = 5
92
+ observer1.should_not_receive(:update)
93
+ observer2.should_receive(:update)
93
94
 
94
- threshold.times do
95
- # stub with return value for method cannot be garbage collected.
96
- observer = OpenStruct.new(:update => nil)
97
- observable.add(observer)
98
- ObjectSpace.define_finalizer(observer, finalizer)
99
- end
95
+ observable.add(observer1)
96
+ observable.add(observer2)
100
97
 
101
- (threshold * stretches).times do
102
- GC.start
103
- sleep 0.001
104
- end
98
+ Ref::Mock.gc(observer1)
105
99
 
106
- # if one is garbage collected, we can expect all to eventually be
107
- # as well
108
- counter.should be > 1
100
+ observable.notify
101
+ end
109
102
  end
110
103
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weak_observable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-28 00:00:00.000000000 Z
12
+ date: 2012-09-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ref
@@ -59,6 +59,7 @@ extra_rdoc_files: []
59
59
  files:
60
60
  - .gitignore
61
61
  - .rspec
62
+ - .travis.yml
62
63
  - CHANGELOG
63
64
  - Gemfile
64
65
  - LICENSE.txt
@@ -85,12 +86,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
86
  - - ! '>='
86
87
  - !ruby/object:Gem::Version
87
88
  version: '0'
89
+ segments:
90
+ - 0
91
+ hash: 269781825206150069
88
92
  required_rubygems_version: !ruby/object:Gem::Requirement
89
93
  none: false
90
94
  requirements:
91
95
  - - ! '>='
92
96
  - !ruby/object:Gem::Version
93
97
  version: '0'
98
+ segments:
99
+ - 0
100
+ hash: 269781825206150069
94
101
  requirements: []
95
102
  rubyforge_project:
96
103
  rubygems_version: 1.8.24