DRY for Ruby变量循环

时间:2016-12-15 09:37:37

标签: ruby

我在下面的红宝石中有一个def。 我可以做些什么让它变干吗?像:

[e,t,l,te,le,le].each |xxx| do
  if xxx
end

这意味着为"变量"而不仅仅是" Enumerator"。

代码:

def findLogs (obj)
  if e=obj['E']
    e=obj['E']['pkg'] ? "@E = #{obj['E']['pkg']},":nil
  else nil
  end
  if t=obj['T']
    t=obj['T']['pkg'] ? "@T = #{obj['T']['pkg']},":nil
  else nil
  end
  if l=obj['L']
    l=obj['L']['pkg'] ? "@L = #{obj['L']['pkg']},":nil
  else nil
  end
  if te=obj['Te']
    te=obj['Te']['pkg'] ? "@Te = #{obj['Te']['pkg']},":nil
  else nil
  end
  if le=obj['Le']
    le=obj['Le']['pkg'] ? "@Le = #{obj['Le']['pkg']},":nil
  else nil
  end
end

3 个答案:

答案 0 :(得分:4)

e, t, l, te, le = %w|E T L Te Le|.map do |s|
  obj[s] && obj[s]['pkg'] ? "@#{s} = #{obj[s]['pkg']}," : nil
end

对于Sergio Tulentsev:

b = binding
%w|E T L Te Le|.each do |s|
  b.local_variable_set(
    s.downcase.to_sym,
    obj[s] && obj[s]['pkg'] ? "@#{s} = #{obj[s]['pkg']}," : nil
  )
end

答案 1 :(得分:2)

正如Stefan在评论中提到的,如果你不使用它们,在findLogs中定义局部变量是没有意义的。即使你定义了两次;)。

您的代码中并不清楚。如果你想通过在String中编写Ruby代码来定义实例变量,然后使用eval:请不要!

obj = {
  'E'  => nil,
  'T'  => { 'pkg' => 't_pkg' },
  'L'  => { 'not_pkg' => 'x' },
  'Te' => { 'pkg' => 'te_pkg' }
}

%w(E T L Te Le).each do |var_name|
  instance_variable_set("@#{var_name}", obj.dig(var_name, 'pkg'))
end

p [@E, @T, @L, @Te, @Le] # => [nil, "t_pkg", nil, "te_pkg", nil]

答案 2 :(得分:1)

这看起来更像是JS函数而不是Ruby:)

很少有事情需要注意:

  1. 不使用变量,因此您可以删除它们
  2. 有很多else nil可以删除,因为Ruby方法默认返回nil
  3. 您只是使用三元运算符返回nil,再次,您可以避免它
  4. 这种方法做了太多事情:它检查它是什么类型的日志,并显示/格式化它
  5. 样式注释:在Ruby中我们使用snake_case,因此该方法应该被称为find_logs
  6. 你可以避免重复,如上所述,并用以下内容替换:

    def find_logs(obj)
      log_type = ["E", "T", "L", "Te", "Le"].detect do |type|
        obj[type] && obj[type]["pkg"]
      end
    
      "@#{log_type} = #{obj[log_type]['pkg']}," if log_type
    end
    

    现在,这不是特别漂亮,它仍然做两件不同的事情,但它可能已经足够好了,并且它删除了重复。

    我不知道你正在尝试解决的问题,但正如我们在Ruby中所做的那样,最好用类来解决它,例如这样的事情(没有经过测试,所以它可能不起作用):

    class LogFormatter
      LOG_TYPES = ["E", "T", "L", "Te", "Le"]
    
      def initialize(obj:)
        @obj = obj
      end
    
      def format
        "@#{log_type} = #{pkg}," if log_type
      end
    
      private
    
      attr_reader :obj
    
      def pkg
        @pkg ||= obj[log_type]["pkg"]
      end
    
      def log_type
        @log_type ||= LOG_TYPES.detect { |type| obj[type] && obj[type]["pkg"] }
      end
    
    end
    

    现在,请记住,根据你想要做的事情,这可能有点矫枉过正 - 但就个人而言,我更喜欢有一个小班,而不是让这个"复杂"其他一些课程中的方法与完全无关的责任。