Recentemente, tivemos um problema em que, após uma série de confirmações, um processo de back-end não foi executado. Agora, éramos bons meninos e meninas e corríamos rake test
após cada check-in, mas, devido a algumas esquisitices no carregamento da biblioteca do Rails, isso só ocorreu quando o rodamos diretamente do Mongrel no modo de produção.
Eu rastreei o bug e isso ocorreu devido a uma nova gema do Rails sobrescrevendo um método na classe String de uma maneira que interrompeu um uso restrito no código Rails em tempo de execução.
Enfim, para encurtar a história, existe uma maneira, em tempo de execução, de perguntar a Ruby onde um método foi definido? Algo assim whereami( :foo )
retorna /path/to/some/file.rb line #45
? Nesse caso, me dizer que ele foi definido na classe String seria inútil, porque estava sobrecarregado por alguma biblioteca.
Eu não posso garantir que a fonte esteja no meu projeto, portanto, aguardar 'def foo'
não necessariamente me dará o que eu preciso, para não mencionar se tenho muitos def foo
, às vezes não sei até o tempo de execução qual deles posso estar usando.
fonte
Respostas:
Isso é realmente tarde, mas eis como você pode encontrar onde um método é definido:
http://gist.github.com/76951
Se você usa Ruby 1.9+, pode usar
source_location
Observe que isso não funcionará em tudo, como código compilado nativo. A classe Method também possui algumas funções interessantes, como Method # owner, que retorna o arquivo em que o método está definido.
EDIT: Veja também os
__file__
e__line__
e notas para REE na outra resposta, que é acessível também. - wgfonte
owner
método2.method(:crime)
?Fixnum
method_missing
. Portanto, se você tiver um módulo ou classe ancestral com umclass_eval
oudefine_method
dentro delemethod_missing
, esse método não funcionará.Você pode realmente ir um pouco além da solução acima. Para o Ruby 1.8 Enterprise Edition, existem os métodos
__file__
e__line__
nasMethod
instâncias:Para Ruby 1.9 e além, existe
source_location
(obrigado Jonathan!):fonte
__file__
e__line__
em qualquerMethod
instância de classe, ex:method(:method).__file__
.m.__file__
em.__line__
foram substituídos porm.source_location
.Estou atrasado para esta discussão e estou surpreso que ninguém tenha mencionado
Method#owner
.fonte
Method#parameters
.Copiando minha resposta de uma pergunta semelhante mais recente que adiciona novas informações a esse problema.
O Ruby 1.9 possui um método chamado source_location :
Isso foi suportado para 1.8.7 por esta jóia:
Então você pode solicitar o método:
E, em seguida, pergunte para
source_location
esse método:Isso retornará uma matriz com o nome do arquivo e o número da linha. Por exemplo, para
ActiveRecord::Base#validates
isso retorna:Para classes e módulos, o Ruby não oferece suporte integrado, mas existe um excelente Gist por aí que se baseia em
source_location
retornar arquivos para um determinado método ou primeiro arquivo para uma classe, se nenhum método foi especificado:Em ação:
Nos Macs com o TextMate instalado, isso também abre o editor no local especificado.
fonte
Isso pode ajudar, mas você teria que codificá-lo. Colado no blog:
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
fonte
Se você pode travar o método, receberá um backtrace que informará exatamente onde ele está.
Infelizmente, se você não pode travá-lo, não pode descobrir onde ele foi definido. Se você tentar usar o método substituindo-o ou substituindo-o, qualquer falha ocorrerá com o seu método substituído ou substituído, e isso não será útil.
Maneiras úteis de travar métodos:
nil
onde ele o proíbe - muitas vezes o método gera umaArgumentError
ou a sempre presenteNoMethodError
em uma classe nula.fonte
require 'ruby-debug'; debugger
em que deseja entrar.Talvez o
#source_location
possa ajudar a descobrir de onde vem o método.ex:
Retorna
OU
Retorna
fonte
Resposta muito tardia :) Mas as respostas anteriores não me ajudaram
fonte
nil
?nil
.»Você pode fazer algo assim:
foo_finder.rb:
Em seguida, verifique se o foo_finder é carregado primeiro com algo como
(Eu só brinquei com trilhos, então não sei exatamente, mas imagino que haja uma maneira de começar dessa maneira.)
Isso mostrará todas as redefinições da String # foo. Com um pouco de metaprogramação, você pode generalizá-lo para qualquer função que desejar. Mas ele precisa ser carregado ANTES do arquivo que realmente faz a redefinição.
fonte
Você sempre pode obter um rastreamento de onde está usando
caller()
.fonte