Làm thế nào để có được tên của phương thức gọi?


161

Có cách nào trong Ruby để tìm tên phương thức gọi bên trong một phương thức không?

Ví dụ:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end


nhận đối tượng gọi: stackoverflow.com/questions/2703136/
Ấn

Không phải là bản sao của "Lấy tên của phương thức hiện được thực thi trong Ruby." Câu hỏi này yêu cầu tên của phương thức gọi, không phải tên của phương thức hiện tại.
Wayne Conrad

Câu trả lời:


210
puts caller[0]

hoặc có lẽ...

puts caller[0][/`.*'/][1..-2]


10
Điều đó cho biết tên của phương thức gọi, nhưng nó không đưa ra bất kỳ dấu hiệu nào cho mô-đun hoặc lớp mà phương thức đó thuộc về. Điều đó có thể không?
thomthom

@thomthom Có, bạn có thể gọi self. class.name để xem tên lớp
Thorin

Sử dụng tuyệt vời của regex như một chỉ số chuỗi! Cũng có thể sử dụngcaller[0][/`(.*)'/,1]
aks

1
Điều này dường như không hoạt động trong Rails 5.2.1. Trong Rails điều khiển này trả về "block in make_lambda". Tôi đoán cái này chỉ dành cho Ruby.
dcangulo

164

Trong Ruby 2.0.0, bạn có thể sử dụng:

caller_locations(1,1)[0].label

nhanh hơn nhiều so với giải pháp Ruby 1.8+:

caller[0][/`([^']*)'/, 1]

Sẽ được bao gồm trong backportskhi tôi nhận được thời gian (hoặc yêu cầu kéo!).


Điều đáng chú ý là điều này không có sẵn trong Rubinius.
Tối đa

1
Nếu bạn sử dụng pry, bạn phải bỏ qua stack prace thì có vẻ như ... dường như không có giải pháp mặc định nào cho việc đó.
dtc

6
Bây giờ có vẻ như caller_locations[0].labeltrên Ruby 2.2.0, bạn luôn có send_actionkết quả
brcebn 16/2/2016

1
Làm thế nào chúng ta chỉ có thể gọi phương thức ứng dụng và bỏ qua cuộc gọi khung?
Ma trận

31

Sử dụng caller_locations(1,1)[0].label(cho ruby> = 2.0)

Chỉnh sửa : Câu trả lời của tôi là nói sử dụng __method__nhưng tôi đã sai, nó trả về tên phương thức hiện tại.


1
@OswaldoFerreira Cảm ơn, đã tìm thấy nó trên SO trong một câu trả lời khác ở đâu đó
Dorian

5
Điều này không chính xác, nó trả về phương thức hiện tại, không phải phương thức được gọi là phương thức hiện tại ...
thrice801

1
hoạt động như một lá bùa. Cũng có vẻ là nhanh hơn nhiều so với các phương pháp trước 2.0.
Dr.Strangelove

21

tôi sử dụng

caller[0][/`([^']*)'/, 1]

4
Lợi thế của việc này so với phương pháp của DigitalRoss là gì?
Andrew Grimm

2
Sạch hơn và chính xác hơn. Thay vì thực hiện tìm kiếm, sau đó sử dụng một phương thức mảng để phân chia các ký tự không mong muốn dựa trên vị trí (có thể không chính xác).
New Alexandria

2
Tại sao không chỉ đơn giản sử dụng trình gọi [0] [/ `(. *) '/, 1]? Tôi không phải là một bậc thầy về các biểu thức thông thường, nhưng nó có vẻ hiệu quả.
collimarco

7
@collimarco Miễn là Chuỗi không chứa 'vượt quá cái bạn đang tìm kiếm (và tôi cho rằng nó không thể), kết quả sẽ giống nhau, chắc chắn. Tuy nhiên, [^']*sẽ hoạt động tốt hơn vì công cụ regex sẽ ngừng cố gắng khớp phần đó với biểu thức thời điểm nó đạt đến '(phiên bản của bạn sẽ kết thúc, sau đó quay lại vì không tìm thấy 'ở cuối). Tất nhiên, sự khác biệt là không đáng kể trong trường hợp này, nhưng đó là một thói quen tốt để tránh .trong các chế độ có thể.
Thor84no

4

Làm thế nào về

caller[0].split("`").pop.gsub("'", "")

Imo sạch hơn nhiều.


3

Thay vào đó bạn có thể viết nó dưới dạng chức năng thư viện và thực hiện cuộc gọi bất cứ khi nào cần. Mã này như sau:

module CallChain
  def self.caller_method(depth=1)
    parse_caller(caller(depth+1).first).last
  end

  private

  # Copied from ActionMailer
  def self.parse_caller(at)
    if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
      file   = Regexp.last_match[1]
      line   = Regexp.last_match[2].to_i
      method = Regexp.last_match[3]
      [file, line, method]
    end
  end
end

Để kích hoạt phương thức mô-đun trên, bạn cần gọi như sau: caller = CallChain.caller_method

mã tham chiếu từ


1
Liên kết đến một giải pháp tiềm năng luôn được chào đón, nhưng vui lòng thêm ngữ cảnh xung quanh liên kết để người dùng đồng nghiệp của bạn sẽ có một số ý tưởng về nó là gì và tại sao nó lại ở đó. Luôn trích dẫn phần có liên quan nhất của một liên kết quan trọng, trong trường hợp trang đích không thể truy cập được hoặc ngoại tuyến vĩnh viễn. Hãy xem xét rằng hầu như không có nhiều hơn một liên kết đến một trang web bên ngoài là một lý do có thể là Tại sao và làm thế nào một số câu trả lời bị xóa? .
Xavi López

@ XaviLópez đã cập nhật câu trả lời, xin vui lòng chỉnh sửa nếu tôi làm sai hoặc có gì đó nhầm lẫn ... thnx cho đề xuất loại :)
amit karsale

1
Cảm ơn đã cải thiện câu trả lời của bạn. Thật không may, tôi không có đủ kiến ​​thức về Ruby để có thể nhận xét đúng về bài đăng này, nhưng câu trả lời có vẻ ổn ngay bây giờ. Tôi đã gỡ bỏ downvote của tôi.
Xavi López

2

Để xem thông tin người gọi và callee bằng bất kỳ ngôn ngữ nào, cho dù đó là ruby ​​hay java hay python, bạn sẽ luôn muốn nhìn vào dấu vết ngăn xếp. Trong một số ngôn ngữ, chẳng hạn như Rust và C ++, có các tùy chọn được tích hợp trong trình biên dịch để bật một số loại cơ chế định hình mà bạn có thể xem trong thời gian chạy. Tôi tin rằng một tồn tại cho Ruby được gọi là ruby-prof.

Và như đã đề cập ở trên, bạn có thể nhìn vào ngăn xếp thực thi cho ruby. Ngăn xếp thực thi này là một mảng chứa các đối tượng vị trí backtrace.

Về cơ bản tất cả những gì bạn cần biết về lệnh này như sau:

người gọi (start = 1, length = nil) → mảng hoặc nil

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.