Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/54.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何找到在运行时定义方法的位置?_Ruby On Rails_Ruby_Runtime_Methods_Definition - Fatal编程技术网

Ruby on rails 如何找到在运行时定义方法的位置?

Ruby on rails 如何找到在运行时定义方法的位置?,ruby-on-rails,ruby,runtime,methods,definition,Ruby On Rails,Ruby,Runtime,Methods,Definition,我们最近遇到了一个问题,在一系列提交发生后,后端进程无法运行。现在,我们都是好孩子,每次签入后都会运行rake测试,但由于Rails库加载中的一些奇怪之处,只有在生产模式下直接从Mongrel运行时才会发生 我追踪到了这个bug,这是由于一个新的Rails gem覆盖了String类中的一个方法,打破了运行时Rails代码中的一个狭隘用法 总之,长话短说,有没有办法在运行时询问Ruby在哪里定义了方法?类似于wheremi(:foo)的东西,它返回/path/to/some/file.rb行#4

我们最近遇到了一个问题,在一系列提交发生后,后端进程无法运行。现在,我们都是好孩子,每次签入后都会运行
rake测试
,但由于Rails库加载中的一些奇怪之处,只有在生产模式下直接从Mongrel运行时才会发生

我追踪到了这个bug,这是由于一个新的Rails gem覆盖了String类中的一个方法,打破了运行时Rails代码中的一个狭隘用法

总之,长话短说,有没有办法在运行时询问Ruby在哪里定义了方法?类似于
wheremi(:foo)
的东西,它返回
/path/to/some/file.rb行#45
?在这种情况下,告诉我它是在类字符串中定义的是没有帮助的,因为它被某个库重载了


我不能保证源代码存在于我的项目中,因此搜索
'def foo'
不一定能满足我的需要,更不用说如果我有很多
def foo
,有时我直到运行时才知道我可能使用哪一个。

这可能会有所帮助,但你必须自己编写代码。从博客中粘贴:

Ruby提供了一个方法 每次调用 方法是在 班级。它是模块类的一部分, 每个类都是一个模块。有 还有两个相关的回调调用 方法_removed()和 方法_undefined()


如果您可以使该方法崩溃,您将得到一个回溯跟踪,它将准确地告诉您它在哪里


不幸的是,如果您不能使它崩溃,那么您就无法找到它的定义位置。如果您试图通过覆盖或重写该方法来蒙骗该方法,那么任何崩溃都将来自被覆盖或重写的方法,并且不会有任何用处

碰撞方法的有用方法:

  • 在禁止的情况下传递
    nil
    ——很多时候,该方法会在nil类上引发
    ArgumentError
    或始终存在的
    NoMethodError
  • 如果您了解该方法的内部知识,并且您知道该方法反过来调用其他方法,那么您可以重写其他方法,并在该方法内部进行提升

  • 您可能可以执行以下操作:

    foo_finder.rb:

     class String
       def String.method_added(name)
         if (name==:foo)
            puts "defining #{name} in:\n\t"
            puts caller.join("\n\t")
         end
       end
     end
    
    然后确保foo_finder首先加载了如下内容

    ruby -r foo_finder.rb railsapp
    
    (我只是弄乱了rails,所以我不知道确切情况,但我想有一种方法可以像这样启动它。)


    这将向您展示字符串#foo的所有重新定义。通过一点元编程,您可以将其概括为您想要的任何函数。但是它确实需要在实际执行重新定义的文件之前加载。

    使用
    caller()

    这真是太晚了,但下面是如何找到方法定义的位置:

    请注意,这不会在所有情况下都起作用,比如本机编译代码。还有一些简洁的函数,比如返回定义方法的文件

    编辑:另一个答案中的
    \uuuu文件
    \uuu行
    以及REE注释也很方便wg

    非常晚的回答:)但之前的回答对我没有帮助

    set_trace_func proc{ |event, file, line, id, binding, classname|
      printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
    }
    # call your method
    set_trace_func nil
    

    实际上,您可以比上面的解决方案更进一步。对于Ruby 1.8企业版,在
    方法
    实例上有
    文件
    方法:

    require 'rubygems'
    require 'activesupport'
    
    m = 2.days.method(:ago)
    # => #<Method: Fixnum(ActiveSupport::CoreExtensions::Numeric::Time)#ago>
    
    m.__file__
    # => "/Users/james/.rvm/gems/ree-1.8.7-2010.01/gems/activesupport-2.3.8/lib/active_support/core_ext/numeric/time.rb"
    m.__line__
    # => 64
    

    我在这篇文章上迟到了,我很惊讶没有人提到
    方法#所有者

    class A; def hello; puts "hello"; end end
    class B < A; end
    b = B.new
    b.method(:hello).owner
    => A
    
    A类;你好;放“你好”;结束
    B级A
    
    从更新版本复制我的答案,这会为该问题添加新信息

    Ruby1.9的方法名为:

    返回包含此方法的Ruby源文件名和行号,如果此方法未在Ruby中定义(即本机),则返回nil

    此gem已将其后传至1.8.7

    因此,您可以请求该方法:

    m = Foo::Bar.method(:create)
    
    然后询问该方法的
    源位置

    m.source_location
    
    这将返回一个带有文件名和行号的数组。 例如,对于
    ActiveRecord::Base#验证

    ActiveRecord::Base.method(:validates).source_location
    # => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]
    
    对于类和模块,Ruby不提供内置支持,但有一个很好的要点,即基于
    source\u location
    返回给定方法的文件,或者在未指定方法的情况下返回类的第一个文件:

    在行动中:

    where_is(ActiveRecord::Base, :validates)
    
    # => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]
    
    在安装了TextMate的Mac电脑上,这也会在指定位置弹出编辑器。

    也许
    #source_location
    可以帮助找到方法的来源

    例:

    返回

    [project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/associations.rb", line_number_of_where_method_is]
    

    返回

    [project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/validations.rb", line_number_of_where_method_is]
    

    我在任何
    方法
    类实例上都得到了
    文件
    的“NoMethodError:undefined method”,例如:
    方法(:方法)。\uu文件
    你有哪个版本的ruby?ruby 1.8.7(2010-06-23补丁级别299)[x86\u 64-linux]在ruby 1.9上,
    m.uu文件uu
    m.u线uu
    已替换为
    m.source u位置
    source u位置
    适用于Ruby 1.9及以上版本,包括Ruby 1.8.7中的2.1,专门添加了一个特殊方法来查找此信息(在1.9.3中仍然存在)。。。我在下面的回答中给出了详细的信息。我很惊讶你是第一个明确提到这个问题的人。在1.9中引入了另一个鲜为人知的宝藏:
    Method#parameters
    。source\u位置似乎适用于使用activesupport-2.3.14的1.8.7-p334。找到方法后,请尝试方法的
    owner
    方法
    2.方法中的第二个是什么(:犯罪)
    ?类的实例
    Fixnum
    重要注意:这不会从
    method\u missing
    中提取任何动态定义的方法。所以如果你有一个modu
    where_is(ActiveRecord::Base, :validates)
    
    # => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]
    
    ModelName.method(:has_one).source_location
    
    [project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/associations.rb", line_number_of_where_method_is]
    
    ModelName.new.method(:valid?).source_location
    
    [project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/validations.rb", line_number_of_where_method_is]