2016-01-14 14 views
6

Ich habe eine einfache Klasse, die bei der Initialisierung zwischen einem und acht Parametern benötigt. Es stellt die Accessoren für diese später ein. Rubocop versucht mich zu verhaften, weil das ABC zu hoch ist, aber ich bin mir nicht sicher, ob irgendetwas mit dem, was ich getan habe, falsch ist. Ist dies ein Fall, in dem ich die Überprüfung auf meiner Initialisierung einfach deaktiviere?Zuweisung Verzweigungsbedingung zu hoch

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 

Mein einziger Gedanke an Größe zu reduzieren wäre, etwas zu tun wie Iterieren durch alle meine attr_accessors auf initialize, zu sehen, ob es ein entsprechendes Symbol in der hat durchlaufen, und wenn ja zuweisen.

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 

Aber das scheint irgendwie schwach.

Antwort

4

Dies ist eine der Möglichkeiten, zu erreichen, was Sie zu tun versuchen:

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 

prüfen Hash#fetch Verfahrens.

Sie können es auch nur mit dem Schlüssel-Wert-Paare von p Variable, wenn Sie anstelle von 8 Variablen entscheiden, eine (@p)


EDIT

Nur aus gehen Zugang nutzen, um Neugier schrieb diese Version (einige Meta-Programmierung) - es wird dynamisch attr_accessor für zusätzliche Instanzvariablen hinzufügen:

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 

Was geschieht, nehmen wir an initialize Methode Argument (Hash p), erhalten Sie seine Schlüssel und erstellen Instanzvariablen von ihnen, jede Variable mit Wert entsprechend dem Schlüssel zuweisen. Dann definieren wir attr_accessor für jeden der Schlüssel.

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

Das sieht ähnlich aus wie ich dachte, könnte ein Cop out sein. Wortspiel beabsichtigt. Während ich zustimme, dass dies ein Weg ist, das Problem zu lösen, gibt es eine Referenz, auf die Sie mich verweisen könnten, damit ich mehr darüber lesen kann, warum dies der "richtige" Weg ist? Danke, dass Sie sich die Zeit genommen haben, zu antworten! – CarlyL

+0

@CarlyL In Bezug auf den richtigen Weg - Ruby ist eine sehr flexible Sprache, so dass Dinge auf verschiedene Arten getan werden können. Und oft ist der "richtige Weg" eine Frage der persönlichen Vorlieben. Ich denke, du kannst Ruby Style Guides durchlesen, um zu sehen, was ** nicht ** zu tun ist, aber ich bezweifle, dass jemand etwas für 100% richtig hält :) –

+0

Du könntest auch die Namen der Attribute in ein eingefrorenes Array schreiben, wie '' 'ATTR_NAMES =% i (eins zwei drei vier fünf sechs sieben acht) .freeze''' Konstante und rufen' '' attr_accessor (* ATTR_NAMES) '' ' –

2

Sie sollten diese nicht als unterschiedliche Variablen zuweisen. Sie sollten das lieber als einzelnen Hash in einer Variablen speichern und auf den Hash zugreifen, wenn Sie die Werte benötigen. Tatsächlich scheinen Sie bereits eine Variable zu haben. Also behalten Sie das als @p = p.

+0

Danke, dass Sie sich die Zeit genommen haben, zu antworten. Beide Antworten sagen irgendwie, dass ich nur einen attr_accessor p haben kann, was ein Hash ist, aber das scheint mir irgendwie seltsam zu sein. Haben Sie einen Hinweis darauf, warum dies der beste Weg wäre? – CarlyL