class CowProxy::Base
Base
class to create CowProxy
classes
Also, it's used as default CowProxy
class for non-registered classes with copy-on-write disabled, so returned values are wrapped but methods trying to change object still raise exception.
Attributes
Class which will be wrapped with this CowProxy
class
Public Class Methods
Setup wrapped_class
and register itself into CowProxy
with {CowProxy.register_proxy CowProxy.register_proxy
}
# File lib/cow_proxy/base.rb, line 14 def inherited(subclass) subclass.wrapped_class = wrapped_class CowProxy.register_proxy wrapped_class, subclass if wrapped_class end
Creates a CowProxy
object wrapping obj
@param obj An object to wrap with CowProxy
class @param parent CowProxy
object wrapping obj @param parent_var instance variable name in parent
which keeps this CowProxy object
# File lib/cow_proxy/base.rb, line 50 def initialize(obj, parent = nil, parent_var = nil) @delegate_dc_obj = obj @parent_proxy = parent @parent_var = parent_var @dc_obj_duplicated = false end
Protected Class Methods
Return block with proxy implementation.
Block calls a method in wrapped object
@param [Symbol] method Method name to call in wrapped object @param [Boolean] cow_enabled True if copy-on-write is enabled
for proxy class, it will _copy_on_write when method will modify wrapped object.
@return [Proc] Block with proxy implementation.
# File lib/cow_proxy/base.rb, line 30 def wrapping_block(method, cow_enabled) lambda do |*args, &block| if method.to_s =~ /^\w+$/ inst_var = "@#{method}" return _instance_variable_get(inst_var) if _instance_variable_defined?(inst_var) elsif method.to_s =~ /^(\w+)=$/ && _instance_variable_defined?("@#{Regexp.last_match(1)}") CowProxy.debug { "remove #{Regexp.last_match(1)}" } _remove_instance_variable "@#{Regexp.last_match(1)}" end __wrapped_method__(inst_var, cow_enabled, method, *args, &block) end end
Protected Instance Methods
Replace wrapped object with a copy, so object can be modified.
@param [Boolean] parent Replace proxy object in parent with
duplicated wrapped object, if this proxy was created from another CowProxy.
@return duplicated wrapped object
# File lib/cow_proxy/base.rb, line 66 def __copy_on_write__(parent = true) CowProxy.debug { "copy on write on #{__getobj__.class.name}" } return @delegate_dc_obj if @dc_obj_duplicated @delegate_dc_obj = @delegate_dc_obj.dup @dc_obj_duplicated = true __copy_parent__ if parent && @parent_proxy @delegate_dc_obj end
Private Instance Methods
# File lib/cow_proxy/base.rb, line 81 def __copy_parent__ @parent_proxy.send :__copy_on_write__, false return unless @parent_var parent_dc = @parent_proxy._instance_variable_get(:@delegate_dc_obj) method = @parent_var[1..-1] + '=' parent_dc.send(method, @delegate_dc_obj) end
# File lib/cow_proxy/base.rb, line 77 def __getobj__ @delegate_dc_obj end
# File lib/cow_proxy/base.rb, line 89 def __wrap__(value, inst_var = nil) return unless value.frozen? CowProxy.debug { "wrap #{value.class.name} with parent #{__getobj__.class.name}" } wrap_klass = CowProxy.wrapper_class(value) wrap_value = wrap_klass&.new(value, self, inst_var) _instance_variable_set(inst_var, wrap_value) if inst_var && wrap_value wrap_value end
# File lib/cow_proxy/base.rb, line 108 def __wrapped_method__(inst_var, cow, method, *args, &block) __wrapped_value__(inst_var, method, *args, &block) rescue StandardError => e CowProxy.debug do "error #{e.message} on #{__getobj__.class.name} (#{__getobj__.object_id}) #{method} "\ "#{args.inspect unless args.empty?} with#{'out' unless cow} cow" end raise unless cow && e.message =~ /^can't modify frozen/ CowProxy.debug { "copy on write to run #{method}" } __copy_on_write__ CowProxy.debug { "new target #{__getobj__.class.name} (#{__getobj__.object_id})" } __wrapped_value__(inst_var, method, *args, &block) end
# File lib/cow_proxy/base.rb, line 98 def __wrapped_value__(inst_var, method, *args, &block) CowProxy.debug do "run on #{__getobj__.class.name} (#{__getobj__.object_id}) "\ "#{method} #{args.inspect unless args.empty?}" end value = __getobj__.__send__(method, *args, &block) wrap_value = __wrap__(value, inst_var) if inst_var && args.empty? && !block wrap_value || value end