LazyMethods

This adds the ability to declare lazy loading or asynchronous methods.

Lazy Loading Methods

Lazy methods will return immediately with a proxy object. The proxy object will look and act just like the result from calling the method. However, the original method will only be called when a method is invoked on the proxy object.

This pattern works great with caching. You can have your business logic invoke lazy methods and your view logic sitting behind a cache. If the cache is hit, you won’t actually end up invoking any of your business logic.

To define a lazy method, simply include the LazyMethods module in your class definition and then call define_lazy_methods or define_lazy_class_methods with the names of one or more methods defined for your class. This will create lazy versions of the methods with the names prefixed with lazy_.

Example

class MyModel
  include LazyMethods
  define_lazy_methods :calculate_value
  define_lazy_class_methods :find
end

object = MyModel.lazy_find           # The find method will not be called yet
object.to_s                          # The find will will be called here
value = object.lazy_calculate_value  # The calculate_value method will not be called yet
sum = value + 1                      # The calculate_value method will be called here

Asynchronous Methods

Asynchronouse methods are similar to lazy methods. The method call will return immediately with a proxy object. The difference is that the original method will be invoked immediately in a separate thread. When a method is called on the proxy object, the thread will block until the result is returned. This can be useful if you have methods that wait on IO like web service calls.

Example

class MyModel
  include LazyMethods
  define_async_methods :get_related_info
  define_async_class_methods :find
end

objects = MyModel.async_find          # The find method will be called in a new thread
objects.size                          # Execution will wait until the find thread has finished
objects.each do |obj|
  obj.async_get_related_info          # A new thread will be started for each object to call get_related_info
end

Usage Notes

Since lazy methods are not invoked at the time when you call them, there is a chance for the state of you application to change between the time when you invoke a method and when it is actually called.

# In this example, the value of object.value will be 2 when the do_something method is called.
object.value = 1
value = object.lazy_do_somthing
object.value = 2
value.to_s

Similarly, all asynchronous methods must make sure they are thread safe.

Exception handling can also be tricky since exceptions will not be immediately thrown.

value = nil
begin
  value = object.lazy_do_something
rescue => e
  # Exceptions thrown by do_something won't be caught here.
end

value.to_s # Exceptions thrown by do_something will be thrown here instead.

Upgrade Notes

In version 1.x of this gem, lazy methods were automatically available for every method on every object. You must now define which methods should be defined as lazy methods. This change was made so that the code is less intrusive and the lazy method invocations are slightly faster.

In addition, version 2.x of this gem includes the functionality of the async_methods 1.x gem. That gem is no longer being maintained.