Sha256: fff1567ae52cbc4ad08fcc2ea855c60e58f32bfac6cff5c53881a994d3102a77

Contents?: true

Size: 1.26 KB

Versions: 1

Compression:

Stored size: 1.26 KB

Contents

require 'monitor'
require 'synchronizable/version'

# Synchronizable is intended to be injected into objects via Object#extend.
# After Object#extend(Synchronizable) is performed, the object's original
# methods will become synchronized via a per-instance lock.
module Synchronizable
  IGNORABLE_METHOD_OWNERS = [Object, Kernel, BasicObject]

  def self.extended(obj)
    # immediately create object-level lock
    obj.send(:__lock)

    # redefine all user-defined methods to utilize lock
    obj.methods.each do |m|
      original_method = obj.method(m)
      next if IGNORABLE_METHOD_OWNERS.include?(original_method.owner)

      without_sync_method = "#{original_method.name}_without_sync"
      obj.define_singleton_method(without_sync_method, original_method)
      obj.define_singleton_method(m) do |*args, &block|
        __lock.synchronize do
          send(without_sync_method, *args, &block)
        end
      end
    end

    # define synchronize method that executes a block
    # protected with the internal instance lock
    obj.define_singleton_method(:synchronize) do |&block|
      __lock.synchronize(&block)
    end
  end

  private

  def __lock
    # Monitor is used instead of Mutex in order to support
    # re-entrant locking
    @__lock ||= Monitor.new
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
synchronizable-0.0.3 lib/synchronizable.rb