weak_observable 1.0.0 → 1.0.1
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/.travis.yml +7 -0
- data/CHANGELOG +6 -0
- data/Gemfile +7 -1
- data/README.md +54 -4
- data/Rakefile +4 -1
- data/lib/weak_observable/hub.rb +6 -5
- data/lib/weak_observable/version.rb +1 -1
- data/spec/weak_observable/hub_spec.rb +14 -37
- data/spec/weak_observable/weak_observable_spec.rb +10 -17
- metadata +9 -2
data/.travis.yml
ADDED
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
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# WeakObservable
|
1
|
+
# WeakObservable [](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
|
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
|
data/lib/weak_observable/hub.rb
CHANGED
@@ -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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
@@ -127,51 +127,28 @@ describe WeakObservable::Hub do
|
|
127
127
|
end
|
128
128
|
|
129
129
|
specify "observers can be garbage collected" do
|
130
|
-
|
131
|
-
|
130
|
+
Ref::Mock.use do
|
131
|
+
observer1 = double
|
132
|
+
observer2 = double
|
132
133
|
|
133
|
-
|
134
|
-
|
134
|
+
observer1.should_not_receive(:update)
|
135
|
+
observer2.should_receive(:update)
|
135
136
|
|
136
|
-
|
137
|
-
|
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
|
-
|
144
|
-
GC.start
|
145
|
-
sleep 0.001
|
146
|
-
end
|
140
|
+
Ref::Mock.gc(observer1)
|
147
141
|
|
148
|
-
|
149
|
-
|
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
|
-
|
155
|
-
finalizer = lambda { |_| counter += 1 }
|
147
|
+
mapping = lambda { |key| observable.instance_eval { @mapping }[key] }
|
156
148
|
|
157
|
-
|
158
|
-
|
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
|
-
|
89
|
-
|
88
|
+
Ref::Mock.use do
|
89
|
+
observer1 = double
|
90
|
+
observer2 = double
|
90
91
|
|
91
|
-
|
92
|
-
|
92
|
+
observer1.should_not_receive(:update)
|
93
|
+
observer2.should_receive(:update)
|
93
94
|
|
94
|
-
|
95
|
-
|
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
|
-
|
102
|
-
GC.start
|
103
|
-
sleep 0.001
|
104
|
-
end
|
98
|
+
Ref::Mock.gc(observer1)
|
105
99
|
|
106
|
-
|
107
|
-
|
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.
|
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-
|
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
|