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