Skip to content

Instantly share code, notes, and snippets.

@hassox
Created August 14, 2012 19:14
Show Gist options
  • Save hassox/3351876 to your computer and use it in GitHub Desktop.
Save hassox/3351876 to your computer and use it in GitHub Desktop.
Quick lazy attribute concern
module Concerns
# Wraps methods to provide lazy attribute evaluation
# If a value evaluates to a proc, the proc is called, and the value
# is returned
#
# @example
# class Foo
# include Concerns::LazyAttributes
#
# attr_accessor :bar
# lazy_attributes :bar
# end
#
# foo = Foo.new
# foo.bar = lambda{ :some_value }
# foo.bar == :some_value
module LazyAttributes
extend ActiveSupport::Concern
module ClassMethods
# Makes the list of attributes lazy.
# If the value of the attribute is a proc,
# then it will be evaluated on the first time the method is called
def lazy_attributes(*attrs)
attrs.each do |attr|
var_sym = :"@lazy_attribute_#{attr}"
define_method "#{attr}_with_lazy_attribute" do
if instance_variable_defined?(var_sym)
return instance_variable_get(var_sym)
end
val = send("#{attr}_without_lazy_attribute")
val = Proc === val ? val.call : val
instance_variable_set(var_sym, val)
val
end
alias_method_chain attr, :lazy_attribute
# update the setter so that we can clear the lazy value
if public_instance_methods.include?(:"#{attr}=")
define_method "#{attr}_with_lazy_attribute=" do |val|
if instance_variable_defined?(var_sym)
remove_instance_variable(var_sym)
end
send "#{attr}_without_lazy_attribute=", val
end
alias_method_chain "#{attr}=", :lazy_attribute
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment