2009-05-26 27 views
27

Cách tốt nhất để quản lý đường dẫn yêu cầu trong chương trình ruby ​​là gì?Quản lý đường dẫn Ruby

Để tôi cho một ví dụ cơ bản, hãy xem xét một cấu trúc như:

\MyProgram 

\MyProgram\src\myclass.rb 

\MyProgram\test\mytest.rb 

Nếu trong thử nghiệm của tôi tôi sử dụng require '../src/myclass' sau đó tôi chỉ có thể gọi là thử nghiệm từ \MyProgram\test thư mục, nhưng tôi muốn để có thể gọi nó là từ bất kỳ con đường nào!

Các giải pháp tôi đưa ra là xác định trong tất cả các nguồn tập tin dòng sau:

ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(ROOT) và sau đó luôn luôn sử dụng require "#{ROOT}/src/myclass"

Có cách nào tốt hơn để làm điều đó?

Trả lời

12

Dưới đây là một cách thay đổi chút ít để làm điều đó:

$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "src")) 

Bằng cách thêm vào trước đường dẫn đến nguồn của bạn đến $ LOAD_PATH (aka $ :) bạn không cần phải cung cấp gốc, vv một cách rõ ràng khi bạn yêu cầu mã của bạn tức là require 'myclass'

1

câu trả lời của sris là cách tiếp cận tiêu chuẩn.

Một cách khác là đóng gói mã của bạn dưới dạng đá quý. Sau đó rubygems sẽ đảm bảo việc bảo đảm các tệp thư viện của bạn nằm trong đường dẫn của bạn.

9

Cùng, ít ồn ào IMHO:

$:.unshift File.expand_path("../../src", __FILE__) 
require 'myclass' 

hoặc chỉ

require File.expand_path "../../src/myclass", __FILE__ 

Tested với ruby ​​1.8.7 và 1.9.0 trên (Debian) Linux - vui lòng cho tôi biết nếu nó hoạt động trên Windows cũng vậy.

Tại sao một phương pháp đơn giản hơn (ví dụ: 'sử dụng', 'require_relative' hoặc sg như thế này) không được tích hợp vào lib chuẩn? UPDATE: require_relative là có từ 1.9.x

+0

Trong khi nó làm nức cột sống của tôi, đây là lựa chọn tốt nhất mà tôi đã nhìn thấy để thực hiện điều này _inside_ của ruby ​​cho đến nay. – Matt

+0

Đó là để nói, tôi thích nối thêm (không phải trước) đường dẫn đến đường dẫn ruby, vì bạn không vô tình dẫm lên thứ gì đó tồn tại trong các thư viện ruby ​​chuẩn. – Matt

+0

Bạn không có nghĩa là 'Tôi thích thêm (không phụ thêm)' thay vào đó? (Nói cách khác: bạn có thực sự muốn chắc chắn rằng công cụ của bạn được ưu tiên không?) Ví dụ ban đầu của tôi là '$: << newpath' đã được thêm vào, giờ đã sửa nó bằng 'unshift', như câu trả lời trước đó. Cảm ơn – inger

0

Đây là những gì tôi đã kết thúc với - một phiên bản Ruby của một kịch bản setenv shell:

# Read application config              
$hConf, $fConf = {}, File.expand_path("../config.rb", __FILE__) 
$hConf = File.open($fConf) {|f| eval(f.read)} if File.exist? $fConf 

    # Application classpath               
$: << ($hConf[:appRoot] || File.expand_path("../bin/app", __FILE__)) 

    # Ruby libs                  
$lib = ($hConf[:rubyLib] || File.expand_path("../bin/lib", __FILE__)) 
($: << [$lib]).flatten! # lib is string or array, standardize      

Sau đó, tôi chỉ cần phải chắc chắn rằng kịch bản này được gọi là một lần trước bất kỳ điều gì khác và không cần chạm vào từng tệp nguồn.

tôi đặt một số tùy chọn bên trong một tập tin cấu hình, giống như vị trí của bên ngoài (không đá quý) thư viện:

# Site- and server specific config - location of DB, tmp files etc. 
{ 
    :webRoot => "/srv/www/myapp/data", 
    :rubyLib => "/somewhere/lib", 
    :tmpDir => "/tmp/myapp" 
} 

này đã làm việc tốt cho tôi, và tôi có thể tái sử dụng các kịch bản setenv trong nhiều dự án chỉ bằng cách thay đổi các tham số trong tập tin cấu hình. Một lựa chọn tốt hơn nhiều so với các kịch bản lệnh shell, IMO.

+0

@ j-g-faustus: "Hợp nhất __ TẬP_TIN __ với thư mục hoạt động đảm bảo rằng tôi có thể gọi nó từ bất cứ nơi nào": File.expand_path (đường dẫn, cơ sở) sẽ có cùng tác dụng. Bạn có chắc là câu trả lời của bên trên không thực hiện công việc? Điều này cho bạn điều gì? (đặt nó trong test.rb, ví dụ): "đặt File.expand_path" ../../src/myclass ", __ FILE __" – inger

+0

Bạn nói đúng, File.expand_path cũng làm như vậy. Tôi đã cập nhật bài đăng. Nó trở nên sạch hơn một chút, cảm ơn :) Ngoài ra, sự khác biệt chính là đây là một tập lệnh riêng biệt chạy một lần khi khởi động ứng dụng và tôi không cần phải chạm vào từng tệp nguồn. –

30

Như của Ruby 1.9, bạn có thể sử dụng require_relative để làm điều này:

require_relative '../src/myclass' 

Nếu bạn cần điều này cho các phiên bản trước đó bạn có thể lấy nó từ các phần mở rộng đá quý theo this SO comment.

2
Pathname(__FILE__).dirname.realpath 

cung cấp đường dẫn tuyệt đối theo cách năng động.

2

Sử dụng mã sau đây để yêu cầu tất cả "rb" tập tin trong thư mục cụ thể (=> của Ruby 1.9):

path='../specific_folder/' # relative path from current file to required folder 

Dir[File.dirname(__FILE__) + '/'+path+'*.rb'].each do |file| 
    require_relative path+File.basename(file) # require all files with .rb extension in this folder 
end 
Các vấn đề liên quan