rubysl-observer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d688ce9f9a7f41c345eb041aaab60e3da171af7
4
+ data.tar.gz: 1a636e1298a86954dbd1da417863537a1fcd4de4
5
+ SHA512:
6
+ metadata.gz: ddd59dbc50a5c515f3307c20d89af59c0f59a609be912f3736c230874ecfc237947eb307f65e9a82d746640263094a4b8a320a01cbabe08503562d5127e636de
7
+ data.tar.gz: 22cf3263b3cc9b1e9e784678bb2dea310ddaed40e79c0360098cad5087b049d12ec3944d7a5eb1bb293a84ecae7fb5487a5f6f95196edc1e236bf0d08b8322ef
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ before_install:
3
+ - gem update --system
4
+ - gem --version
5
+ - gem install rubysl-bundler
6
+ script: bundle exec mspec spec
7
+ rvm:
8
+ - rbx-nightly-18mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubysl-observer.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubysl::Observer
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubysl-observer'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubysl-observer
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/observer.rb ADDED
@@ -0,0 +1 @@
1
+ require "rubysl/observer"
@@ -0,0 +1,2 @@
1
+ require "rubysl/observer/observer"
2
+ require "rubysl/observer/version"
@@ -0,0 +1,192 @@
1
+ #
2
+ # observer.rb implements the _Observer_ object-oriented design pattern. The
3
+ # following documentation is copied, with modifications, from "Programming
4
+ # Ruby", by Hunt and Thomas; http://www.rubycentral.com/book/lib_patterns.html.
5
+ #
6
+ # == About
7
+ #
8
+ # The Observer pattern, also known as Publish/Subscribe, provides a simple
9
+ # mechanism for one object to inform a set of interested third-party objects
10
+ # when its state changes.
11
+ #
12
+ # == Mechanism
13
+ #
14
+ # In the Ruby implementation, the notifying class mixes in the +Observable+
15
+ # module, which provides the methods for managing the associated observer
16
+ # objects.
17
+ #
18
+ # The observers must implement the +update+ method to receive notifications.
19
+ #
20
+ # The observable object must:
21
+ # * assert that it has +changed+
22
+ # * call +notify_observers+
23
+ #
24
+ # == Example
25
+ #
26
+ # The following example demonstrates this nicely. A +Ticker+, when run,
27
+ # continually receives the stock +Price+ for its +@symbol+. A +Warner+ is a
28
+ # general observer of the price, and two warners are demonstrated, a +WarnLow+
29
+ # and a +WarnHigh+, which print a warning if the price is below or above their
30
+ # set limits, respectively.
31
+ #
32
+ # The +update+ callback allows the warners to run without being explicitly
33
+ # called. The system is set up with the +Ticker+ and several observers, and the
34
+ # observers do their duty without the top-level code having to interfere.
35
+ #
36
+ # Note that the contract between publisher and subscriber (observable and
37
+ # observer) is not declared or enforced. The +Ticker+ publishes a time and a
38
+ # price, and the warners receive that. But if you don't ensure that your
39
+ # contracts are correct, nothing else can warn you.
40
+ #
41
+ # require "observer"
42
+ #
43
+ # class Ticker ### Periodically fetch a stock price.
44
+ # include Observable
45
+ #
46
+ # def initialize(symbol)
47
+ # @symbol = symbol
48
+ # end
49
+ #
50
+ # def run
51
+ # lastPrice = nil
52
+ # loop do
53
+ # price = Price.fetch(@symbol)
54
+ # print "Current price: #{price}\n"
55
+ # if price != lastPrice
56
+ # changed # notify observers
57
+ # lastPrice = price
58
+ # notify_observers(Time.now, price)
59
+ # end
60
+ # sleep 1
61
+ # end
62
+ # end
63
+ # end
64
+ #
65
+ # class Price ### A mock class to fetch a stock price (60 - 140).
66
+ # def Price.fetch(symbol)
67
+ # 60 + rand(80)
68
+ # end
69
+ # end
70
+ #
71
+ # class Warner ### An abstract observer of Ticker objects.
72
+ # def initialize(ticker, limit)
73
+ # @limit = limit
74
+ # ticker.add_observer(self)
75
+ # end
76
+ # end
77
+ #
78
+ # class WarnLow < Warner
79
+ # def update(time, price) # callback for observer
80
+ # if price < @limit
81
+ # print "--- #{time.to_s}: Price below #@limit: #{price}\n"
82
+ # end
83
+ # end
84
+ # end
85
+ #
86
+ # class WarnHigh < Warner
87
+ # def update(time, price) # callback for observer
88
+ # if price > @limit
89
+ # print "+++ #{time.to_s}: Price above #@limit: #{price}\n"
90
+ # end
91
+ # end
92
+ # end
93
+ #
94
+ # ticker = Ticker.new("MSFT")
95
+ # WarnLow.new(ticker, 80)
96
+ # WarnHigh.new(ticker, 120)
97
+ # ticker.run
98
+ #
99
+ # Produces:
100
+ #
101
+ # Current price: 83
102
+ # Current price: 75
103
+ # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75
104
+ # Current price: 90
105
+ # Current price: 134
106
+ # +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134
107
+ # Current price: 134
108
+ # Current price: 112
109
+ # Current price: 79
110
+ # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79
111
+
112
+
113
+ #
114
+ # Implements the Observable design pattern as a mixin so that other objects can
115
+ # be notified of changes in state. See observer.rb for details and an example.
116
+ #
117
+ module Observable
118
+
119
+ #
120
+ # Add +observer+ as an observer on this object. +observer+ will now receive
121
+ # notifications.
122
+ #
123
+ def add_observer(observer)
124
+ @observer_peers = [] unless defined? @observer_peers
125
+ unless observer.respond_to? :update
126
+ raise NoMethodError, "observer needs to respond to `update'"
127
+ end
128
+ @observer_peers.push observer
129
+ end
130
+
131
+ #
132
+ # Delete +observer+ as an observer on this object. It will no longer receive
133
+ # notifications.
134
+ #
135
+ def delete_observer(observer)
136
+ @observer_peers.delete observer if defined? @observer_peers
137
+ end
138
+
139
+ #
140
+ # Delete all observers associated with this object.
141
+ #
142
+ def delete_observers
143
+ @observer_peers.clear if defined? @observer_peers
144
+ end
145
+
146
+ #
147
+ # Return the number of observers associated with this object.
148
+ #
149
+ def count_observers
150
+ if defined? @observer_peers
151
+ @observer_peers.size
152
+ else
153
+ 0
154
+ end
155
+ end
156
+
157
+ #
158
+ # Set the changed state of this object. Notifications will be sent only if
159
+ # the changed +state+ is +true+.
160
+ #
161
+ def changed(state=true)
162
+ @observer_state = state
163
+ end
164
+
165
+ #
166
+ # Query the changed state of this object.
167
+ #
168
+ def changed?
169
+ if defined? @observer_state and @observer_state
170
+ true
171
+ else
172
+ false
173
+ end
174
+ end
175
+
176
+ #
177
+ # If this object's changed state is +true+, invoke the update method in each
178
+ # currently associated observer in turn, passing it the given arguments. The
179
+ # changed state is then set to +false+.
180
+ #
181
+ def notify_observers(*arg)
182
+ if defined? @observer_state and @observer_state
183
+ if defined? @observer_peers
184
+ @observer_peers.dup.each do |i|
185
+ i.update(*arg)
186
+ end
187
+ end
188
+ @observer_state = false
189
+ end
190
+ end
191
+
192
+ end
@@ -0,0 +1,5 @@
1
+ module Rubysl
2
+ module Observable
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ require './lib/rubysl/observer/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "rubysl-observer"
6
+ spec.version = Rubysl::Observable::VERSION
7
+ spec.authors = ["Brian Shirai"]
8
+ spec.email = ["brixen@gmail.com"]
9
+ spec.description = %q{Ruby standard library observer.}
10
+ spec.summary = %q{Ruby standard library observer.}
11
+ spec.homepage = "https://github.com/rubysl/rubysl-observer"
12
+ spec.license = "BSD"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "mspec", "~> 1.5"
22
+ spec.add_development_dependency "rubysl-prettyprint", "~> 1.0"
23
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../fixtures/classes', __FILE__)
2
+
3
+ describe "Observer#add_observer" do
4
+
5
+ before(:each) do
6
+ @observable = ObservableSpecs.new
7
+ @observer = ObserverCallbackSpecs.new
8
+ @custom_observer = ObserverCustomCallbackSpecs.new
9
+ end
10
+
11
+ it "adds the observer" do
12
+ @observer.value.should == nil
13
+ @observable.changed
14
+ @observable.notify_observers("test")
15
+ @observer.value.should == nil
16
+
17
+ @observable.add_observer(@observer)
18
+ @observable.changed
19
+ @observable.notify_observers("test2")
20
+ @observer.value.should == "test2"
21
+ end
22
+
23
+ it "supports custom method on observer" do
24
+ @observable.add_observer(@custom_observer, :custom)
25
+ @observable.changed
26
+ @observable.notify_observers("test2")
27
+ @custom_observer.value.should == "test2"
28
+ end
29
+
30
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../fixtures/classes', __FILE__)
2
+
3
+ describe "Observer#count_observers" do
4
+ before(:each) do
5
+ @observable = ObservableSpecs.new
6
+ @observer = ObserverCallbackSpecs.new
7
+ @observer2 = ObserverCallbackSpecs.new
8
+ end
9
+
10
+ it "returns the number of observers" do
11
+ @observable.count_observers.should == 0
12
+ @observable.add_observer(@observer)
13
+ @observable.count_observers.should == 1
14
+ @observable.add_observer(@observer2)
15
+ @observable.count_observers.should == 2
16
+ end
17
+
18
+ ruby_version_is "" ... "1.9" do
19
+ it "returns the number observers including duplicates" do
20
+ 2.times { @observable.add_observer(@observer) }
21
+ @observable.count_observers.should == 2
22
+ end
23
+ end
24
+
25
+ ruby_version_is "1.9" do
26
+ it "returns the number of unique observers" do
27
+ 2.times { @observable.add_observer(@observer) }
28
+ @observable.count_observers.should == 1
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../fixtures/classes', __FILE__)
2
+
3
+ describe "Observer#delete_observer" do
4
+ before(:each) do
5
+ @observable = ObservableSpecs.new
6
+ @observer = ObserverCallbackSpecs.new
7
+ end
8
+
9
+ it "deletes the observer" do
10
+ @observable.add_observer(@observer)
11
+ @observable.delete_observer(@observer)
12
+
13
+ @observable.changed
14
+ @observable.notify_observers("test")
15
+ @observer.value.should == nil
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../fixtures/classes', __FILE__)
2
+
3
+ describe "Observer#delete_observers" do
4
+ before(:each) do
5
+ @observable = ObservableSpecs.new
6
+ @observer = ObserverCallbackSpecs.new
7
+ end
8
+
9
+ it "deletes the observers" do
10
+ @observable.add_observer(@observer)
11
+ @observable.delete_observers
12
+
13
+ @observable.changed
14
+ @observable.notify_observers("test")
15
+ @observer.value.should == nil
16
+ end
17
+
18
+ end
@@ -0,0 +1,25 @@
1
+ require 'observer'
2
+
3
+ class ObserverCallbackSpecs
4
+ attr_reader :value
5
+
6
+ def initialize
7
+ @value = nil
8
+ end
9
+
10
+ def update(value)
11
+ @value = value
12
+ end
13
+ end
14
+
15
+ class ObserverCustomCallbackSpecs < ObserverCallbackSpecs
16
+ def update ; end
17
+
18
+ def custom(value)
19
+ @value = value
20
+ end
21
+ end
22
+
23
+ class ObservableSpecs
24
+ include Observable
25
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../fixtures/classes', __FILE__)
2
+
3
+ describe "Observer#notify_observers" do
4
+
5
+ before(:each) do
6
+ @observable = ObservableSpecs.new
7
+ @observer = ObserverCallbackSpecs.new
8
+ @observable.add_observer(@observer)
9
+ end
10
+
11
+ it "must call changed before notifying observers" do
12
+ @observer.value.should == nil
13
+ @observable.notify_observers("test")
14
+ @observer.value.should == nil
15
+ end
16
+
17
+ it "verifies observer responds to update" do
18
+ lambda {
19
+ @observable.add_observer(@observable)
20
+ }.should raise_error(NoMethodError)
21
+ end
22
+
23
+ it "receives the callback" do
24
+ @observer.value.should == nil
25
+ @observable.changed
26
+ @observable.notify_observers("test")
27
+ @observer.value.should == "test"
28
+ end
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubysl-observer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Shirai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubysl-prettyprint
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ description: Ruby standard library observer.
70
+ email:
71
+ - brixen@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .travis.yml
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - lib/observer.rb
83
+ - lib/rubysl/observer.rb
84
+ - lib/rubysl/observer/observer.rb
85
+ - lib/rubysl/observer/version.rb
86
+ - rubysl-observer.gemspec
87
+ - spec/add_observer_spec.rb
88
+ - spec/count_observers_spec.rb
89
+ - spec/delete_observer_spec.rb
90
+ - spec/delete_observers_spec.rb
91
+ - spec/fixtures/classes.rb
92
+ - spec/notify_observers_spec.rb
93
+ homepage: https://github.com/rubysl/rubysl-observer
94
+ licenses:
95
+ - BSD
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.0.7
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Ruby standard library observer.
117
+ test_files:
118
+ - spec/add_observer_spec.rb
119
+ - spec/count_observers_spec.rb
120
+ - spec/delete_observer_spec.rb
121
+ - spec/delete_observers_spec.rb
122
+ - spec/fixtures/classes.rb
123
+ - spec/notify_observers_spec.rb