Skip to content

Commit 41aa337

Browse files
committed
Dereferenceable is now in the Concern module.
1 parent 626aa46 commit 41aa337

17 files changed

+108
-106
lines changed

lib/concurrent/agent.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require 'thread'
2-
require 'concurrent/dereferenceable'
2+
require 'concurrent/concern/dereferenceable'
33
require 'concurrent/observable'
44
require 'concurrent/logging'
55
require 'concurrent/executor/executor'
@@ -79,7 +79,7 @@ module Concurrent
7979
# @!attribute [r] timeout
8080
# @return [Fixnum] the maximum number of seconds before an update is cancelled
8181
class Agent
82-
include Dereferenceable
82+
include Concern::Dereferenceable
8383
include Observable
8484
include Logging
8585
include Deprecation

lib/concurrent/atom.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require 'concurrent/dereferenceable'
1+
require 'concurrent/concern/dereferenceable'
22
require 'concurrent/atomic/atomic_reference'
33
require 'concurrent/synchronization/object'
44

@@ -22,7 +22,7 @@ module Concurrent
2222
#
2323
# @see http://clojure.org/atoms Clojure Atoms
2424
class Atom < Synchronization::Object
25-
include Dereferenceable
25+
include Concern::Dereferenceable
2626

2727
# Create a new atom with the given initial value.
2828
#
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
module Concurrent
2+
module Concern
3+
4+
# Object references in Ruby are mutable. This can lead to serious problems when
5+
# the `#value` of a concurrent object is a mutable reference. Which is always the
6+
# case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type.
7+
# Most classes in this library that expose a `#value` getter method do so using the
8+
# `Dereferenceable` mixin module.
9+
#
10+
# @!macro copy_options
11+
module Dereferenceable
12+
13+
# Return the value this object represents after applying the options specified
14+
# by the `#set_deref_options` method.
15+
#
16+
# @return [Object] the current value of the object
17+
def value
18+
mutex.synchronize { apply_deref_options(@value) }
19+
end
20+
alias_method :deref, :value
21+
22+
protected
23+
24+
# Set the internal value of this object
25+
#
26+
# @param [Object] value the new value
27+
def value=(value)
28+
mutex.synchronize{ @value = value }
29+
end
30+
31+
# A mutex lock used for synchronizing thread-safe operations. Methods defined
32+
# by `Dereferenceable` are synchronized using the `Mutex` returned from this
33+
# method. Operations performed by the including class that operate on the
34+
# `@value` instance variable should be locked with this `Mutex`.
35+
#
36+
# @return [Mutex] the synchronization object
37+
def mutex
38+
@mutex
39+
end
40+
41+
# Initializes the internal `Mutex`.
42+
#
43+
# @note This method *must* be called from within the constructor of the including class.
44+
#
45+
# @see #mutex
46+
def init_mutex(mutex = Mutex.new)
47+
@mutex = mutex
48+
end
49+
50+
# @!macro [attach] dereferenceable_set_deref_options
51+
# Set the options which define the operations #value performs before
52+
# returning data to the caller (dereferencing).
53+
#
54+
# @note Most classes that include this module will call `#set_deref_options`
55+
# from within the constructor, thus allowing these options to be set at
56+
# object creation.
57+
#
58+
# @param [Hash] opts the options defining dereference behavior.
59+
# @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
60+
# @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
61+
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
62+
# the internal value and returning the value returned from the proc
63+
def set_deref_options(opts = {})
64+
mutex.synchronize{ ns_set_deref_options(opts) }
65+
end
66+
67+
# @!macro dereferenceable_set_deref_options
68+
# @!visibility private
69+
def ns_set_deref_options(opts)
70+
@dup_on_deref = opts[:dup_on_deref] || opts[:dup]
71+
@freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze]
72+
@copy_on_deref = opts[:copy_on_deref] || opts[:copy]
73+
@do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref)
74+
nil
75+
end
76+
77+
# @!visibility private
78+
def apply_deref_options(value)
79+
return nil if value.nil?
80+
return value if @do_nothing_on_deref
81+
value = @copy_on_deref.call(value) if @copy_on_deref
82+
value = value.dup if @dup_on_deref
83+
value = value.freeze if @freeze_on_deref
84+
value
85+
end
86+
end
87+
end
88+
end

lib/concurrent/delay.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module Concurrent
2626
# return the cached value. The operation will only be run once. This means that
2727
# any side effects created by the operation will only happen once as well.
2828
#
29-
# `Delay` includes the `Concurrent::Dereferenceable` mixin to support thread
29+
# `Delay` includes the `Concurrent::Concern::Dereferenceable` mixin to support thread
3030
# safety of the reference returned by `#value`.
3131
#
3232
# @!macro copy_options
@@ -39,7 +39,7 @@ module Concurrent
3939
# constructor option. This will cause the delayed operation to be
4040
# execute on the given executor, allowing the call to timeout.
4141
#
42-
# @see Concurrent::Dereferenceable
42+
# @see Concurrent::Concern::Dereferenceable
4343
class Delay < Synchronization::Object
4444
include Obligation
4545

lib/concurrent/dereferenceable.rb

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

lib/concurrent/exchanger.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Concurrent
1010
# the `MVar` constructors.
1111
#
1212
# @see Concurrent::MVar
13-
# @see Concurrent::Dereferenceable
13+
# @see Concurrent::Concern::Dereferenceable
1414
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger
1515
class Exchanger
1616

lib/concurrent/mvar.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require 'concurrent/dereferenceable'
1+
require 'concurrent/concern/dereferenceable'
22

33
module Concurrent
44

@@ -69,7 +69,7 @@ module Concurrent
6969
# (PoPL), 1996.
7070
class MVar
7171

72-
include Dereferenceable
72+
include Concern::Dereferenceable
7373

7474
# Unique value that represents that an `MVar` was empty
7575
EMPTY = Object.new

lib/concurrent/obligation.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
require 'thread'
22
require 'timeout'
33

4-
require 'concurrent/dereferenceable'
4+
require 'concurrent/concern/dereferenceable'
55
require 'concurrent/atomic/event'
66
require 'concurrent/utility/deprecation'
77

88
module Concurrent
99

1010
module Obligation
11-
include Dereferenceable
11+
include Concern::Dereferenceable
1212
include Deprecation
1313

1414
# Has the obligation been fulfilled?

lib/concurrent/timer_task.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require 'concurrent/dereferenceable'
1+
require 'concurrent/concern/dereferenceable'
22
require 'concurrent/observable'
33
require 'concurrent/atomic/atomic_boolean'
44
require 'concurrent/executor/executor_service'
@@ -150,7 +150,7 @@ module Concurrent
150150
# @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
151151
# @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
152152
class TimerTask < RubyExecutorService
153-
include Dereferenceable
153+
include Concern::Dereferenceable
154154
include Observable
155155

156156
# Default `:execution_interval` in seconds.

spec/concurrent/agent_spec.rb

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

44
module Concurrent

0 commit comments

Comments
 (0)