2010-07-30 44 views
51

Tôi đang chạy một số mã Ruby có thể xuất hiện một tệp Ruby mỗi khi ngày của nó thay đổi. Trong tệp, tôi có các định nghĩa liên tục, nhưLàm thế nào để xác định lại một hằng số Ruby mà không cần cảnh báo?

Tau = 2 * Pi 

và tất nhiên, chúng làm cho thông báo không mong muốn "đã được khởi tạo" liên tục, vì vậy, tôi muốn có các chức năng sau:

def_if_not_defined(:Tau, 2 * Pi) 
redef_without_warning(:Tau, 2 * Pi) 

tôi có thể tránh được những cảnh báo bằng cách viết tất cả các định nghĩa liên tục của tôi như thế này:

Tau = 2 * Pi unless defined?(Tau) 

nhưng nó được hay cho lắm và một chút ẩm ướt (không DRY).

Có cách nào tốt hơn để def_if_not_defined không? Và làm thế nào để redef_without_warning?

-

Giải pháp nhờ Steve:

class Object 
    def def_if_not_defined(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.const_set(const, value) unless mod.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.send(:remove_const, const) if mod.const_defined?(const) 
    mod.const_set(const, value) 
    end 
end 

A = 1 
redef_without_warning :A, 2 
fail 'unit test' unless A == 2 
module M 
    B = 10 
    redef_without_warning :B, 20 
end 
fail 'unit test' unless M::B == 20 

-

Câu hỏi này là cũ. Đoạn mã trên chỉ cần thiết cho Ruby 1.8. Trong Ruby 1.9, câu trả lời của P3t3rU5 không tạo ra cảnh báo và chỉ đơn giản là tốt hơn.

+5

Tại sao bạn muốn xác định lại một hằng số? Tốt hơn đối với hằng số không gian tên bằng cách giữ chúng trong các lớp hoặc mô-đun của riêng bạn - theo cách này, chúng sẽ không bao giờ xung đột với các hằng số khác. –

+1

Tôi muốn xác định lại một hằng số vì tôi muốn sử dụng hằng số một cách tự nhiên như thể tôi không sử dụng trình tải lại mã nguồn tự động, vì vậy tôi sẽ không chấp nhận bất kỳ câu trả lời "không sử dụng hằng số" nào. –

+2

Điều gì không phù hợp và không BIẾT về 'Tau = 2 * Pi trừ khi được định nghĩa? (Tàu)'? – jrdioko

Trả lời

58

Mô-đun sau có thể làm những gì bạn muốn. Nếu không nó có thể cung cấp một số gợi ý để giải pháp của bạn

module RemovableConstants 

    def def_if_not_defined(const, value) 
    self.class.const_set(const, value) unless self.class.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    self.class.send(:remove_const, const) if self.class.const_defined?(const) 
    self.class.const_set(const, value) 
    end 
end 

Và như một ví dụ của việc sử dụng nó

class A 
    include RemovableConstants 

    def initialize 
    def_if_not_defined("Foo", "ABC") 
    def_if_not_defined("Bar", "DEF") 
    end 

    def show_constants 
    puts "Foo is #{Foo}" 
    puts "Bar is #{Bar}" 
    end 

    def reload 
    redef_without_warning("Foo", "GHI") 
    redef_without_warning("Bar", "JKL") 
    end 

end 

a = A.new 
a.show_constants 
a.reload 
a.show_constants 

Cung cấp đầu ra sau đây

Foo is ABC 
Bar is DEF 
Foo is GHI 
Bar is JKL 

tha thứ cho tôi nếu tôi đã bị phá vỡ bất kỳ ruby điều cấm kỵ ở đây như tôi vẫn còn nhận được đầu của tôi xung quanh một số mô-đun: Class: cấu trúc Eigenclass trong Ruby

+0

Chắc chắn, chìa khóa cho câu trả lời này chỉ đơn giản là lần đầu tiên gọi 'Object.send (: remove_const, 'Tau') nếu Object.const_defined? ('Tau')', mà undefines hằng số, do đó preempting cảnh báo. Cách tiếp cận tuyệt vời. – ghayes

+0

Đúng, hoặc chỉ 'gửi (: remove_const,: CONST) nếu const_defined? (: CONST)' nếu bạn đang ở trong lớp (không phải trường hợp) phạm vi. – thewoolleyman

4

Nếu bạn muốn xác định lại giá trị, sau đó không sử dụng hằng số, hãy sử dụng biến toàn cầu thay thế ($ tau = 2 * Pi), nhưng đó cũng không phải là một cách hay. Bạn nên biến nó thành một biến cá thể của một lớp phù hợp.

Đối với trường hợp khác, Tau = 2 * Pi unless defined?(Tau) là hoàn toàn ổn và dễ đọc nhất, do đó giải pháp thanh lịch nhất.

2

Trừ khi các giá trị của hằng số là khá kỳ lạ (ví dụ: bạn có hằng số thiết lập để nil hoặc false), sự lựa chọn tốt nhất là nên sử dụng toán tử gán có điều kiện: Tau ||= 2*Pi

này sẽ thiết lập Tàu đến 2π nếu nó là nil, false hoặc không được xác định, và để nó một mình nếu không.

+1

Ý tưởng tuyệt vời ... Thật không may, nó không phải là rất xách tay: tùy thuộc vào phiên bản ruby ​​và thực hiện (ruby/jruby), sự ảnh hưởng đến một hằng số với || = đã cho tôi ba kết quả khác nhau. Hoặc là nó hoạt động lặng lẽ như dự định (jruby1.5), hoặc là tôi nhận được lỗi "uninitialized constant" (ruby1.8), hoặc là tôi nhận được cảnh báo ngay cả khi không có sự ảnh hưởng nào xảy ra (jruby1.2). –

3

Cách tiếp cận khác, bằng cách sử dụng $ VERBOSE, để chặn cảnh báo, được thảo luận tại đây: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/

+2

Có. Như đã đề cập trong liên kết của bạn, thực hiện tốt hơn các silence_warnings tồn tại trong Rails: http://api.rubyonrails.org/classes/Kernel.html#M002564 Nhưng cách tiếp cận đó thấp hơn câu trả lời được chấp nhận, bởi vì nó có thể có tác dụng phụ trên chủ đề. –

1

Điều gì sau đây?

TAU ||= 2 * Pi 

Nó hoạt động trên đá quý mà tôi đang nghiên cứu.

+5

Điều này sẽ không bao giờ xác định lại một hằng số, do đó không phải là câu trả lời cho câu hỏi. Làm thế nào mà nó thậm chí còn có 8 phiếu bầu? – jrochkind

+1

Vâng, nó trả lời def_if_not_defined (: Tau, 2 * Pi) và tôi nghĩ rằng đó là câu hỏi ban đầu, không chắc chắn, nó được một thời gian dài trước đây – P3t3rU5

+1

Ngoài ra xác định lại hằng số là một lạm dụng ngôn ngữ, ngay cả khi bạn có thể làm điều đó , không phải lúc nào bạn cũng nên làm – P3t3rU5

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