当在其中调用proc时,ruby instance_eval将进入stac级别太深

时间:2022-01-07 18:56:29

I run into really interesting problem with ruby today. I have a module/rails concern :

今天我遇到了红宝石真正有趣的问题。我有一个模块/轨道问题:

module BreakCacheModule
  extend ActiveSupport::Concern      

  module ClassMethods
    def breakable_cache_for(method_name, &block)
      method_name = method_name.to_sym
      set_breakable_cache_proc(method_name, block)
      define_breakable_cache_method(method_name)
    end

    def define_breakable_cache_method(method_name) 
      instance_eval(
        "def #{method_name}
          # here will be Rails.cache.fetch block around line below once I figure out this problem
          @_break_cache_procs[#{method_name}].call  # !!! this line will cause an issue
        end"
      )
    end

    def set_breakable_cache_proc(method_name, block)
      @_break_cache_procs ||={}
      @_break_cache_procs.merge!({method_name => block})
      @_break_cache_procs
    end
  end

end

and in my model

在我的模型中

class Client < ActiveRecord::Base
  include BreakCacheModule

  breakable_cache_for :all_client_ids do
    Client.pluck :id
  end
end

so sofar so good but once I go into console (Or run my spec) problems will show up

这么好,但一旦我进入控制台(或运行我的规格)问题将出现

Client.all_client_ids 
# SystemStackError: stack level too deep

but when I do:

但当我这样做时:

Client.instance_variable_get("@_break_cache_procs")[:all_client_ids].call
#=> [1,2,3]

The functionality is exactly the same, only difference is that I'm not calling proc from instance_eval.

功能完全相同,唯一的区别是我没有从instance_eval调用proc。

Am I missing something ??

我错过了什么?

my ruby ruby-2.0.0-p247 and Rails 3.2.14

我的ruby ruby​​-2.0.0-p247和Rails 3.2.14

Thank you for help

谢谢你的帮助


Update after accepting

接受后更新

Just to sum this up, I was getting actually this error from two places:

总而言之,我从两个地方得到了这个错误:

    "def #{method_name}
      Rails.cache.fetch(#{method_name.to_s}) do     # method_name should be in quotes
        @_break_cache_procs[#{method_name}].call    # missing colon ...look on answer 
      end
    end"

so the code should look like this

所以代码看起来应该是这样的

  instance_eval(
    "def #{method_name}
      Rails.cache.fetch('#{method_name.to_s}') do
        @_break_cache_procs[:#{method_name}].call
      end
    end"
  )

1 个解决方案

#1


3  

The string passed to instance_eval is actually:

传递给instance_eval的字符串实际上是:

"def all_client_ids
  @_break_cache_procs[all_client_ids].call
end"

You may have noticed the problem: a colon is missing.

您可能已经注意到了这个问题:缺少冒号。

This should be the correct code:

这应该是正确的代码:

def define_breakable_cache_method(method_name) 
  instance_eval(
    "def #{method_name}
      # here will be Rails.cache.fetch block around line below once I figure out this problem
      @_break_cache_procs[:#{method_name}].call  # !!! this line will cause an issue
    end"
  )
end

#1


3  

The string passed to instance_eval is actually:

传递给instance_eval的字符串实际上是:

"def all_client_ids
  @_break_cache_procs[all_client_ids].call
end"

You may have noticed the problem: a colon is missing.

您可能已经注意到了这个问题:缺少冒号。

This should be the correct code:

这应该是正确的代码:

def define_breakable_cache_method(method_name) 
  instance_eval(
    "def #{method_name}
      # here will be Rails.cache.fetch block around line below once I figure out this problem
      @_break_cache_procs[:#{method_name}].call  # !!! this line will cause an issue
    end"
  )
end