module AdLint::Memoizable

Public Instance Methods

memoize(name, *opts) click to toggle source
# File lib/adlint/memo.rb, line 35
def memoize(name, *opts)
  force_nullary, key_indices = extract_memoize_options(opts)
  case
  when instance_method(name).arity == 0 || force_nullary
    memoize_nullary_method(name)
  when instance_method(name).arity == 1 || key_indices.size == 1
    memoize_unary_method(name, key_indices.first || 0)
  else
    memoize_polynomial_method(name, key_indices)
  end
end

Private Instance Methods

cache_name_of(name) click to toggle source
# File lib/adlint/memo.rb, line 202
def cache_name_of(name)
  "@__cache_of__#{name.to_s.sub("?", "_p")}"
end
define_key_generator(name, key_indices) click to toggle source
# File lib/adlint/memo.rb, line 178
    def define_key_generator(name, key_indices)
      if key_indices.empty?
        class_eval <<-EOS
          define_method(:__key_for_#{name}) do |*args|
            args
          end
        EOS
      else
        class_eval <<-EOS
          define_method(:__key_for_#{name}) do |*args|
            args.values_at(#{key_indices.join(',')})
          end
        EOS
      end
      class_eval "private(:__key_for_#{name})"
    end
extract_memoize_options(opts) click to toggle source
# File lib/adlint/memo.rb, line 48
def extract_memoize_options(opts)
  hash = opts.first || {}
  [hash[:force_nullary], hash[:key_indices] || []]
end
memoize_nullary_method(name) click to toggle source
# File lib/adlint/memo.rb, line 53
    def memoize_nullary_method(name)
      save_memoizing_method(name)
      prepare_nullary_method_cache(name)
      class_eval <<-EOS
        define_method(:#{name}) do |*args|
          if #{cache_name_of(name)}_initialized ||= false
            #{cache_name_of(name)}_forbidden = false
            #{cache_name_of(name)}
          else
            if #{cache_name_of(name)}_forbidden ||= false
              #{cache_name_of(name)}_forbidden = false
              #{orig_name_of(name)}
            else
              #{cache_name_of(name)}_initialized = true
              #{cache_name_of(name)} = #{orig_name_of(name)}(*args)
            end
          end
        end
      EOS
    end
memoize_polynomial_method(name, key_indices) click to toggle source
# File lib/adlint/memo.rb, line 101
    def memoize_polynomial_method(name, key_indices)
      save_memoizing_method(name)
      prepare_polynomial_method_cache(name, key_indices)
      class_eval <<-EOS
        define_method(:#{name}) do |*args|
          key = __key_for_#{name}(*args)
          if #{cache_name_of(name)}_initialized ||= false
            #{cache_name_of(name)}_forbidden = false
            if #{cache_name_of(name)}.include?(key)
              #{cache_name_of(name)}[key]
            else
              #{cache_name_of(name)}[key] = #{orig_name_of(name)}(*args)
            end
          else
            if #{cache_name_of(name)}_forbidden ||= false
              #{cache_name_of(name)}_forbidden = false
              #{orig_name_of(name)}(*args)
            else
              #{cache_name_of(name)}_initialized = true
              #{cache_name_of(name)} = {}
              #{cache_name_of(name)}[key] = #{orig_name_of(name)}(*args)
            end
          end
        end
      EOS
    end
memoize_unary_method(name, key_index) click to toggle source
# File lib/adlint/memo.rb, line 74
    def memoize_unary_method(name, key_index)
      save_memoizing_method(name)
      prepare_unary_method_cache(name, key_index)
      class_eval <<-EOS
        define_method(:#{name}) do |*args|
          key = args[#{key_index}]
          if #{cache_name_of(name)}_initialized ||= false
            #{cache_name_of(name)}_forbidden = false
            if #{cache_name_of(name)}.include?(key)
              #{cache_name_of(name)}[key]
            else
              #{cache_name_of(name)}[key] = #{orig_name_of(name)}(*args)
            end
          else
            if #{cache_name_of(name)}_forbidden ||= false
              #{cache_name_of(name)}_forbidden = false
              #{orig_name_of(name)}(*args)
            else
              #{cache_name_of(name)}_initialized = true
              #{cache_name_of(name)} = {}
              #{cache_name_of(name)}[key] = #{orig_name_of(name)}(*args)
            end
          end
        end
      EOS
    end
orig_name_of(name) click to toggle source
# File lib/adlint/memo.rb, line 206
def orig_name_of(name)
  "__orig_#{name}"
end
prepare_nullary_method_cache(name) click to toggle source
# File lib/adlint/memo.rb, line 128
    def prepare_nullary_method_cache(name)
      class_eval <<-EOS
        define_method(:forbid_once_memo_of__#{name}) do
          #{cache_name_of(name)}_forbidden = true
        end
        define_method(:clear_memo_of__#{name}) do
          #{cache_name_of(name)} = nil
          #{cache_name_of(name)}_initialized = false
        end
        define_method(:forget_memo_of__#{name}) do
          clear_memo_of__#{name}
        end
      EOS
    end
prepare_polynomial_method_cache(name, key_indices) click to toggle source
# File lib/adlint/memo.rb, line 160
    def prepare_polynomial_method_cache(name, key_indices)
      define_key_generator(name, key_indices)
      class_eval <<-EOS
        define_method(:forbid_once_memo_of__#{name}) do
          #{cache_name_of(name)}_forbidden = true
        end
        define_method(:clear_memo_of__#{name}) do
          #{cache_name_of(name)} = nil
          #{cache_name_of(name)}_initialized = false
        end
        define_method(:forget_memo_of__#{name}) do |*args|
          if #{cache_name_of(name)}_initialized
            #{cache_name_of(name)}.delete(__key_for_#{name}(*args))
          end
        end
      EOS
    end
prepare_unary_method_cache(name, key_index) click to toggle source
# File lib/adlint/memo.rb, line 143
    def prepare_unary_method_cache(name, key_index)
      class_eval <<-EOS
        define_method(:forbid_once_memo_of__#{name}) do
          #{cache_name_of(name)}_forbidden = true
        end
        define_method(:clear_memo_of__#{name}) do
          #{cache_name_of(name)} = nil
          #{cache_name_of(name)}_initialized = false
        end
        define_method(:forget_memo_of__#{name}) do |*args|
          if #{cache_name_of(name)}_initialized
            #{cache_name_of(name)}.delete(args[#{key_index}])
          end
        end
      EOS
    end
save_memoizing_method(name) click to toggle source
# File lib/adlint/memo.rb, line 195
    def save_memoizing_method(name)
      class_eval <<-EOS
        alias_method(:#{orig_name_of(name)}, :#{name})
        private(:#{orig_name_of(name)})
      EOS
    end