【问题标题】:Reusable Code Chunks - Ruby Blocks, Procs, Lambdas可重用代码块 - Ruby 块、Procs、Lambdas
【发布时间】:2015-08-04 07:39:16
【问题描述】:

红宝石新手。写了一个程序现在尝试元编程。如您所见,我有下面的代码。有标记的常用语句。我如何将这些写在一个地方并一次又一次地使用它们。 这些语句是循环的一部分。所以就像我只想有插入语句的能力。尝试了一个proc,它似乎可以工作。但是还没有真正理解好。行话让我明白了。 我应该好好阅读什么以及什么是好的来源。 有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

【问题讨论】:

    标签: ruby lambda codeblocks procedures


    【解决方案1】:

    您要问的是,即阻止和让步。 它的工作原理是这样的:

    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|
    

    真正的区别只在于 :values 的情况,因为each_with_index 也适用于最后一种情况——我们只是不会使用索引。 那么不常见的就变成了简单的两个if:

    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。方法名称必须小写并且应该有意义。

    【讨论】:

      猜你喜欢
      • 2014-12-23
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 2013-11-12
      • 1970-01-01
      • 2015-01-25
      • 2014-06-26
      • 1970-01-01
      相关资源
      最近更新 更多