2012-04-03 48 views
5

Làm thế nào tôi có thể lấy tên lớp của một thể hiện của BasicObject trong Ruby? Ví dụ: giả sử tôi có điều này:Nhận tên lớp Ruby mà không cần phương thức lớp

class MyObjectSystem < BasicObject 
end 
puts MyObjectSystem.new.class 

Làm cách nào để làm cho mã này thành công?

EDIT: Tôi đã tìm thấy phương pháp thể hiện của đối tượng class được định nghĩa là return rb_class_real(CLASS_OF(obj));. Bất kỳ cách nào để sử dụng điều này từ Ruby?

+1

Bạn có thể cho một ví dụ cụ thể hơn một chút về những gì bạn đang cố gắng làm? Bạn đang hỏi "Nếu tôi có một lớp Foo kế thừa từ BasicObject, có cách nào để xác định rằng một thể hiện của lớp đó là 'Foo' trái ngược với BasicObject" không? Không chắc chắn những gì bạn đang yêu cầu. –

+0

Thực ra, có chính xác! Thay đổi bài đăng để làm rõ – Jwosty

+0

'MyObjectSystem.class.name'? –

Trả lời

8

tôi đã dành một số thời gian chơi đùa với IRB và đến với điều này:

class BasicObject 
    def class 
    klass = class << self; self; end # get the object's singleton class 
    klass.superclass # the superclass of an object's singleton class is that object's class 
    end 
end 

Điều đó sẽ cung cấp cho bất kỳ đối tượng được thừa kế từ BasicObject một phương pháp #class rằng bạn có thể gọi.

Sửa

Tiếp tục giải thích theo yêu cầu trong các ý kiến:

Giả sử bạn có đối tượng obj đó là một thể hiện của lớp Foo. obj nhận các phương thức thể hiện của nó từ các phương thức được xác định trong lớp Foo, ngoài các phương thức được xác định trong lớp cha của Foo và như vậy trên chuỗi thừa kế. Ruby cho phép bạn xác định phương pháp trực tiếp trên một đối tượng mà chỉ có thể truy cập đến đối tượng đặc biệt như thế này

obj = Foo.new 
def obj.hello 
    puts "hello" 
end 

obj.hello #=> hello 

other_obj = Foo.new 
other_obj.hello #=> Method missing error 

Lý do bạn có thể làm điều này là bởi vì mỗi đối tượng có một cái gì đó gọi là một lớp singleton (hoặc đôi khi gọi một eigenclass) mà bạn đang thực sự xác định phương thức trên. Lớp đơn này thực sự tồn tại trong chuỗi kế thừa của đối tượng trực tiếp bên dưới lớp thực tế của đối tượng. Điều đó làm cho lớp thực tế của đối tượng, Foo trong ví dụ này, lớp cha của lớp đơn của đối tượng.

Dòng class << self bạn thấy trong câu trả lời là một cú pháp đặc biệt để nhập phạm vi lớp đơn của đối tượng. Vì vậy, trong ví dụ trên, bạn cũng có thể định nghĩa một phương thức trong lớp singleton của một đối tượng như thế này

class << obj 
    def goodbye 
    puts "goodbye" 
    end 
end 

obj.goodbye #=> goodbye 

Vì vậy, các dòng class << self; self; end đang mở lớp singleton của đối tượng (bất kể đối tượng hiện đang self) và sau đó trở self (self có bây giờ trở thành lớp singleton), sau đó có thể được gán cho một biến để làm những gì bạn muốn.

Tôi khuyên bạn nên đọc Metaprogramming Ruby nếu bạn muốn giải thích rõ hơn về tất cả điều này. Nó chắc chắn cung cấp cho bạn một sự hiểu biết tốt hơn về mô hình đối tượng Ruby nói chung.

+0

Ah, cảm ơn! Điều này dường như làm các trick. – Jwosty

+3

Ồ, thông minh! –

+0

Thật tuyệt vời. Tôi muốn hiểu tại sao và cách thức hoạt động. Bạn có thể cung cấp giải thích chi tiết hơn không? –

1

Tôi phải rời đi sau vài phút để tôi không thể tự mình thử nghiệm, nhưng có vẻ như bạn có thể tạo một mô-đun riêng biệt sử dụng ffi để gọi rb_class_real từ libruby. Nếu tôi có nhiều thời gian hơn thì tôi sẽ kiểm tra nó trước, nhưng không ai khác trả lời và tôi không muốn bạn bỏ rơi bạn hoàn toàn trong cái lạnh.

+1

Được rồi, tôi sẽ xem xét điều này. Cảm ơn! Nhưng bạn có biết một cách Ruby thuần khiết không? Điều đó thật tuyệt. – Jwosty

0

Dựa trên Jeff Smith answer, bạn có thể làm điều này mà không sửa đổi BasicObject:

class << object; self; end.superclass 

nơi object là một thể hiện của một đối tượng mà lớp bạn muốn, ví dụ,

irb(main):001:0> object = BasicObject.new 
(Object doesn't support #inspect) 
=> 
irb(main):002:0> class << object; self; end.superclass 
=> BasicObject 
Các vấn đề liên quan