可重复使用的代码块 - Ruby块,Procs,Lambdas

时间:2015-05-22 10:14:00

标签: ruby lambda codeblocks procedures

红宝石新手。写了一个程序,现在尝试元编程。如您所见,我有以下代码。有明显的共同声明。我如何在一个地方写这些并一次又一次地使用它们。 这些陈述是循环的一部分。所以就像我只想要能够插入语句一样。尝试过程似乎有效。但是还没有真正理解它。行话对我而言。 我应该读什么,以及什么是好的来源。 有3个循环要做。循环开始因条件而异,并且每个循环中只有一个语句不同。我该怎么写这个清洁和干燥

@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

1 个答案:

答案 0 :(得分: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

P.S。你不应该调用方法A或S.方法名称必须是小写的,并且应该有意义。