2016-01-14 22 views
6

Tôi có một lớp đơn giản, khi khởi tạo, phải mất từ ​​một đến tám tham số. Nó thiết lập các accessors để sử dụng sau này. Rubocop đang cố gắng bắt tôi vì ABC quá cao, nhưng tôi không chắc là có gì sai với những gì tôi đã làm hay không. Đây có phải là trường hợp tôi chỉ vô hiệu hóa việc kiểm tra khi khởi tạo của tôi không?Chi nhánh chuyển nhượng Điều kiện quá cao

class Foo 
    attr_accessor :one, :two, :three, :four 
    attr_accessor :five, :six, :seven, :eight 

    def initialize(p={}) 
    @one = p[:one] if p[:one].present? 
    # ... 
    @eight = p[:eight] if p[:eight].present? 
    end 
end 

suy nghĩ duy nhất của tôi về việc giảm kích thước sẽ phải làm một cái gì đó giống như lặp qua tất cả attr_accessors tôi trên initialize, nhìn thấy nếu có một biểu tượng tương ứng đi qua trong có, và nếu như vậy gán cho nó.

class Foo 
    attr_accessor :one, :two, :three, :four 
    attr_accessor :five, :six, :seven, :eight 

    def initialize(p={}) 
    instance_variables.each do |variable| 
     send("@#{variable}") = p["#{send(variable)}".to_sym] if p["#{send(variable)}".to_sym].present? 
    end 
    end 
end 

Nhưng điều này có vẻ yếu.

Trả lời

4

Đây là một trong những cách để đạt được những gì bạn đang cố gắng để làm:

class Foo 
    %i(one two three four five six seven eight).each { |attribute| attr_accessor attribute } 

    def initialize(p = {}) 
    p.keys.each { |k| instance_variable_set("@#{k}", p.fetch(k, nil)) } 
    end 
end 

Check-out cho Hash#fetch phương pháp.

Bạn cũng có thể sử dụng nó để chỉ truy cập vào các cặp khóa-giá trị của p biến, nếu bạn thay vì 8 biến quyết định đi với một (@p)


EDIT

Chỉ cần ra khỏi sự tò mò đã viết phiên bản này (một số chương trình meta được sử dụng) - nó sẽ tự động thêm attr_accessor cho các biến mẫu được thêm vào:

class Foo 
    def initialize(p = {}) 
    p.keys.each do |k| 
     instance_variable_set("@#{k}", p.fetch(k, nil)) 
     self.class.__send__(:attr_accessor, k) 
    end 
    end 
end 

Điều gì đang xảy ra, chúng ta được cung cấp cho đối số phương thức initialize (băm p), lấy khóa của nó và tạo các biến mẫu từ chúng, gán cho mỗi biến có giá trị tương ứng với khóa. Sau đó, chúng tôi đang xác định attr_accessor cho mỗi khóa.

a = Foo.new(a: 2, b: 3) 
#=> #<Foo:0x00000002d63ad8 @a=2, @b=3> 
+0

Điều này có vẻ tương tự như những gì tôi đang nghĩ có thể là cảnh sát. Pun dự định. Trong khi tôi đồng ý đây là một cách để giải quyết vấn đề, có một tài liệu tham khảo bạn có thể chỉ cho tôi để tôi có thể đọc thêm về lý do tại sao đây là cách 'đúng'? Cảm ơn vì đã dành thời gian trả lời! – CarlyL

+0

@CarlyL Về đúng cách - Ruby là ngôn ngữ rất linh hoạt, vì vậy mọi thứ có thể được thực hiện theo nhiều cách khác nhau. Và thường là "đúng cách" là vấn đề sở thích cá nhân. Tôi nghĩ bạn có thể đọc qua Hướng dẫn về phong cách Ruby để xem điều gì không ** làm, nhưng tôi nghi ngờ một người nào đó sẽ yêu cầu quyền sở hữu 100% :) –

+0

Bạn cũng có thể đặt tên của các thuộc tính trong một mảng được cố định, như '' 'ATTR_NAMES =% i (một hai ba bốn năm sáu bảy tám) .freeze''' liên tục và gọi' '' attr_accessor (* ATTR_NAMES) '' ' –

2

Bạn không được chỉ định từng biến là các biến khác nhau. Bạn nên lưu nó vào một biến dưới dạng một băm duy nhất và truy cập vào băm khi bạn cần các giá trị. Trong thực tế, bạn dường như có một biến số p. Vì vậy, hãy giữ nguyên đó là @p = p.

+0

Cảm ơn bạn đã dành thời gian trả lời. Cả hai câu trả lời đều nói rằng tôi chỉ có thể có một attr_accessor p là một băm, nhưng điều đó có vẻ kỳ lạ với tôi. Bạn có bất kỳ tài liệu tham khảo tôi có thể đọc là tại sao điều này sẽ là cách tốt nhất? – CarlyL

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