ฉันจะรับซอร์สโค้ดของวิธีการแบบไดนามิกได้อย่างไรและไฟล์ใดเป็นวิธีการค้นหาในไฟล์


90

ฉันต้องการทราบว่าฉันสามารถรับซอร์สโค้ดวิธีการได้ทันทีหรือไม่และฉันสามารถรับไฟล์ที่เป็นวิธีนี้ได้หรือไม่

ชอบ

A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE

คำตอบ:


117

ใช้source_location:

class A
  def foo
  end
end

file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"

โปรดทราบว่าสำหรับวิธีการในตัว, ผลตอบแทนsource_location nilหากต้องการตรวจสอบซอร์สโค้ด C (ขอให้สนุก!) คุณจะต้องมองหาไฟล์ C ที่ถูกต้อง (มีการจัดเรียงตามคลาสมากหรือน้อย) และค้นหาrb_define_methodวิธีการ (ในตอนท้ายของไฟล์ ).

ใน Ruby 1.8 ไม่มีวิธีนี้ แต่คุณสามารถใช้อัญมณีนี้ได้


2
สวัสดีฉันมาจากอนาคตโดยใช้ Ruby 2.6.1! ฉันต้องการซอร์สโค้ดของString#include?. String.instance_method(:include?).source_locationผลตอบแทนที่ไกลออกnilไป
S. Goswami

39

จนถึงขณะนี้ไม่มีคำตอบใดที่แสดงวิธีการแสดงซอร์สโค้ดของวิธีการได้ทันที ...

จริงๆแล้วมันง่ายมากถ้าคุณใช้อัญมณี 'method_source' ที่ยอดเยี่ยมโดย John Mair (ผู้ผลิต Pry): ต้องใช้วิธีนี้ใน Ruby (ไม่ใช่ C) และต้องโหลดจากไฟล์ (ไม่ใช่ irb)

นี่คือตัวอย่างการแสดงซอร์สโค้ดวิธีการในคอนโซล Rails ด้วย method_source:

  $ rails console
  > require 'method_source'
  > I18n::Backend::Simple.instance_method(:lookup).source.display
    def lookup(locale, key, scope = [], options = {})
      init_translations unless initialized?
      keys = I18n.normalize_keys(locale, key, scope, options[:separator])

      keys.inject(translations) do |result, _key|
        _key = _key.to_sym
        return nil unless result.is_a?(Hash) && result.has_key?(_key)
        result = result[_key]
        result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
        result
      end
    end
    => nil 

ดูสิ่งนี้ด้วย:


1
ฉันพลาดฟีเจอร์นี้ใน Ruby มาตลอด เสียงกระเพื่อมทำได้ :)
จนถึง

มาจาก sourceClojure สิ่งนี้ได้ผลตามที่คาดไว้
Sebastian Palma

ฉันได้รับข้อผิดพลาดนี้: [1] pry(main)> RSpec.method(:class_exec).source MethodSource::SourceNotFoundError: Could not locate source for class_exec! from /home/vagrant/.bundle/foo/ruby/2.5.0/gems/method_source-0.9.2/lib/method_source.rb:24:in `source_helper'
อับราม

RSpec.method(:to_json).source_locationทำงานได้ดี
อับราม


10

โดยไม่ต้องพึ่งพา

method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define 
IO.readlines(file_path)[line-1, 10]

หากคุณต้องการใช้สิ่งนี้ให้สะดวกยิ่งขึ้นคุณสามารถเปิดMethodคลาส:

# ~/.irbrc
class Method
  def source(limit=10)
    file, line = source_location
    if file && line
      IO.readlines(file)[line-1,limit]
    else
      nil
    end
  end
end

แล้วก็โทร method.source

ด้วย Pryคุณสามารถใช้show-methodเพื่อดูแหล่งที่มาของวิธีการและคุณยังสามารถดูซอร์สโค้ด Ruby c ที่pry-docติดตั้งได้ตามเอกสารของ pry ในcodde-browing

โปรดทราบว่าเรายังสามารถดูวิธีการ C (จาก Ruby Core) โดยใช้ปลั๊กอิน pry-doc นอกจากนี้เรายังแสดงไวยากรณ์ทางเลือกสำหรับ show-method:

pry(main)> show-method Array#select

From: array.c in Ruby Core (C Method):
Number of lines: 15

static VALUE
rb_ary_select(VALUE ary)
{
    VALUE result;
    long i;

    RETURN_ENUMERATOR(ary, 0, 0);
    result = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
            rb_ary_push(result, rb_ary_elt(ary, i));
        }
    }
    return result;
}

เป็นความคิดที่ดีสำหรับsourceวิธีการในMethodชั้นเรียน จะดียิ่งขึ้นถ้ามันประมวลผลข้อความและใหม่เมื่อหยุดพิมพ์เพราะมันถึงจุดสิ้นสุดของวิธีการแล้ว
Toby 1 Kenobi

4

ฉันสร้างอัญมณี "ri_for" เพื่อจุดประสงค์นี้

 >> require 'ri_for'
 >> A.ri_for :foo

... แสดงแหล่งที่มา (และตำแหน่งหากคุณใช้ 1.9)

GL. - ร


ทั้งหมดนี้สำหรับฉันทำให้เกิดข้อผิดพลาดในการแบ่งส่วน :(
panzi

จะทำซ้ำข้อผิดพลาดของ seg ได้อย่างไร? method / class ไหน
rogerdpack

1

ฉันต้องใช้คุณลักษณะที่คล้ายกัน (คว้าแหล่งที่มาของบล็อก) เป็นส่วนหนึ่งของWrongและคุณสามารถดูวิธีการ (และอาจใช้รหัสซ้ำ) ในchunk.rb (ซึ่งอาศัย RubyParser ของ Ryan Davis และบางเรื่องตลก ซอร์สไฟล์glomming code ) คุณจะต้องแก้ไขเพื่อใช้งานMethod#source_locationและอาจปรับแต่งสิ่งอื่น ๆ เพื่อให้ทำหรือไม่รวมไฟล์def.

BTW ฉันคิดว่า Rubinius มีคุณสมบัตินี้ในตัวด้วยเหตุผลบางประการจึงถูกปล่อยออกจาก MRI (การใช้งาน Ruby มาตรฐาน) ดังนั้นการแฮ็กนี้

โอฉันชอบบางสิ่งในmethod_source ! เช่นเดียวกับการใช้ eval เพื่อบอกว่านิพจน์นั้นถูกต้องหรือไม่ (และเก็บบรรทัดซอร์ส glomming ไว้จนกว่าคุณจะหยุดรับข้อผิดพลาดในการแยกวิเคราะห์เช่น Chunk ทำ) ...


1

วิธีการภายในไม่มีแหล่งที่มาหรือตำแหน่งต้นทาง (เช่นInteger#to_s)

require 'method_source'
User.method(:last).source
User.method(:last).source_location
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.