2012-04-30 17 views
6

Nadszedł czas, aby zrobić to krótsze:Jak wygenerować inicjator w Ruby?

class Foo 
    attr_accessor :a, :b, :c, :d, :e 

    def initialize(a, b, c, d, e) 
    @a = a 
    @b = b 
    @c = c 
    @d = d 
    @e = e 
    end 
end 

Mamy '' attr_accessor generowania pobierające i ustawiające.

Czy mamy coś do generowania inicjalizatorów według atrybutów?

+1

możliwe duplikat [idiomatyczne tworzenia obiektów w Ruby] (http://stackoverflow.com/questions/1778638/idiomatic-object-creation-in-ruby) –

+0

'def initialize (* args)' ... '@ a, @ b, @ c, @ d, @ e = args' –

Odpowiedz

1

Możesz użyć klejnotu jak constructor. Z opisu:

Deklaratywne oznacza zdefiniowanie właściwości obiektu poprzez przekazanie skrótu do konstruktora, który ustawi odpowiednie znaki iv.

Jest łatwo wykorzystane:

Class Foo 
    constructor :a, :b, :c, :d, :e, :accessors => true 
end 

foo = Foo.new(:a => 'hello world', :b => 'b',:c => 'c', :d => 'd', :e => 'e') 
puts foo.a # 'hello world' 

Jeśli nie chcesz Ivars wygenerowanych z akcesorów, można pozostawić off: akcesorów => true

Nadzieja to pomaga /Salernost

0
class Foo 
    class InvalidAttrbute < StandardError; end 

    ACCESSORS = [:a, :b, :c, :d, :e] 
    ACCESSORS.each{ |atr| attr_accessor atr } 

    def initialize(args) 
    args.each do |atr, val| 
     raise InvalidAttrbute, "Invalid attribute for Foo class: #{atr}" unless ACCESSORS.include? atr 
     instance_variable_set("@#{atr}", val) 
    end 
    end 
end 

foo = Foo.new(a: 1) 
puts foo.a 
#=> 1 

foo = Foo.new(invalid: 1) 
#=> Exception 
+0

Myślę, że pierwsze zdanie było coś w stylu "Czas, aby było krótsze";) – d11wtq

+0

Yeap. Ale Struct robi to samo pod spodem :) – fl00r

0
class Module 
    def initialize_with(*names) 
    define_method :initialize do |*args| 
     names.zip(args).each do |name,val| 
     instance_variable_set :"@#{name}", val 
     end 
    end 
    end 
end 
+0

Jest to całkiem niezłe, z wyjątkiem tego, że pominie normalne sprawdzanie argumentów 'initialize': initialize_with: a,: b' +' Foo.new (1,2,3,4,5) 'nie spowoduje żadnego błędu. – Casper

+0

@ fl00r Dzięki za edycję; Głupi iPhone'a z wielką literą. – Phrogz

12

Najłatwiejszy:

Foo = Struct.new(:a, :b, :c) 

Generuje zarówno akcesory, jak i inicjator. można dodatkowo dostosować swoją klasę:

Foo = Struct.new(…) do 
    def some_method 
    … 
    end 
end 
+1

To jest miłe. Nigdy wcześniej nie myślałem o tym, żeby użyć Struct w tym celu. Oczywiście wiąże się to z ograniczeniami, takimi jak niezdolność do zejścia z innej klasy. – d11wtq

+2

Możesz także wykonać 'class Foo

+0

@ d11wtq Możesz dziedziczyć z lub do Struct. – steenslag

2

Możemy stworzyć coś podobnego def_initializer tak:

# Create a new Module-level method "def_initializer" 
class Module 
    def def_initializer(*args) 
    self.class_eval <<END 
     def initialize(#{args.join(", ")}) 
     #{args.map { |arg| "@#{arg} = #{arg}" }.join("\n")} 
     end 
END 
    end 
end 

# Use it like this 
class Foo 
    attr_accessor :a, :b, :c, :d 
    def_initializer :a, :b, :c, :d 

    def test 
    puts a, b, c, d 
    end 
end 

# Testing 
Foo.new(1, 2, 3, 4).test 

# Outputs: 
# 1 
# 2 
# 3 
# 4 
+1

+1 za użycie ciągu znaków 'eval', aby wymagać odpowiedniego poziomu. Powinieneś prawdopodobnie umieścić tę metodę na 'Module' lub w klasie singleton' Class', ponieważ nie ma sensu używać tego na obiektach innych niż klasy. – Phrogz

+0

@Phrogz Ah right..thx. Aktualizacja kodu. – Casper

Powiązane problemy