2008-11-05 28 views

Trả lời

11

Nếu bạn đã đặt trái tim của mình trên mucking với lớp Số (hoặc số nguyên, v.v.) để chuyển đổi đơn vị, thì ít nhất hãy thực hiện nó một cách logic và với một số giá trị thực.

Đầu tiên, tạo một lớp Đơn vị lưu trữ loại đơn vị (mét, chân, hình khối, v.v ...) và giá trị khi tạo. Sau đó, thêm một loạt các phương thức vào Số tương ứng với đơn vị giá trị hợp lệ có thể có: các phương thức này sẽ trả về một đối tượng Đơn vị với kiểu của nó được ghi là tên phương thức. Lớp Đơn vị sẽ hỗ trợ một loạt các phương thức to_ * sẽ chuyển đổi thành một loại đơn vị khác với giá trị đơn vị tương ứng. Bằng cách đó, bạn có thể làm lệnh sau:

>> x = 47.feet.to_meters 
=> 14.3256 
>> x.inspect 
=> #<Unit 0xb795efb8 @value=14.3256, @type=:meter> 

Cách tốt nhất để xử lý nó có lẽ sẽ là một ma trận của các loại chuyển đổi và biểu thức trong lớp đơn vị, sau đó sử dụng method_missing để kiểm tra xem một loại nhất định có thể được chuyển đổi sang loại khác. Trong lớp số, sử dụng method_missing để hỏi Unit nếu nó hỗ trợ phương thức đã cho như là một loại đơn vị, và nếu như vậy, trả về một đối tượng đơn vị của kiểu được yêu cầu bằng cách sử dụng số làm giá trị của nó. Sau đó bạn có thể hỗ trợ thêm các đơn vị và chuyển đổi khi chạy bằng cách thêm một phương thức register_type và register_conversion vào Đơn vị mở rộng ma trận chuyển đổi và Numeric sẽ "tự động" nhận khả năng.

Đối với vị trí đặt, hãy tạo tệp lib/units.rb, cũng sẽ chứa tệp monkey_patch thành Số, sau đó khởi chạy nó trong config/environment.rb bu yêu cầu tệp lib/units.rb.

+1

Điều duy nhất tôi đề nghị làm khác là làm khởi tạo bằng cách sử dụng thư mục initializers thay vì trong environment.rb. Bài đăng tuyệt vời. – jonnii

2

thường (và logic), số nguyên không thể được chuyển đổi sang dặm hoặc để mét. Có vẻ như bạn có thể muốn tạo một lớp mới như "Feet" hoặc "inches" được khởi tạo với một số nguyên, sau đó chứa các phương thức như size_in_miles hoặc size_in_meters. Để thuận tiện các phương pháp đó có thể trở lại thập phân hoặc nổi các loại, nhưng bạn cũng có thể muốn viết một lớp dặm hoặc một lớp mét.

Là một phương pháp thay thế, bạn có thể muốn tạo ra một phương pháp tĩnh trong lớp mới của bạn mà có thể có một chữ ký như thế này:

Float feetToMiles(integer I)

rằng bạn sẽ gọi

miles = Feet.feetToMiles(5280);

và nhận được miles = 1.0

2

Tạo mô-đun/thư viện của riêng bạn ch bạn đưa vào phạm vi khi bạn cần nó để thực hiện tác vụ này.

Chẳng hạn như "requre 'unitCoversions"

Và Rất có thể, ai đó đã làm điều này nếu bạn nhìn cứng đủ :)

Tuy nhiên DONT thử sửa đổi các lớp lõi bản xứ, mà sẽ chỉ kết thúc trong Misery.

(Ngoài ra, lớp bạn muốn mở rộng là 'số', mà sẽ áp dụng cho cả Số nguyên và Floats :))

Không hoàn toàn rõ ràng lý do tại sao tôi không nên làm điều này ... Rails làm điều này cho lớp chuỗi thành công lớn.

Bởi vì nó có thể được thực hiện không có nghĩa là nó nên được thực hiện. 'Khỉ Patching' vì nó được biết đến có thể có tất cả các loại tác dụng phụ lạ, và họ có thể là một thất bại sử thi khi làm sai.

Làm khi không có lựa chọn thay thế tốt.

Vì nếu bạn thực sự muốn làm điều gì đó, bạn có thể xây dựng toàn bộ khuôn khổ TẤT CẢ nó đã làm khỉ vá các lớp lõi.

Ví dụ: lật dữ liệu trên đầu của nó.

5.getArtist(); 
10.getEvent(); 
100.getTrack(); 

v.v. không có giới hạn về số lượng cách xấu để thực hiện điều đó.

"Bob".createUser(); 

đau khổ trong cốc.

Nếu bạn muốn làm điều gì đó thực tế, có một lớp Chuyển đổi hoặc chức năng,

convert(3 , { :from=>:miles, :to=>:meters }); 

ít nhất bạn không làm ô nhiễm các chức năng namespace và lõi toàn cầu như vậy và nó có ý nghĩa mạch lạc hơn.

+0

Không hoàn toàn rõ ràng lý do tại sao tôi không nên làm điều này ... Rails thực hiện điều này với lớp chuỗi thành công lớn. – Ben

-1

Nếu bạn đang đi để làm điều này, mà bạn không nên, sau đó bạn sẽ đặt mã của bạn vào:

config/initializers/add_methods_that_are_naughty_to_numeric.rb 

Rails sẽ tự động chạy những cho bạn.

2

Tại sao không chỉ:

class Feet 
    def self.in_miles(feet) 
    feet/5280 
    end 
end 

sử dụng:

Feet.in_miles 2313 

Hoặc có thể nhìn vào nó theo cách khác:

class Miles 
    def self.from_feet(feet) 
    feet/5280 
    end 
end 

Miles.from_feet 2313 
2

Tôi đồng ý khỉ vá nên được sử dụng một cách cẩn thận, nhưng đôi khi nó chỉ có ý nghĩa. Tôi thực sự thích những người trợ giúp cho phép bạn nhập 5.days.ago là một phần của thư viện active_support

Vì vậy, một số câu trả lời khác có thể tốt hơn trong trường hợp này, nhưng nếu bạn đang mở rộng lớp ruby, chúng tôi giữ tất cả các tiện ích mở rộng trong lib/extensions/class_name.rb

cách này khi làm việc trên một dự án nhanh chóng và dễ dàng để tìm và xem mọi thứ có thể không bình thường với các lớp tiêu chuẩn.

0

Nhận ra câu hỏi là cũ, nhưng tôi nghĩ cách rõ ràng nhất là tạo lớp Khoảng cách với hai thuộc tính @length@unit.

Bạn chỉ cần một băm chuyển đổi, có lẽ như là một biến lớp học của Khỏang cách:

class Distance 

    @@conversion_rates = { 
    meters: { 
     feet: 3.28084, 
     meters: 1.0 
    } 
    } 

    def to(new_unit) 
    new_length = @length * @@conversion_rates[@unit][new_unit] 
    Distance.new(new_length, new_unit) 
    end 

end 

Và nó sẽ trông kinda thích:

Distance.new(3, :meters).to(:feet) 

mà tôi thật sự nghĩ trông tốt hơn so với

3.meters.to_feet 
Các vấn đề liên quan