Ruby rails 中 _url _path 方法是什么怎么生成的?

googya · 2013年11月19日 · 最后由 googya 回复于 2013年11月21日 · 5830 次阅读

之前看到有人提过相应的源代码在哪里,不过我现在忘记了,刚好在看 DTrace 有关的资料,Ruby 2.0.0 也提供了 Provider,于是我想试试通过查方法调用的过程,能不能发现点线索(有不正确的地方,希望大家指出来)。

首先是准备 dtrace 脚本,如下:

#!/usr/sbin/dtrace -Zs
#pragma D option quiet
#pragma D option switchrate=10

self int depth;


ruby*:::method-entry
/pid == $target/
{
   self->name = copyinstr(arg1);
   printf("%*s-> %s in %s  @ %d \n", self->depth * 2,  "",  self->name,   copyinstr(arg2), arg3);
   self->depth++;
}

ruby*:::method-return
/pid == $target/
{
   this->name = copyinstr(arg1);
   self->depth -= self->depth > 0 ? 1 : 0;
   printf("%*s<- %s  @ %s \n",self->depth * 2, "", self->name,  copyinstr(arg2) );
}

有关 ruby 的 Provider,可以参见 DTraceProbes

然后运行脚本:

chmod +x ruby_call_flow.d
sudo ./ruby_call_flow.d  > d_result.txt

接着开一个 rails 项目的控制台,执行如下语句:

rails c 
app.user_path('aaa')

可以得到如下的结果:

-> user_path in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb  @ 215 
  -> hash_for_user_path in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb  @ 180 
  <- hash_for_user_path  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb 
  -> url_for in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/url_for.rb  @ 143 
    -> _routes in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/url_for.rb  @ 148 
    <- _routes  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/url_for.rb 
    -> url_options in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/testing/integration.rb  @ 189 
    <- url_options  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/testing/integration.rb 
    -> url_for in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb  @ 579 
                                  -> escape_path in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/journey-1.0.4/lib/journey/router/utils.rb  @ 44 
                                  <- escape_path  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/journey-1.0.4/lib/journey/router/utils.rb 
      -> url_for in /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/http/url.rb  @ 23 
      <- url_for  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/http/url.rb 
    <- url_for  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb 
  <- url_for  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/url_for.rb 
<- user_path  @ /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb 

输出格式有点乱,看图:

看了对应的代码,

          def define_url_helper(route, name, kind, options)
            selector = url_helper_name(name, kind)
            hash_access_method = hash_access_name(name, kind)
binding.pry
            @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
              remove_possible_method :#{selector}
              def #{selector}(*args)
                url_for(#{hash_access_method}(*args))
              end
            END_EVAL
            helpers << selector
          end

也有定义这些方法的过程。

也不知道找对地方了没有?

大家一般遇到常用的方法,而且想找到对应的源码的时候,都是怎么做的?

pry 里 show-method app.some_path 也可以

@luikore 嗯,怎么把这个方法给忘记了!印象中,这个方式还可以找到对应的 c 代码

[2] pry(main)> show-method app.user_path

From: /Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb @ line 215: Owner: #Module:0x007f8f163be8e8 Visibility: public Number of lines: 3

def 0;34#{selector}(*args)
  url_for(0;34#{hash_access_method}(*args))
end

看来地方是找对了

还可以用这个方法,即使是在 irb 中:

app.method(:user_path).source_location

=>

["/Users/leslie/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.15/lib/action_dispatch/routing/route_set.rb",
 215]
需要 登录 后方可回复, 如果你还没有账号请 注册新账号