2014-04-20 19 views
5

Bu bir ortak başlatıcı desen:initialize() ayarı için kısayol özniteliklere mi?

def initialize(title, val, type) 
    @title, @val, @type = title, val, type 
end 

"aynı ada sahip bir öznitelik oluşturmak, Her tartışmayı almak ve argümanının değeri eşit özelliğini ayarlamak" eşdeğerdir kısayol var mı?

Gem-free bir çözüm arıyorum.

+0

Bu konu hakkında oldukça iyi bir konu. http://stackoverflow.com/questions/2680523/dry-ruby-initialization-with-hash-argument – Jazzepi

+0

@Jazzepi, bu ilginç bir iş parçacığı, ancak yalnızca karma tartışmalarla ilgilidir. –

cevap

2

İşte bunu nasıl yapabileceğiniz. initialize parametresinin her biri için @ ile aynı ada sahip değişken ile bir örnek değişkeni ve ilişkili bir okuma/yazma erişimi oluşturulacak ve her bir değişkene ilgili parametrenin değeri atanacaktır.

Kod

class MyClass 
    def initialize(< arbitrary parameters >) 
    self.class.params.each { |v| 
     instance_variable_set("@#{v}", instance_eval("#{v}")) } 

    < other code > 
    end 

    @params = instance_method(:initialize).parameters.map(&:last) 
    @params.each { |p| instance_eval("attr_accessor :#{p}") } 

    class << self 
    attr_reader :params 
    end 

    < other code >  
end 

Örnek

class MyClass 
    def initialize(a, b, c) 
    self.class.params.each { |v| 
     instance_variable_set("@#{v}", instance_eval("#{v}")) } 
    end 

    @params = instance_method(:initialize).parameters.map(&:last) 
    @params.each { |p| instance_eval("attr_accessor :#{p}") } 

    class << self 
    attr_reader :params 
    end 
end 

MyClass.methods(false) 
    #=> [:params] 
MyClass.instance_methods(false) 
    #=> [:a, :a=, :b, :b=, :c, :c=] 

m = MyClass.new(1,2,3) 
m.a #=> 1 
m.b #=> 2 
m.C#=> 3 
m.a = 4 
m.a #=> 4 

açıklama

sınıfı MyClass ayrıştırılır, sınıf örneği değişken @params atanmış olan bir elemanları, initialize parametresidir. Bu @params = ... başlayan kod ayrıştırıldığında yöntem initialize oluşturulduğundan, bu mümkündür.

Method#parameters yöntemi initialize parametresinin elde edilmesinde kullanılır. Yukarıdaki Örneğin,

instance_method(:initialize).parameters 
    #=> [[:req, :a], [:req, :b], [:req, :c]] 

yüzden

@params = instance_method(:initialize).parameters.map(&:last) 
    #=> [:a, :b, :c] 
Sonra okuma/yazma erişenleri oluşturmak

: initialize tarafından kullanılmak üzere

@params.each { |p| instance_eval("attr_accessor :#{p}") } 

ve @params için okundu erişimcisi,:

class << self 
    attr_reader :params 
end 

MyClass örneğinin my_class örneği oluşturulduğunda, MyClass.new'a iletilen parametre değerleri initialize'a geçirilir. initialize, sınıf örneği @params değişkenine rağmen döngüler yapar ve her örnek değişkenin değerini ayarlar.Bu örnekte,

MyClass.new(1,2,3) 

çağırır

a => 1 
b => 2 
c => 3 

Biz initialize(a,b,c):

params ( :a) birinci elemanı için
params = self.class.params 
    #=> [:a, :b, :c] 

params.each { |v| instance_variable_set("@#{v}", instance_eval("#{v}")) } 

, bu:

instance_variable_set("@a", instance_eval(a) } 
olduğu:

instance_variable_set("@a", 1 } 

@a neden 1 atanacak.

Not @params için erişimci gerekli değildir:

class MyClass 
    def initialize(a, b, c) 
    self.class.instance_variable_get(:@params).each { |v| 
     instance_variable_set("@#{v}", instance_eval("#{v}")) } 
    end 

    @params = instance_method(:initialize).parameters.map(&:last) 
    @params.each { |p| instance_eval("attr_accessor :#{p}") } 
end 
3

Sen yukarıda da belirtildiği gibi Structkullanabilir veya benzeri dinamik yapabilirsiniz: Neyse

class MyClass 

    def initialize input 
    input.each do |k,v| 
     instance_variable_set("@#{k}", v) unless v.nil? 
    end 
    end 

end 

benim kod buysa ben olacak Struct kullanarak git.

4

Yanlış argümanlar karşı kontrol etmek fonksiyonunu kaybeder, ama bunu yapabilirsiniz:

def initialize(*args) 
    @title, @val, @type = args 
end 

Ama defalarca böyle yapıyorsun, sonra kod doğru değil. Sen en iyisi isimli değişkenler almak için API yeniden tasarlamak gerekir:

def initialize(title:, val:, type:) 
    ... 
end 

WhateverClass.new(title: "foo", val: "bar", type: "baz") 
+0

sadece basit ve en iyi –

1

Ben sadece bir bağımsız değişken karma kullanabilir ve örneğine her özelliğini göndermek isterler. Ancak bu, bu öznitelikler için erişim sağlayıcıları oluşturmayacaktır, böylece istenirse bunları eklemeniz gerekecektir.

def initialize(args) 
    args.each do |method, value| 
    self.send("#{method}=", value) 
    end 
end 
İlgili konular