2

After returning to Ruby from a long stint coding in another language, I regularly assume that foo.sort, foo.map {...}, foo.sub /bar/, 'zip' will change foo. Of course I meant foo.sort!, etc. But that usually takes 3 or 4 debugging potshots before I notice. Meanwhile, the sort is calculated, but then isn't assigned to anything. Can I make ruby warn about that missing lvalue, like a C compiler warns of a function's ignored return value?

Camille Goudeseune
  • 2,934
  • 2
  • 35
  • 56

2 Answers2

2

You mean like Perl's somewhat infamous "using map in void context"? I don't know of Ruby having such a thing. Sounds like you need more unit testing to catch mistakes like this before they can worm into your code deeply enough to be considered bugs.

Keep in mind Ruby's a lot more flexible than languages like Perl. For example, the following code might be useful:

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

Now technically that's a map in a void context, but because it's used as a return value it might be captured elsewhere. It's the responsibility of the caller to make use of it. Flagging the method itself for some sort of warning is a level removed from what most linting type tools can do.

tadman
  • 208,517
  • 23
  • 234
  • 262
1

Here's a very basic parser :

@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) }

It checks every ruby script in the current directory for sort, map or sub without ! that aren't preceded by =, puts, print or return.

It's just a start, but maybe it could help you find some of the low hanging fruits. There are many false positives, though.

A more complex version could use abstract syntax trees, for example with Ripper.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • Mittag's "halting problem" comment, and tadman's concrete example, indeed suggest that low-hanging fruit is the best one can hope for. A few false positives from such a test are tolerable. – Camille Goudeseune Dec 05 '16 at 18:26