Module: RedisMemo::MemoizeMethod

Defined in:
lib/redis_memo/memoize_method.rb

Instance Method Summary collapse

Instance Method Details

#memoize_method(method_name, method_id: nil, **options, &depends_on) ⇒ Object

Core entry method for using RedisMemo to cache a method’s results. When a method is memoized, all calls to the method will first check if the results exist in the RedisMemo cache before calling the original method.

Examples:

class Post < ApplicationRecord
  extend RedisMemo::MemoizeMethod
  def display_title
    "#{title} by #{author.display_name}"
  end
  memoize_method :display_title do |post|
    depends_on Post.where(id: post.id)
    depends_on User.where(id: post.author_id)
  end
end

Parameters:

  • method_name (String)

    The name of the method to memoize

  • method_id (String) (defaults to: nil)

    Optionally, a method_id that’s used to tag APM traces of RedisMemo calls.

  • options (Hash)

    Cache options to pass to RedisMemo. These values will override the global cache options.

  • depends_on (block)

    The method’s dependency block.

    • The first parameter of the block is a reference to the object whose method is being memoized.

    • The rest of the block parameters are the memoized method’s arguments.

    • Within this block, you can declare the method’s dependencies as individual RedisMemo::Memoizable‘s, using the RedisMemo::Dependency.depends_on method. RedisMemo will automatically extract dependencies from this block and use them to compute a method’s versioned cache key.

Options Hash (**options):

  • :expires_in (Integer)

    The TTL for this method’s cached result.

  • :redis_options (Hash)

    Other valid options are ones which are passed along to the Rails RedisCacheStore.



39
40
41
42
43
44
45
46
47
48
49
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
96
97
# File 'lib/redis_memo/memoize_method.rb', line 39

def memoize_method(method_name, method_id: nil, **options, &depends_on)
  method_name_without_memoization = :"_redis_memo_#{method_name}_without_memoization"
  method_name_with_memo = :"_redis_memo_#{method_name}_with_memo"

  alias_method method_name_without_memoization, method_name

  define_method method_name_with_memo do |*args|
    return __send__(method_name_without_memoization, *args) if RedisMemo.without_memoization?

    dependent_memos = nil
    if depends_on
      dependency = RedisMemo::MemoizeMethod.__send__(:get_or_extract_dependencies, self, *args, &depends_on)
      dependent_memos = dependency.memos
    end

    future = RedisMemo::Future.new(
      self,
      case method_id
      when NilClass
        RedisMemo::MemoizeMethod.__send__(:method_id, self, method_name)
      when String, Symbol
        method_id
      else
        method_id.call(self, *args)
      end,
      args,
      dependent_memos,
      options,
      method_name_without_memoization,
    )

    if RedisMemo::Batch.current
      RedisMemo::Batch.current << future
      return future
    end

    future.execute
  rescue RedisMemo::WithoutMemoization
    __send__(method_name_without_memoization, *args)
  end

  ruby2_keywords method_name_with_memo
  alias_method method_name, method_name_with_memo

  @__redis_memo_method_dependencies ||= Hash.new
  @__redis_memo_method_dependencies[method_name] = depends_on

  define_method :dependency_of do |other_method_name, *method_args|
    method_depends_on = self.class.instance_variable_get(:@__redis_memo_method_dependencies)[other_method_name]
    unless method_depends_on
      raise RedisMemo::ArgumentError.new(
        "#{other_method_name} is not a memoized method",
      )
    end

    RedisMemo::MemoizeMethod.__send__(:get_or_extract_dependencies, self, *method_args, &method_depends_on)
  end
  ruby2_keywords :dependency_of
end