Class: Module
- Inherits:
-
Object
- Object
- Module
- Defined in:
- lib/sync_attr/class_attributes.rb
Instance Method Summary collapse
-
#sync_mattr_accessor(*attributes, &block) ⇒ Object
(also: #sync_cattr_accessor)
Generate a class reader and writer for the attribute.
-
#sync_mattr_reader(*attributes, &block) ⇒ Object
(also: #sync_cattr_reader)
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.
-
#sync_mattr_writer(*attributes) ⇒ Object
(also: #sync_cattr_writer)
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}.
Instance Method Details
#sync_mattr_accessor(*attributes, &block) ⇒ Object Also known as: sync_cattr_accessor
Generate a class reader and writer for the attribute
79 80 81 82 |
# 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 |
#sync_mattr_reader(*attributes, &block) ⇒ Object Also known as: sync_cattr_reader
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
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# 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 |
#sync_mattr_writer(*attributes) ⇒ Object Also known as: sync_cattr_writer
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}
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# 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 |