2017-01-05 16 views
6

Tôi có những file sau:Làm thế nào tôi có thể mở rộng một lớp ruby ​​từ một lớp được định nghĩa trong một mô-đun?

file.rb

require_relative 'foo/bar' 
baz = Foo::Stuff::Baz.new 
# do stuff 

foo/bar.rb

require_relative 'stuff/baz' 
module Foo 
    class Bar 
     def initialize 
      # do stuff 
     end 
    end 
end 

foo/stuff/baz.rb

module Foo 
    module Stuff 
     class Baz < Bar 
     end 
    end 
end 

tôi nhận được lỗi sau:

`': uninitialized constant Foo::Stuff::Bar (NameError)

Có điều gì tôi đang làm sai ở đây không? Điều này thậm chí có thể trong Ruby? Trong trường hợp nó quan trọng, tôi chỉ làm điều này bởi vì tôi cần phải kế thừa phương thức khởi tạo cụ thể.

Trả lời

3

Nó chỉ hoạt động tốt khi bạn đặt chúng trong cùng một tập lệnh:

module Foo 
    class Bar 
    def initialize 
     # do stuff 
    end 
    end 
end 

module Foo 
    module Stuff 
    class Baz < Bar 
    end 
    end 
end 

p Foo::Stuff::Baz.ancestors 
#=> [Foo::Stuff::Baz, Foo::Bar, Object, Kernel, BasicObject] 

Vì vậy, nó phải là một vấn đề với cách thức hoặc thứ tự mà bạn yêu cầu các tập tin của bạn.

Ngoài ra, nếu bạn chỉ cần một phương thức cụ thể từ Foo::Bar trong Foo::Stuff::Baz, bạn có thể đặt phương thức này trong mô-đun và bao gồm mô-đun này trong cả hai lớp.

+0

Đúng, bạn đã đúng. Vấn đề là tôi yêu cầu foo/stuff/baz.rb trong foo/bar.rb. Tôi đang đánh dấu câu trả lời của bạn là câu trả lời chính xác. – sluther

1

Foo::Bar được xác định. Bạn cũng có thể truy cập ::Foo::Bar (mô-đun "gốc") khi có sự cố khi tìm đúng không gian tên.

3

foo/stuff/baz.rb của bạn không chứa bất kỳ tuyên bố nào require và bạn không nói gì về chương trình chính. Vì vậy, tôi nghĩ rằng bạn chỉ cần không tải mã.

Ruby không tải tự động tùy thuộc vào đường dẫn thư mục, bạn phải tải mã nguồn một cách rõ ràng. Trong trường hợp của bạn, bạn cần số require_relative '../bar' trong tệp foo/stuff/baz.rb. Sau đó, lớp Foo::Bar được biết:

require_relative '../bar' 

module Foo 
    module Stuff 
     class Baz < Bar 
     end 
    end 
    end 

    p Foo::Stuff::Baz.new 
    p Foo::Stuff::Baz.ancestors 

Kết quả:

#<Foo::Stuff::Baz:0x00000002ff3c30> 
[Foo::Stuff::Baz, Foo::Bar, Object, Kernel, BasicObject] 

Các initialize-phương pháp Foo::Bar được thực thi.


Một kiến ​​trúc thực tế hơn sẽ là sử dụng một tập tin chính nơi bạn tải tất cả các file mã, ví dụ:

foo.rb 
foo/bar.rb 
foo/stuff/baz.rb 

và foo.rb sẽ chứa:

require_relative 'foo/bar' 
require_relative 'foo/stuff/baz' 
+0

tôi có những điều khoản require_relative trong đó, trên thực tế. Tôi nên đưa chúng vào bài viết của tôi. – sluther

+0

Vì vậy, nếu tôi không nhầm, tôi nên có require_relatives cho mọi thứ trong tệp chính. Thay vào đó, tôi sẽ quay lại. – sluther

+0

Cảm ơn, tôi đã tìm ra. Tôi nhận ra rằng vấn đề là câu lệnh require trong tệp foo/bar.rb của tôi. – sluther

0

Nó không hoạt động vì trong không gian tên baz.rb không có bất kỳ tham chiếu đến lớp Bar; đơn giản nên nhập:

class Bar; end 

Vì vậy, cấu trúc baz.rb trở nên đơn giản có: (foo/stuff/baz.rb)

module Foo 
    class Bar; end 
    module Stuff 
    class Baz < Bar 
    end 
    end 
end 
Các vấn đề liên quan