2013-03-16 12 views
5

Mam obiekt danych, który zawiera dziesiątki pól attr_accessor dla różnych danych wejściowych. Czy mogę w jakiś sposób zdefiniować klasę tak, aby wszystkie setery dla wszystkich pól były np. ustawić wartość jako pusty ciąg zamiast próby zerowej?attr_accessor, który przekształca zero na ciąg znaków przy pisaniu

+1

Co masz na myśli "usiłowanie Nil"? – Linuxios

+0

Jeśli ktoś spróbuje object.foo = nil, w rzeczywistości zmienna foo zostanie ustawiona na "" zamiast zera. –

Odpowiedz

9

Oto mały moduł do zrobienia to:

module NilToBlankAttrAccessor 

    def nil_to_blank_attr_accessor(attr) 
    attr_reader attr 
    define_method "#{attr}=" do |value| 
     value = '' if value.nil? 
     instance_variable_set "@#{attr}", value 
    end 
    end 

end 

Wystarczy zmieszać go w:

class Foo 
    extend NilToBlankAttrAccessor 
    nil_to_blank_attr_accessor :bar 
end 

i używać go:

foo = Foo.new 
foo.bar = nil 
p foo.bar  # => "" 
foo.bar = 'abc' 
p foo.bar  # => "abc" 

Jak to działa

NilToBlankAttrAccessor#nil_to_blank_attr_accessor pierwszy definiuje attr_reader normalnie:

attr_reader attr 

Następnie definiuje pisarz, definiując metodę o tej samej nazwie, co akcesor, tylko z "=" na końcu. Tak więc, dla atrybutu :bar, metoda nosi nazwę bar=

define_method "#{attr}=" do |value| 
     ... 
    end 

Teraz trzeba ustawić zmienną. Po pierwsze okazuje nil do pustej struny:

 value = '' if value.nil? 

Następnie użyj instance_variable_set, który robi to przypisanie zmiennej instancji gdzie zmienna instancji nie jest znany aż do czasu wykonywania.

 instance_variable_set "@#{attr}", value 

klasy Foo potrzebuje nil_to_blank_attr_accessor być metoda klasy, a nie metoda instancji, więc używa extend zamiast include:

class Foo 
    extend NilToBlankAttrAccessor 
    ... 
end 
+1

To zmieni nie tylko 'zero', ale także' fałsz' na '" ". – sawa

+0

@sawa, dziękuję. Naprawiony. –

+0

@WayneConrad To miła odpowiedź i świetne wyjaśnienie :) –

1

Zamiast robić

object.foo = given_input 

należy zrobić

object.foo = given_input.nil? ? "" : given_input 

lub jeśli chcesz włączyć false do "" jak dobrze, to

object.foo = given_input || "" 
Powiązane problemy