Skip to content

Instantly share code, notes, and snippets.

@jamiew
Created August 22, 2008 23:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamiew/6877 to your computer and use it in GitHub Desktop.
Save jamiew/6877 to your computer and use it in GitHub Desktop.
Allows attributes to be declared as lazy, meaning that they won't be # computed until they are asked for
# pseudoforked from mojombo: http://rubyisawesome.com/2007/10/13/lazy-mixin
# Before you ask--yes, this has a very specific use case and is not
# generally applicable to the problem of fine-grained lazy evaluation.
# But it does *exactly* what I need it to do. =)
# Allows attributes to be declared as lazy, meaning that they won't be
# computed until they are asked for. Just mix this module in:
#
# class Foo
# include Lazy
# ...
# end
#
# To specify a lazy reader:
#
# lazy_reader :att
#
# Then, define a method called __bake__ that computes all your lazy
# attributes:
#
# def __bake__
# @att = ...
# end
#
# That's it! (Tom Preston-Werner: rubyisawesome.com)
module Lazy
module ClassMethods
def lazy_reader(*args)
args.each do |arg|
define_method(arg) do
self.__prebake__
instance_variable_get(('@' + arg.to_s).intern)
end
end
end
end
def __prebake__
return if @__baked__
self.__bake__
@__baked__ = true
end
def self.included(base)
base.extend(ClassMethods)
end
end
# A pedagogical class with a lazy attribute
class Foo
include Lazy
attr_reader :id
lazy_reader :body
def initialize(id)
@id = id
end
def __bake__
puts "__baking__"
@body = "The 30th fibonacci is #{self.fib(30)}"
end
def fib(n)
return 1 if n == 0 || n == 1
return fib(n-1) + fib(n-2)
end
end
t = Foo.new('abc')
puts t.id # => (immediate) "abc"
puts t.body # => (short pause) The 30th fibonacci is 1346269
puts t.body # => (immediate) The 30th fibonacci is 1346269
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment