检测丢失的 sub!、sort!、map! 等

Detecting a missing sub!, sort!, map!, etc

在长期使用另一种语言编码 return 到 Ruby 之后,我经常假设 foo.sortfoo.map {...}foo.sub /bar/, 'zip'改变 foo。当然,我的意思是 foo.sort!,等等。但在我注意到之前通常需要 3 或 4 次调试。同时,计算了排序,但没有分配给任何东西。我可以让 ruby 警告丢失的左值,就像 C 编译器警告函数被忽略的 return 值一样吗?

你是说 Perl 有点臭名昭著 "using map in void context"?我不知道 Ruby 有这样的事情。听起来你需要更多的单元测试来发现这样的错误,然后它们才能深入到你的代码中,以至于被认为是错误。

请记住 Ruby 比 Perl 等语言灵活得多。例如,以下代码 可能 有用:

def rewrite(list)
  list.map do |row|
    row += '!'
  end
end

从技术上讲,这是空上下文中的 map,但因为它用作 return 值,所以 可能 在其他地方捕获。调用者有责任使用它。将方法本身标记为某种警告是大多数 linting 类型工具可以执行的级别。

这是一个非常的基本解析器:

@forgetful_methods = %w(sort map sub)

Dir['*.rb'].each do |script|
  File.readlines(script).each.with_index(1) do |line, i|
    @forgetful_methods.each do |method|
      if line =~ /\.#{method}(?!!)/ && $` !~ /(=|\b(puts|print|return)\b|^#)/
        puts format('%-25s (%3d) : %s', script, i, line.strip)
      end
    end
  end
end

# =>
# brace_globbing.rb         ( 13) : subpatterns.map{|subpattern| explode_extglob(match.pre_match+subpattern+match.post_match)}.flatten
# delegate.rb               ( 11) : @targets.map { |t| t.send(m, *args) }

它检查当前目录中的每个 ruby 脚本是否有 sortmapsub 没有 ! 且前面没有 =putsprintreturn.

这只是一个开始,但也许它可以帮助您找到一些唾手可得的成果。 但是,有很多误报。

更复杂的版本可以使用抽象语法树,例如 Ripper