Как найти, где метод определяется во время выполнения?
81028 просмотра
10 ответа
Недавно у нас возникла проблема, когда после серии коммитов серверный процесс не запускался. Теперь мы были хорошими мальчиками и девочками и бегали rake test
после каждой регистрации, но из-за некоторых странностей в загрузке библиотеки Rails это происходило только тогда, когда мы запускали ее непосредственно из Mongrel в производственном режиме.
Я отследил ошибку, и это произошло из-за того, что новый драгоценный камень Rails переписал метод в классе String способом, который нарушил одно узкое использование в коде Rails времени выполнения.
В любом случае, если коротко, есть ли способ, во время выполнения, спросить Ruby, где был определен метод? Что-то подобное whereami( :foo )
возвращается /path/to/some/file.rb line #45
? В этом случае, сказать мне, что он был определен в классе String, было бы бесполезно, потому что он был перегружен какой-то библиотекой.
Я не могу гарантировать, что источник живет в моем проекте, поэтому поиск 'def foo'
не обязательно даст мне то, что мне нужно, не говоря уже о том, есть ли у меня их много def foo
, иногда я не знаю до времени выполнения, какой из них я могу использовать.
Ответы (10)
412 плюса
Это действительно поздно, но вот как вы можете найти, где определен метод:
# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
def crime
end
end
class Fixnum
include Perpetrator
end
p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>
Если вы используете Ruby 1.9+, вы можете использовать source_location
require 'csv'
p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>
CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]
Обратите внимание, что это не будет работать на все, как нативный скомпилированный код. Класс Method также имеет несколько полезных функций, таких как Method # owner, который возвращает файл, в котором определен метод.
РЕДАКТИРОВАТЬ: Также см. __file__
И __line__
и примечания для REE в другом ответе, они тоже удобны. - РГ
81 плюса
На самом деле вы можете пойти немного дальше, чем решение выше. Для Ruby 1.8 Enterprise Edition, есть __file__
и __line__
методы на Method
случаях:
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
Для Ruby 1.9 и выше есть source_location
(спасибо Джонатан!):
require 'active_support/all'
m = 2.days.method(:ago)
# => #<Method: Fixnum(Numeric)#ago> # comes from the Numeric module
m.source_location # show file and line
# => ["/var/lib/gems/1.9.1/gems/activesupport-3.0.6/.../numeric/time.rb", 63]
Автор: James Adam
Размещён: 25.08.2010 09:52
37 плюса
Я опаздываю к этой теме и удивляюсь, что никто не упомянул Method#owner
.
class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A
Автор: Alex D
Размещён: 20.02.2012 04:07
12 плюса
Копирование моего ответа из более нового аналогичного вопроса, который добавляет новую информацию к этой проблеме.
В Ruby 1.9 есть метод с именем source_location :
Возвращает имя файла Ruby-источника и номер строки, содержащие этот метод, или nil, если этот метод не был определен в Ruby (т.е. нативном)
Это было перенесено в 1.8.7 этим драгоценным камнем:
Таким образом, вы можете запросить метод:
m = Foo::Bar.method(:create)
А затем спросите source_location
об этом методе:
m.source_location
Это вернет массив с именем файла и номером строки. Например, для ActiveRecord::Base#validates
этого возвращается:
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 не предлагает встроенную поддержку, но есть отличный Gist, основанный source_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]
На компьютерах Mac с установленным TextMate это также вызывает редактор в указанном месте.
Автор: Laas Размещён: 22.10.2012 04:296 плюса
Это может помочь, но вам придется кодировать его самостоятельно. Вставлено из блога:
Ruby предоставляет обратный вызов метода method_added (), который вызывается каждый раз, когда метод добавляется или переопределяется в классе. Это часть класса Module, и каждый класс является модулем. Есть также два связанных обратных вызова, которые называются method_removed () и method_undefined ().
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
Автор: Ken Размещён: 06.10.2008 08:015 плюса
Если вы можете вызвать сбой метода, вы получите обратную трассировку, которая точно скажет вам, где он находится.
К сожалению, если вы не можете разбить его, вы не можете узнать, где он был определен. Если вы попытаетесь изменить метод, перезаписав его или переопределив, любой сбой произойдет из-за перезаписанного или переопределенного метода, и он не будет использоваться.
Полезные способы сбоя методов:
- Пройдите,
nil
где это запрещено, - в большинстве случаев метод будет вызыватьArgumentError
или всегда присутствоватьNoMethodError
в нулевом классе. - Если вы обладаете внутренними знаниями о методе и знаете, что метод в свою очередь вызывает какой-то другой метод, то вы можете перезаписать другой метод и поднять его внутри.
5 плюса
Может быть, #source_location
может помочь найти источник метода.
например:
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]
Автор: Samda
Размещён: 14.07.2016 07:51
3 плюса
Очень поздний ответ :) Но более ранние ответы мне не помогли
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
Автор: tig
Размещён: 14.05.2010 06:36
2 плюса
Вы могли бы сделать что-то вроде этого:
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
(Я только перепутал с рельсами, так что я точно не знаю, но я думаю, что есть способ начать это примерно так.)
Это покажет вам все переопределения String # foo. Немного метапрограммирования вы можете обобщить для любой функции, которую захотите. Но он должен быть загружен ПЕРЕД файлом, который фактически выполняет переопределение.
Автор: AShelly Размещён: 06.10.2008 08:162 плюса
Вы всегда можете получить информацию о том, где вы находитесь, используя caller()
.
Вопросы из категории :
- ruby-on-rails Как я могу "красиво" отформатировать вывод JSON в Ruby on Rails?
- ruby-on-rails Обновление хода сервера на Rails-приложении
- ruby-on-rails Изменения модели документа CouchDB?
- ruby-on-rails JRuby on Rails против Ruby on Rails, в чем разница?
- ruby Вызов команд оболочки из Ruby
- ruby Почему в Ruby нет реального StringBuffer или StringIO?
- ruby Как создать случайный 10-значный номер в рубине?
- ruby Каков наилучший способ конвертировать массив в хеш в Ruby
- runtime Как найти, где метод определяется во время выполнения?
- runtime Можно ли скомпилировать и выполнить новый код во время выполнения в .NET?
- runtime Моно перформанс
- runtime Как узнать, какой тип является вар?
- methods Почему я не могу объявить статические методы в интерфейсе?
- methods Является ли Java «передачей по ссылке» или «передачей по значению»?
- methods Регулярное выражение, которое будет соответствовать объявлению метода Java
- methods Как получить переменные экземпляра в Python?
- definition Что такое «Currying»?
- definition Каков пример Принципа замещения Лискова?
- definition В чем разница между каррированием и частичным применением?