Module: ExpirationDate::ClassMethods
- Defined in:
- lib/expiration-date.rb
Overview
Container for the class methods to add to including modules.
Instance Method Summary collapse
- #_class_expiration_labels ⇒ Object
- #_class_managers_specials ⇒ Object
-
#_managers_specials ⇒ Object
:stopdoc: Class-level hash used to hold the initialization blocks for the expiring attributes.
-
#expiring_attr(name, age, &block) ⇒ Object
Declares a new instance attribute that will expire after age seconds and be replaced by the results of running the block.
-
#expiring_class_attr(name, age, &block) ⇒ Object
Declares a new class attribute that will expire after age seconds and be replaced by the results of running the block.
Instance Method Details
#_class_expiration_labels ⇒ Object
175 176 177 178 179 |
# File 'lib/expiration-date.rb', line 175 def _class_expiration_labels @_class_expiration_labels ||= Hash.new do |h,k| h[k] = ExpirationLabel.new(Mutex.new) end end |
#_class_managers_specials ⇒ Object
171 172 173 |
# File 'lib/expiration-date.rb', line 171 def _class_managers_specials @_class_managers_specials ||= Hash.new end |
#_managers_specials ⇒ Object
:stopdoc: Class-level hash used to hold the initialization blocks for the expiring attributes.
167 168 169 |
# File 'lib/expiration-date.rb', line 167 def _managers_specials @_managers_specials ||= Hash.new end |
#expiring_attr(name, age, &block) ⇒ Object
Declares a new instance attribute that will expire after age seconds and be replaced by the results of running the block. The block is lazily evaluated when the attribute is accessed after the expiration time. The block is evaluated in the context of the instance (as opposed to being evaluated in the context of the class where the block is declared).
Obviously this scheme will only work if the attribute is only accessed using the setter and getter methods defined by this function.
class A
include ExpirationDate
expiring_attr( :foo, 60 ) { 'foo' }
end
a = A.new
a.foo #=> 'foo'
a.foo = 'bar'
a.foo #=> 'bar'
sleep 61
a.foo #=> 'foo'
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/expiration-date.rb', line 50 def expiring_attr( name, age, &block ) raise ArgumentError, "a block must be given" if block.nil? name = name.to_sym age = Float(age) _managers_specials[name] = block self.class_eval <<-CODE, __FILE__, __LINE__ def #{name} now = Time.now label = _expiration_labels[#{name.inspect}] if label.expires_on.nil? || now >= label.expires_on label.mutex.synchronize { break unless label.expires_on.nil? || now >= label.expires_on block = ::#{self.name}._managers_specials[#{name.inspect}] @#{name} = instance_eval(&block) label.age ||= #{age} label.expires_on = now + label.age } end @#{name} end def #{name}=( val ) now = Time.now label = _expiration_labels[#{name.inspect}] label.mutex.synchronize { @#{name} = val label.age ||= #{age} label.expires_on = now + label.age } @#{name} end def expire_#{name}_now label = _expiration_labels[#{name.inspect}] label.mutex.synchronize {label.expires_on = Time.now - 1} @#{name} end def alter_#{name}_age( age ) label = _expiration_labels[#{name.inspect}] label.mutex.synchronize {label.age = Float(age)} end CODE end |
#expiring_class_attr(name, age, &block) ⇒ Object
Declares a new class attribute that will expire after age seconds and be replaced by the results of running the block. The block is lazily evaluated when the attribute is accessed after the expiration time. The block is evaluated in the context of the class.
Obviously this scheme will only work if the attribute is only accessed using the setter and getter methods defined by this function.
class A
include ExpirationDate
expiring_class_attr( :foo, 60 ) { 'foo' }
end
A.foo #=> 'foo'
A.foo = 'bar'
A.foo #=> 'bar'
sleep 61
A.foo #=> 'foo'
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/expiration-date.rb', line 116 def expiring_class_attr( name, age, &block ) raise ArgumentError, "a block must be given" if block.nil? name = name.to_sym age = Float(age) _class_managers_specials[name] = block self.class_eval <<-CODE, __FILE__, __LINE__ def self.#{name} now = Time.now label = _class_expiration_labels[#{name.inspect}] if label.expires_on.nil? || now >= label.expires_on label.mutex.synchronize { break unless label.expires_on.nil? || now >= label.expires_on block = ::#{self.name}._class_managers_specials[#{name.inspect}] @#{name} = instance_eval(&block) label.age ||= #{age} label.expires_on = now + label.age } end @#{name} end def self.#{name}=( val ) now = Time.now label = _class_expiration_labels[#{name.inspect}] label.mutex.synchronize { @#{name} = val label.age ||= #{age} label.expires_on = now + label.age } @#{name} end def self.expire_#{name}_now label = _class_expiration_labels[#{name.inspect}] label.mutex.synchronize {label.expires_on = Time.now - 1} @#{name} end def self.alter_#{name}_age( age ) label = _class_expiration_labels[#{name.inspect}] label.mutex.synchronize {label.age = Float(age)} end CODE end |