Module: SyncAttr::Attributes::ClassMethods
- Defined in:
- lib/sync_attr/attributes.rb
Instance Method Summary collapse
-
#sync_attr_accessor(*attributes, &block) ⇒ Object
Generate a reader and writer for the attribute.
-
#sync_attr_reader(*attributes, &block) ⇒ Object
Thread-safe access to attributes in an object.
-
#sync_attr_writer(*attributes) ⇒ Object
Generates a writer to set a synchronized attribute Supply a Proc ensure an attribute is not being updated by another thread: my_object.count = Proc.new {|count| (count||0) + 1}.
Instance Method Details
#sync_attr_accessor(*attributes, &block) ⇒ Object
Generate a reader and writer for the attribute
78 79 80 81 |
# File 'lib/sync_attr/attributes.rb', line 78 def sync_attr_accessor(*attributes, &block) sync_attr_reader(*attributes, &block) sync_attr_writer(*attributes) end |
#sync_attr_reader(*attributes, &block) ⇒ Object
Thread-safe access to attributes in an object.
Attributes protected with ‘sync_attr_reader`, `sync_attr_writer`, and/or `sync_attr_accessor` can be safely read and written across many threads.
Additionally ‘sync_attr_reader` supports lazy loading the corresponding attribute in a thread-safe way. While the value is being calculated / loaded all other threads calling that attribute will block until the value is available
An optional block can be supplied to initialize the 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:
class MyClass
include SyncAttr::Attributes
# Generates a reader for the attribute 'hello'
# and Lazy initializes the value to 'hello world' only on the first
# call to the reader
sync_attr_reader :hello do
'hello world'
end
end
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 53 54 |
# File 'lib/sync_attr/attributes.rb', line 28 def sync_attr_reader(*attributes, &block) attributes.each do |attribute| raise NameError.new("invalid attribute name: #{attribute}") unless attribute =~ /^[_A-Za-z]\w*$/ self.send(:define_method, attribute.to_sym) do var_name = "@#{attribute}".to_sym if instance_variable_defined?(var_name) # If there is no writer then it is not necessary to protect reads if respond_to?("#{attribute}=".to_sym, true) sync_attr_sync(attribute) { instance_variable_get(var_name) } else instance_variable_get(var_name) end else return nil unless block sync_attr_sync(attribute) do # Now that we have exclusive access make sure that another thread has # not just initialized this attribute if instance_variable_defined?(var_name) instance_variable_get(var_name) else instance_variable_set(var_name, instance_eval(&block)) end end end end end end |
#sync_attr_writer(*attributes) ⇒ Object
Generates a writer to set a synchronized attribute Supply a Proc ensure an attribute is not being updated by another thread:
my_object.count = Proc.new {|count| (count||0) + 1}
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/sync_attr/attributes.rb', line 59 def sync_attr_writer(*attributes) attributes.each do |attribute| raise NameError.new("invalid attribute name: #{attribute}") unless attribute =~ /^[_A-Za-z]\w*$/ class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{attribute}=(value) sync_attr_sync('#{attribute}') 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 |