سؤال

لقد واجهنا مؤخرًا مشكلة حيث فشلت عملية الواجهة الخلفية في التشغيل بعد حدوث سلسلة من الالتزامات.الآن، كنا فتيان وفتيات جيدين وهربنا rake test بعد كل تسجيل وصول، ولكن بسبب بعض الأمور الشاذة في تحميل مكتبة Rails، حدث ذلك فقط عندما قمنا بتشغيلها مباشرةً من Mongrel في وضع الإنتاج.

لقد قمت بتتبع الخطأ وكان ذلك بسبب وجود جوهرة Rails جديدة تقوم بالكتابة فوق طريقة في فئة String بطريقة أدت إلى كسر استخدام محدود في كود Rails وقت التشغيل.

على أي حال، باختصار، هل هناك طريقة، في وقت التشغيل، لسؤال روبي أين تم تعريف الطريقة؟شيء مثل whereami( :foo ) الذي يعود /path/to/some/file.rb line #45؟في هذه الحالة، إخباري أنه تم تعريفه في فئة String لن يكون مفيدًا، لأنه تم تحميله بشكل زائد من قبل بعض المكتبات.

لا أستطيع أن أضمن أن المصدر موجود في مشروعي، لذا فإنني أتطلع إليه 'def foo' لن يعطيني بالضرورة ما أحتاج إليه، ناهيك عما إذا كان لدي كثير def fooأحيانًا لا أعرف حتى وقت التشغيل أي واحد قد أستخدمه.

هل كانت مفيدة؟

المحلول

وهذا هو حقا في وقت متأخر، ولكن هنا كيف يمكنك العثور حيث يتم تعريف طريقة:

http://gist.github.com/76951

# 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>

إذا كنت على روبي 1.9+، يمكنك استخدام <لأ href = "http://www.ruby-doc.org/core-1.9.3/Method.html#method-i-source_location" يختلط = "noreferrer"> 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]

لاحظ أن هذا لن يعمل على كل شيء، مثل التعليمات البرمجية المترجمة الأصلي. و الطريقة الطبقة لديها بعض الوظائف أنيق، أيضا، مثل <ل أ href = "http://www.ruby-doc.org/core-1.9.3/Method.html#method-i-owner" يختلط = "noreferrer"> الطريقة # صاحب التي ترجع الملف حيث ويعرف الأسلوب.

وتحرير: انظر أيضا __file__ و__line__ ومذكرات للالعناصر الأرضية النادرة في إجابة أخرى، وانهم مفيد جدا. - مجموعة العمل

نصائح أخرى

ويمكنك فعلا الذهاب أبعد قليلا من الحل أعلاه. لروبي 1.8 الطبعة المؤسسة، هناك __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

لروبي 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]

وأنا قادم في وقت متأخر لهذا الموضوع، وأنا فوجئت أن لا أحد ذكر Method#owner.

class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A

نسخ إجابتي من الأحدث سؤال مماثل الذي يضيف معلومات جديدة لهذه المشكلة.

روبي 1.9 لديه طريقة تسمى source_location:

يُرجع اسم ملف مصدر Ruby ورقم السطر الذي يحتوي على هذه الطريقة أو لا شيء إذا لم يتم تعريف هذه الطريقة في Ruby (أيمحلي)

وقد تم backported هذا إلى 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، سينبثق هذا أيضًا المحرر في الموقع المحدد.

وهذا قد يساعد ولكن قد تضطر إلى رمز ذلك بنفسك. لصق من بلوق:

<اقتباس فقرة>   

وروبي يوفر method_added ()   رد أن يتم استدعاء كل مرة   يضاف طريقة أو إعادة تعريف ضمن   صف دراسي. انها جزء من الطبقة حدة،   وكل فئة هي وحدة نمطية. هناك   كما دعا اثنين من الاسترجاعات ذات الصلة   method_removed () و   method_undefined ().

http://scie.nti.st / 2008/9/17 / صنع أساليب غير قابل للتغيير في وروبي

إذا تمكنت من تعطيل الطريقة، فستحصل على تتبع خلفي سيخبرك بمكانه بالضبط.

لسوء الحظ، إذا لم تتمكن من تعطله، فلن تتمكن من معرفة المكان الذي تم تعريفه فيه.إذا حاولت التلاعب بهذه الطريقة عن طريق الكتابة فوقها أو تجاوزها، فإن أي تعطل سيأتي من طريقتك المكتوبة أو التي تم تجاوزها، ولن يكون هناك أي فائدة.

طرق مفيدة لطرق التعطل:

  1. يمر nil حيث يحظر ذلك - في كثير من الأحيان ستؤدي الطريقة إلى رفع مستوى ArgumentError أو الحاضر دائمًا NoMethodError على فئة الصفر.
  2. إذا كان لديك معرفة داخلية بهذه الطريقة، وتعلم أن الطريقة بدورها تستدعي طريقة أخرى، فيمكنك الكتابة فوق الطريقة الأخرى، والرفع بداخلها.

وربما #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]

وOR

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]

ولم إجابات الإجابة في وقت متأخر جدا :) ولكن في وقت سابق لم تساعدني

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

وكنت قد تكون قادرة على القيام بشيء من هذا القبيل:

و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

و(لقد افسدت فقط مع القضبان، لذلك أنا لا أعرف بالضبط، ولكن أتصور أن هناك وسيلة لبدء تشغيله نوع من مثل هذا).

وهذا سوف تظهر لك كل إعادة التعاريف من سلسلة # فو. مع القليل الفوقية البرمجة، هل يمكن تعميمها لأي وظيفة تريدها. ولكنها لا تحتاج إلى تحميل BEFORE الملف الذي في الواقع لا إعادة تعريف.

ويمكنك دائما الحصول على المتتبع الخلفي من أين أنت باستخدام caller().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top