class Module

Public Instance Methods

sync_cattr_accessor(*attributes, &block)
Alias for: sync_mattr_accessor
sync_cattr_reader(*attributes, &block)
Alias for: sync_mattr_reader
sync_cattr_writer(*attributes)
Alias for: sync_mattr_writer
sync_mattr_accessor(*attributes, &block) click to toggle source

Generate a class reader and writer for the attribute

# File lib/sync_attr/class_attributes.rb, line 79
def sync_mattr_accessor(*attributes, &block)
  sync_cattr_writer(*attributes)
  sync_cattr_reader(*attributes, &block)
end
Also aliased as: sync_cattr_accessor
sync_mattr_reader(*attributes, &block) click to toggle source

Lazy load the specific class attribute by calling the supplied block when the attribute is first read and then return the same value for all subsequent calls to the class variable

An optional block can be supplied to initialize the synchronized class attribute when first read. Acts as a thread safe lazy initializer. The block will only be called once even if several threads call the reader at the same time

Example:

require 'sync_attr'
class MyClass
  # Generates a reader for the class attribute 'hello'
  # and Lazy initializes the value to 'hello world' only on the first
  # call to the reader
  sync_cattr_reader :hello do
    'hello world'
  end
end
# File lib/sync_attr/class_attributes.rb, line 20
def sync_mattr_reader(*attributes, &block)
  attributes.each do |attribute|
    raise NameError.new("invalid attribute name: #{attribute}") unless attribute =~ /^[_A-Za-z]\w*$/
    mutex_var_name = "@@sync_attr_#{attribute}".to_sym
    class_variable_set(mutex_var_name, Mutex.new) unless class_variable_defined?(mutex_var_name)
    # Class reader with lazy initialization for the first thread that calls this method
    # Use metaclass/eigenclass to dynamically generate class methods
    (class << self; self; end).instance_eval do
      define_method(attribute.to_sym) do
        var_name = "@@#{attribute}".to_sym
        if class_variable_defined?(var_name)
          # If there is no writer then it is not necessary to protect reads
          if self.respond_to?("#{attribute}=".to_sym, true)
            class_variable_get(mutex_var_name).synchronize { class_variable_get(var_name) }
          else
            class_variable_get(var_name)
          end
        else
          return nil unless block
          class_variable_get(mutex_var_name).synchronize do
            # Now that we have exclusive access make sure that another thread has
            # not just initialized this attribute
            if class_variable_defined?(var_name)
              class_variable_get(var_name)
            else
              class_variable_set(var_name, class_eval(&block))
            end
          end
        end
      end
    end
  end
end
Also aliased as: sync_cattr_reader
sync_mattr_writer(*attributes) click to toggle source

Generates a writer to set a synchronized attribute Supply a Proc ensure an attribute is not being updated by another thread:

MyClass.count = Proc.new {|count| (count||0) + 1}
# File lib/sync_attr/class_attributes.rb, line 58
  def sync_mattr_writer(*attributes)
    attributes.each do |attribute|
      mutex_var_name = "@@sync_attr_#{attribute}".to_sym
      class_variable_set(mutex_var_name, Mutex.new) unless class_variable_defined?(mutex_var_name)
      class_eval(<<-EOS, __FILE__, __LINE__ + 1)
        def self.#{attribute}=(value)
          #{mutex_var_name}.synchronize do
            if value.is_a?(Proc)
              current_value = @@#{attribute} if defined?(@@#{attribute})
              @@#{attribute} = value.call(current_value)
            else
              @@#{attribute} = value
            end
          end
        end
      EOS
    end
  end
Also aliased as: sync_cattr_writer