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.
@@ -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