2013-10-17 45 views
2

我想爲一個人的名字分配很多屬性,如果該屬性爲空然後更新它,但是如果該屬性已經有值然後跳過它。代碼看起來像這樣:ruby​​優雅的方式來減少分配屬性時的類似代碼

self.first = first_parsed unless self.first 
self.middle = middle_parsed unless self.middle 
self.last = last_parsed unless self.last 
self.title = title_parsed unless self.title 
self.suffix = suffix_parsed unless self.suffix 

是否有任何優雅的方式來做到這一點,以避免重複的代碼?

回答

2
%w(first middle last title suffix).each do |m| 
    self.send("#{m}=",eval("#{m}_parsed")) unless self.send(m) 
end 

短代碼來測試:

class Foo 
    attr_accessor :first,:middle 
    def meth(first_parsed,middle_parsed) 
    %w(first middle).each do |m| 
     self.send("#{m}=",eval("#{m}_parsed")) unless self.send(m) 
    end 
    end 
end 

foo = Foo.new 
foo.meth(11,'wax') 
foo.first # => 11 
foo.middle # => "wax" 
+0

在這個例子中,傳遞給參數的參數'eval'uation只是沒有意義;) –

+0

@DavidUnric我沒有明確你的觀點:) –

1
%w[ first middle last title suffix ].each do |a| 
    send("#{a}=", send("#{a}_parsed")) unless send(a) 
end 
1

這就是我會做

["first", "middle", "last", "title", "suffix"].map do |method| 
    self.send("#{method}=", send("#{method}_parsed")) unless self.send(method) 
end 
0

instance variable set可以幫助在這裏:

class Person 
    def some_setter_method 
    %w(first middle last title suffix).each do |attr| 
     unless instance_variable_get "@#{attr}" 
     instance_variable_set "@#{attr}", method(#{attr}_parsed).call 
     end   
    end 
    end 
end 

我儘量避免使用send,因爲它會調用方法,而不管它的作用域狀態(private public protected)。

+1

在這種情況下,你可以使用['public_send'](http:/ /www.ruby-doc.org/core-2.0.0/Object.html#method-i-public_send)也:) –

1

通常情況下,在Ruby中,我們會做到這一點使用:

self.first ||= first_parsed 
self.middle ||= middle_parsed 
self.last ||= last_parsed 
self.title ||= title_parsed 
self.suffix ||= suffix_parsed 

如果我打算做多一點動態我會做這樣的事情:

class SomeClass 

    def initialize(first_name=nil, middle_name=nil, last_name=nil, title=nil, suffix=nil) 
    @first_name, @middle_name, @last_name, @title, @suffix = first_name, middle_name, last_name, title, suffix 
    end 

    def update(first_parsed, middle_parsed, last_parsed, title_parsed, suffix_parsed) 
    { 
     :first_name => first_parsed, 
     :middle_name => middle_parsed, 
     :last_name => last_parsed, 
     :title  => title_parsed, 
     :suffix  => suffix_parsed 
    }.each{ |k, v| 
     instance_var = "@#{ k }" 
     self.instance_variable_set(instance_var, v) unless self.instance_variable_get(instance_var) 
    } 
    end 

end 

使用它:

some_class_instance = SomeClass.new('foo', 'bar') 
some_class_instance 
# => #<SomeClass:0x007fcb030941a8 
#  @first_name="foo", 
#  @last_name=nil, 
#  @middle_name="bar", 
#  @suffix=nil, 
#  @title=nil> 

some_class_instance.update(
    *%w[ 
    new_first 
    new_middle 
    new_last 
    new_title 
    new_suffix 
    ] 
) 

some_class_instance 
# => #<SomeClass:0x007fcb030941a8 
#  @first_name="foo", 
#  @last_name="new_last", 
#  @middle_name="bar", 
#  @suffix="new_suffix", 
#  @title="new_title"> 

我更喜歡使用某種視覺映射,這就是爲什麼符號對變量的散列存在。使用字符串解析可以更動態地實現這一點,但是當算法的某些部分搞亂時,這可能會導致維護問題,並且唯一的方法是通過在循環內打印。使用這樣的表格可以很容易地搜索特定的kev/value關係。

問題是,當我們生成代碼來動態地做到這一點時,我們可能已經寫了一個簡單的基於||=的塊,然後繼續前進。調試時間會減少,很明顯什麼影響什麼,所有這些都會提高可維護性。所以,我不確定從長遠來看,更具活力的實際購買什麼是有用的。這是我們在編寫代碼時經常做出的折中之一。