This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
module Concurrent
|
||||
module Concern
|
||||
|
||||
# Object references in Ruby are mutable. This can lead to serious problems when
|
||||
# the `#value` of a concurrent object is a mutable reference. Which is always the
|
||||
# case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type.
|
||||
# Most classes in this library that expose a `#value` getter method do so using the
|
||||
# `Dereferenceable` mixin module.
|
||||
#
|
||||
# @!macro copy_options
|
||||
module Dereferenceable
|
||||
# NOTE: This module is going away in 2.0. In the mean time we need it to
|
||||
# play nicely with the synchronization layer. This means that the
|
||||
# including class SHOULD be synchronized and it MUST implement a
|
||||
# `#synchronize` method. Not doing so will lead to runtime errors.
|
||||
|
||||
# Return the value this object represents after applying the options specified
|
||||
# by the `#set_deref_options` method.
|
||||
#
|
||||
# @return [Object] the current value of the object
|
||||
def value
|
||||
synchronize { apply_deref_options(@value) }
|
||||
end
|
||||
alias_method :deref, :value
|
||||
|
||||
protected
|
||||
|
||||
# Set the internal value of this object
|
||||
#
|
||||
# @param [Object] value the new value
|
||||
def value=(value)
|
||||
synchronize{ @value = value }
|
||||
end
|
||||
|
||||
# @!macro dereferenceable_set_deref_options
|
||||
# Set the options which define the operations #value performs before
|
||||
# returning data to the caller (dereferencing).
|
||||
#
|
||||
# @note Most classes that include this module will call `#set_deref_options`
|
||||
# from within the constructor, thus allowing these options to be set at
|
||||
# object creation.
|
||||
#
|
||||
# @param [Hash] opts the options defining dereference behavior.
|
||||
# @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
|
||||
# @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
|
||||
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
|
||||
# the internal value and returning the value returned from the proc
|
||||
def set_deref_options(opts = {})
|
||||
synchronize{ ns_set_deref_options(opts) }
|
||||
end
|
||||
|
||||
# @!macro dereferenceable_set_deref_options
|
||||
# @!visibility private
|
||||
def ns_set_deref_options(opts)
|
||||
@dup_on_deref = opts[:dup_on_deref] || opts[:dup]
|
||||
@freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze]
|
||||
@copy_on_deref = opts[:copy_on_deref] || opts[:copy]
|
||||
@do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref)
|
||||
nil
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
def apply_deref_options(value)
|
||||
return nil if value.nil?
|
||||
return value if @do_nothing_on_deref
|
||||
value = @copy_on_deref.call(value) if @copy_on_deref
|
||||
value = value.dup if @dup_on_deref
|
||||
value = value.freeze if @freeze_on_deref
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user