Skip to content

Commit 4c58a52

Browse files
committed
Observable is now in the Concern module.
1 parent 6488ad9 commit 4c58a52

File tree

16 files changed

+152
-148
lines changed

16 files changed

+152
-148
lines changed

lib/concurrent/agent.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'thread'
22
require 'concurrent/concern/dereferenceable'
3-
require 'concurrent/observable'
3+
require 'concurrent/concern/observable'
44
require 'concurrent/logging'
55
require 'concurrent/executor/executor'
66
require 'concurrent/concern/deprecation'
@@ -80,7 +80,7 @@ module Concurrent
8080
# @return [Fixnum] the maximum number of seconds before an update is cancelled
8181
class Agent
8282
include Concern::Dereferenceable
83-
include Observable
83+
include Concern::Observable
8484
include Logging
8585
include Concern::Deprecation
8686

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
require 'concurrent/atomic/copy_on_notify_observer_set'
2+
require 'concurrent/atomic/copy_on_write_observer_set'
3+
4+
module Concurrent
5+
module Concern
6+
7+
# The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one
8+
# of the most useful design patterns.
9+
#
10+
# The workflow is very simple:
11+
# - an `observer` can register itself to a `subject` via a callback
12+
# - many `observers` can be registered to the same `subject`
13+
# - the `subject` notifies all registered observers when its status changes
14+
# - an `observer` can deregister itself when is no more interested to receive
15+
# event notifications
16+
#
17+
# In a single threaded environment the whole pattern is very easy: the
18+
# `subject` can use a simple data structure to manage all its subscribed
19+
# `observer`s and every `observer` can react directly to every event without
20+
# caring about synchronization.
21+
#
22+
# In a multi threaded environment things are more complex. The `subject` must
23+
# synchronize the access to its data structure and to do so currently we're
24+
# using two specialized ObserverSet: CopyOnWriteObserverSet and
25+
# CopyOnNotifyObserverSet.
26+
#
27+
# When implementing and `observer` there's a very important rule to remember:
28+
# **there are no guarantees about the thread that will execute the callback**
29+
#
30+
# Let's take this example
31+
# ```
32+
# class Observer
33+
# def initialize
34+
# @count = 0
35+
# end
36+
#
37+
# def update
38+
# @count += 1
39+
# end
40+
# end
41+
#
42+
# obs = Observer.new
43+
# [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) }
44+
# # execute [obj1, obj2, obj3, obj4]
45+
# ```
46+
#
47+
# `obs` is wrong because the variable `@count` can be accessed by different
48+
# threads at the same time, so it should be synchronized (using either a Mutex
49+
# or an AtomicFixum)
50+
module Observable
51+
52+
# @return [Object] the added observer
53+
def add_observer(*args, &block)
54+
observers.add_observer(*args, &block)
55+
end
56+
57+
# as #add_observer but it can be used for chaining
58+
# @return [Observable] self
59+
def with_observer(*args, &block)
60+
add_observer(*args, &block)
61+
self
62+
end
63+
64+
# @return [Object] the deleted observer
65+
def delete_observer(*args)
66+
observers.delete_observer(*args)
67+
end
68+
69+
# @return [Observable] self
70+
def delete_observers
71+
observers.delete_observers
72+
self
73+
end
74+
75+
# @return [Integer] the observers count
76+
def count_observers
77+
observers.count_observers
78+
end
79+
80+
protected
81+
82+
attr_accessor :observers
83+
end
84+
end
85+
end

lib/concurrent/ivar.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
require 'concurrent/errors'
44
require 'concurrent/obligation'
5-
require 'concurrent/observable'
5+
require 'concurrent/concern/observable'
66
require 'concurrent/synchronization'
77

88
module Concurrent
@@ -48,7 +48,7 @@ module Concurrent
4848
# [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html).
4949
class IVar < Synchronization::Object
5050
include Obligation
51-
include Observable
51+
include Concern::Observable
5252

5353
# @!visibility private
5454
NO_VALUE = Object.new # :nodoc:

lib/concurrent/observable.rb

Lines changed: 0 additions & 83 deletions
This file was deleted.

lib/concurrent/timer_task.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require 'concurrent/concern/dereferenceable'
2-
require 'concurrent/observable'
2+
require 'concurrent/concern/observable'
33
require 'concurrent/atomic/atomic_boolean'
44
require 'concurrent/executor/executor_service'
55
require 'concurrent/executor/safe_task_executor'
@@ -151,7 +151,7 @@ module Concurrent
151151
# @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
152152
class TimerTask < RubyExecutorService
153153
include Concern::Dereferenceable
154-
include Observable
154+
include Concern::Observable
155155

156156
# Default `:execution_interval` in seconds.
157157
EXECUTION_INTERVAL = 60

spec/concurrent/agent_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require_relative 'concern/dereferenceable_shared'
2-
require_relative 'observable_shared'
2+
require_relative 'concern/observable_shared'
33

44
module Concurrent
55

spec/concurrent/channel/probe_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require_relative '../observable_shared'
1+
require_relative '../concern/observable_shared'
22

33
module Concurrent
44

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)