2013-02-08 19 views
8

Tôi có một viên ngọc có mã như bên này:Nhận thư mục của tập tin đó khởi tạo một ruby ​​lớp

def read(file) 
    @file = File.new file, "r" 
end 

Bây giờ vấn đề là, nói rằng bạn có một cấu trúc thư mục như sau:

app/main.rb 
app/templates/example.txt 

main.rb có đoạn mã sau:

require 'mygem' 

example = MyGem.read('templates/example.txt') 

Nó đi kèm với File Not Found: templates/example.txt. Nó sẽ hoạt động nếu example.txt nằm trong cùng một thư mục với tên main.rb nhưng không phải nếu nó nằm trong một thư mục. Để giải quyết vấn đề này, tôi đã thêm một đối số tùy chọn được gọi là relative_to trong read(). Điều này có một đường dẫn tuyệt đối để các điều trên có thể cần phải là:

require 'mygem' 

example = MyGem.read('templates/example.txt', File.dirname(__FILE__)) 

Điều đó làm việc tốt, nhưng tôi nghĩ rằng đó là một chút xấu xí. Có anyway để làm cho nó để lớp biết những gì tập tin read() đang được gọi và làm việc ra con đường dựa trên đó?

+2

Thư mục main.rb không liên quan - đó là giá trị của 'Dir.pwd' quan trọng. –

+0

Ahh cảm ơn đó là những gì tôi cần. Vấn đề là 'rspec' dường như không chạy từ thư mục bạn mong đợi. Vì vậy, tham khảo thư mục 'templates' trong' spec/'không hoạt động. – andy

Trả lời

1

Ngoài ra bạn có thể kiểm tra caller:

def read(file) 
    if /^(?<file>.+?):.*?/ =~ caller(1).first 
    caller_dir, caller_file = Pathname.new(Regexp.last_match[:file]).split 
    file_with_path = File.join caller_dir, file 
    @file = File.new "#{file_with_path}", "r" 
    end 
end 

Tôi sẽ không khuyên bạn làm như vậy (các mã trên sẽ phá vỡ được gọi là gián tiếp, vì caller(1), xem tài liệu tham khảo tài liệu hướng dẫn trên caller). Hơn nữa, regex ở trên cần được điều chỉnh chính xác hơn nếu đường dẫn của người gọi được dự định chứa dấu hai chấm.

1

này nên làm việc cho sử dụng điển hình (Tôi không chắc chắn kháng của nó là sử dụng gián tiếp, như đã đề cập bởi madusobwa above):

def read_relative(file) 
    @file = File.new File.join(File.dirname(caller.first), file) 
end 

Trên một mặt lưu ý, cân nhắc việc thêm một hình thức khối của phương pháp của bạn đóng tập tin sau khi sinh. Trong biểu mẫu hiện tại, bạn buộc khách hàng phải sử dụng đá quý của mình với một số ensure.

1

Chấp nhận đường dẫn tệp Chuỗi làm đối số. Chuyển đổi thành đối tượng Pathname. Kiểm tra xem đường dẫn có tương đối hay không. Nếu có, sau đó chuyển đổi thành tuyệt đối.

def read(file) 
    fpath = Pathname.new(file) 
    if fpath.relative? 
    fpath = File.expand_path(File.join(File.dirname(__FILE__),file)) 
    end 
    @file = File.new(fpath,"r") 
end 

Bạn có thể làm cho mã này gọn gàng hơn (ít tiết).

4

Có một thư viện thú vị - i told you it was private. Người ta có thể bảo vệ phương pháp của họ với nó khỏi bị gọi từ bên ngoài. Mã tìm thấy tệp của phương thức của người gọi và xóa nó. Các phạm tội được tìm thấy sử dụng dòng này:

offender = caller[0].split(':')[0] 

Tôi đoán bạn có thể sử dụng nó trong mã MyGem.read của bạn:

def read(file) 
    fpath = Pathname.new(file) 
    if fpath.relative? 
    offender = caller[0].split(':')[0] 
    fpath = File.join(File.dirname(offender), file) 
    end 
    @file = File.new(fpath, "r") 
end 

Bằng cách này bạn có thể sử dụng đường dẫn, liên quan đến người gọi Mygem của bạn và không phải pwd. Chính xác cách bạn đã thử trong số app/main.rb

+0

Heh một viên ngọc rất thú vị :) – Speed

+1

Điều này không phải lúc nào cũng hiệu quả. Nó phá vỡ nếu phương thức được gọi gián tiếp, và nếu phương thức được gọi bởi một thư viện khác. Xem giải pháp của tôi dưới đây. – Linuxios

2

Vâng, bạn có thể sử dụng người gọi và rất đáng tin cậy hơn những gì người khác cũng nói.

Trong tập đá quý của bạn, bên ngoài của bất kỳ lớp hoặc module, đặt này:

c = caller 
req_file = nil 
c.each do |s| 
    if(s =~ /(require|require_relative)/) 
    req_file = File.dirname(File.expand_path(s.split(':')[0])) #Does not work for filepaths with colons! 
    break 
    end 
end 
REQUIRING_FILE_PATH = req_file 

này sẽ làm việc 90% thời gian, trừ kịch bản yêu cầu thực hiện một Dir.chdir. File.expand_path phụ thuộc vào điều đó. Tôi sợ rằng trừ khi người yêu cầu của bạn vượt qua số __FILE__ của họ, bạn không thể làm gì nếu họ thay đổi thư mục làm việc.

Các vấn đề liên quan