2015-05-22 64 views
0

紅寶石的新成員。現在寫一個程序嘗試元編程。正如你可以看到我有下面的代碼。有明顯的共同聲明。我如何在一個地方寫這些並一次又一次地使用它們。 這些語句是循環的一部分。所以它就像我只想有能力插入語句。試過一個proc它似乎工作。但還沒有真正理解它。行話來到我身上。 我應該怎樣讀得很好,什麼是良好的來源。 有3個循環。循環開始是不同的條件和條件只有一個語句是不同的每個循環。我如何寫這個清潔和乾燥可重複使用的代碼塊 - Ruby塊,Procs,Lambdas

@ids.each do |key, ids| 
    key_ids = [] 
    case key 
     when :flows then next 
     when :morals 
     ids.each_with_index do |id, index| 
      relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A 
      relation.merge!(ids_string); relation[:for] = key; relation[key] = id          #Common B 
      relation[:values] = S(@ids[:values][index]) 
      @stack << relation                      #Common C 
      key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D 
     end 
     when :values 
     ids.flatten.uniq.each do |id| 
      relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A 
      relation.merge!(ids_string); relation[:for] = key; relation[key] = id;         #Common B 
      ids.each_with_index { |array, index| !array.include?(id) ? relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) :() } 
      @stack << relation                      #Common C 
      key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D 
     end 
     else 
     ids.each do |id| 
      relation = {for: nil, state: nil}; @objects.each_key { |key| relation[key] = nil unless key == :flows } #Common A 
      relation.merge!(ids_string); relation[:for] = key; relation[key] = id          #Common B 
      @stack << relation                      #Common C 
      key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } #Common D 
     end 
    end 
    !key_ids.empty? ? TaleRelation.where(for: key , key => key_ids).each { |activerecord| activerecord[:state] = nil; @stack << activerecord } :() 
    end 

回答

2

你問的是,即塊和產量。 它的工作原理是這樣的:

def add_with_extra(a, b) 
    c = a + b 
    d = yield(c) 
    c + d 
end 

# > add_with_extra(3, 5) { |c| c * 2 } 
# => 24 
# > add_with_extra(3, 5) { |c| c/2 } 
# => 12 

但在你的情況下,它看起來就像這樣:

case key 
    when :morals 
    ids.each_with_index do |id, index| 
     do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id| 
     relation[:values] = S(@ids[:values][index]) 
     end 
    end 
    when :values 
    ids.flatten.uniq.each do |id| 
     do_processing(ids, basic_relation, key_ids, key, id, index) do |relation, ids, index, id| 
     ids.each_with_index { |array, index| relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id } 
     end 
    end 
    else 
    ids.each do |id| 
     do_processing(ids, basic_relation, key_ids, key, id, index) 
    end 
end 

這是不是真的很好閱讀和理解。相反,我建議做一些重構:

def prepare_relation(basic_relation, key, id) 
    relation = basic_relation.dup 
    relation[:for] = key 
    relation[key] = id 
    relation 
end 

def add_to_stack(relation, key_ids, key, id) 
    @stack << relation 
    key_ids << id unless @stack.find{ |relation| relation.class != Hash && relation[:for] == key.to_s && relation[key] == id } 
end 

basic_relation = {for: nil, state: nil} 
@objects.each_key { |key| basic_relation[key] = nil unless key == :flows } 
basic_relation.merge!(ids_string) 

@ids.each do |key, ids| 
    next if key == :flows 
    key_ids = [] 
    lookup_ids = key == :values ? ids.flatten.uniq : ids 

    lookup_ids.each_with_index do |id, index| 
    relation = prepare_relation(basic_relation, key, id) 
    relation[:values] = S(@ids[:values][index]) if key == :morals 
    if key == :values 
     ids.each_with_index do |array, index| 
     relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id 
     end 
    end 
    add_to_stack(relation, key_ids, key, id) 
    end 

    unless key_ids.empty? 
    TaleRelation.where(for: key , key: key_ids).each do |activerecord| 
     activerecord[:state] = nil 
     @stack << activerecord 
    end 
    end 
end 

在這裏,我概括您switch的主要區別在於:

when :morals 
    ids.each_with_index do |id, index| 
... 
when :values 
    ids.flatten.uniq.each do |id| 
... 
else 
    ids.each do |id| 

的真正區別是隻能用:值的情況下,因爲each_with_index適用於後一種情況也 - 我們不會使用索引。 那麼什麼是不常見的轉化成了簡單的兩如果是:

relation[:values] = S(@ids[:values][index]) if key == :morals 
if key == :values 
    ids.each_with_index do |array, index| 
    relation[:morals] = S(A(relation[:morals]) - A(@ids[:morals][index])) unless array.include? id 
    end 
end 

附:您不應該調用方法A或S.方法名稱必須小寫,並且應該有含義。