module Ref::Mock

This module provides mock weak and strong references that are designed to be used in tests. You can define a block where all weak and soft references created will be mock references. You can then mimic running the garbage collector on the objects pointed to by the references.

Example usage:

Ref::Mock.use do
  obj = Object.new
  ref = Ref::WeakReference.new(obj)
  ref.object   # obj
  Ref::Mock.gc(obj)  # mimics the garbage collector reclaiming the referenced object
  ref.object   # nil
end

Public Class Methods

cleanup() click to toggle source

Stop using mock references.

# File lib/ref/mock.rb, line 85
def cleanup
  @object_space = nil
  class << ObjectSpace
    alias_method :define_finalizer_with_mock_reference, :define_finalizer
    alias_method :define_finalizer, :define_finalizer_without_mock_reference
  end
  
  class << WeakReference
    alias_method :new_with_mock_reference, :new
    alias_method :new, :new_without_mock_reference
  end
  
  class << SoftReference
    alias_method :new_with_mock_reference, :new
    alias_method :new, :new_without_mock_reference
  end
end
gc(*objects) click to toggle source

Simulate garbage collection of the objects passed in as arguments. If no objects are specified, all objects will be reclaimed.

# File lib/ref/mock.rb, line 109
def gc(*objects)
  objects = if objects.empty?
    object_space.keys
  else
    objects.map { |obj| obj.__id__ }
  end

  objects.each do |id|
    finalizers = object_space.delete(id)
    if finalizers
      finalizers.each{|finalizer| finalizer.call(id)}
    end
  end
end
setup() click to toggle source

Start using mock references.

# File lib/ref/mock.rb, line 33
def setup
  raise "Ref::Mock already setup" if object_space
  
  @object_space = {}
  
  class << ObjectSpace
    unless method_defined?(:define_finalizer_with_mock_reference)
      def define_finalizer_with_mock_reference(obj, finalizer)
        if ::Ref::Mock.object_space.include?(obj.__id__)
          ::Ref::Mock.object_space[obj.__id__] << finalizer
        else
          define_finalizer_without_mock_reference(obj, finalizer)
        end
      end
    end
    
    alias_method :define_finalizer_without_mock_reference, :define_finalizer
    alias_method :define_finalizer, :define_finalizer_with_mock_reference
  end
  
  class << WeakReference
    unless method_defined?(:new_with_mock_reference)
      def new_with_mock_reference(obj)
        if self == Mock::MockWeakReference
          new_without_mock_reference(obj)
        else
          Mock::MockWeakReference.new(obj)
        end
      end
    end
    
    alias_method :new_without_mock_reference, :new
    alias_method :new, :new_with_mock_reference
  end
  
  class << SoftReference
    unless method_defined?(:new_with_mock_reference)
      def new_with_mock_reference(obj)
        if self == Mock::MockSoftReference
          new_without_mock_reference(obj)
        else
          Mock::MockSoftReference.new(obj)
        end
      end
    end
    
    alias_method :new_without_mock_reference, :new
    alias_method :new, :new_with_mock_reference
  end
end
use() { || ... } click to toggle source

Use the mock implementation inside a block and then restore the original implementation.

# File lib/ref/mock.rb, line 19
def use
  if object_space
    yield
  else
    setup
    begin
      yield
    ensure
      cleanup
    end
  end
end