tags:

views:

556

answers:

6

Most of the code I write is in Ruby, and every once in a while, I make some typo ( which only gets caught after a while ). This can suck when you have your scripts do some long running tasks, and you return to them only to find out you had a typo.

Is there an actively developed lint tool for Ruby that could help me overcome this? Would it be possible to use it across a system that works with a lot of source files ( some of them loaded dynamically )?

EDIT: Take this snippet as an example:

a = 20
b = 30
puts c

EDIT: to win bounty, show me a tool that will detect the c variable as not created/undefined. I'd like something that will alert me that c doesn't exist.

+7  A: 

Yes. Test::Unit

Ok, I know you already know this and that in some sense this is a non-helpful answer, but you do bring up the negative consequence of duck typing, that there kind of is (at this time) no way around just writing more tests than something like Java might need.

So, for the record, see Test::Unit in the Ruby Standard Library or one of the other test frameworks.

Having unit tests that you can run and rerun is the best way to catch errors, and you do need more of them (tests, not errors :-) in dynamic languages like Ruby...

DigitalRoss
I know tests are a good thing :). I'd just like to have something readily available to just run, and tell me if I have typos, or unusually poor code. Something like `pylint` http://www.logilab.org/857 .
Geo
I guess I agree that it would be useful. The only thing is, often people deliberately pass different types to a method. Imagine `f x=nil;...;end; f(1);`.
DigitalRoss
I don't see a reason that you need more of them in dynamic languages. Compilers only solve one of an infinite number of possible errors that could happen.
James Deville
Imagine the life cycle of a complex software system. Eventually, something major will get refactored. With Java, this can be done with confidence. At the end of the process everyone is expecting the types they will actually be getting. In Ruby, there could be any number of unexpected types just waiting to be passed dynamically, even without any refactoring at all. That's the conventional wisdom and the usual argument in favor of static typing.
DigitalRoss
+2  A: 
  • ruby -c myfile.rb will check for correct Ruby syntax.
  • Reek checks Ruby code for common code smells.
  • Roodi checks Ruby code for common object-oriented design issues.
  • Flog can warn you about unusually complex code.

[Plug] If your project is in a public Github repository, Caliper can run the latter three tools and others on your code every time you commit. (Disclaimer: I work on Caliper)

Avdi
Can either of them detect typos in variable names?
Geo
I ran Reek,Roodi and Flog on the snippet I provided, and neither of them said anything was wrong with the `c` variable.
Geo
Welcome to the world of dynamic languages. You gain a tremendous amount of flexibility, but you lose the ability to make static assertions about the code like "all the symbols I've referenced are valid at runtime". It's a tradeoff.That said, I think some of the recent IDEs attempt to identify mistakes like this. You might look into RubyMine or Netbeans. Personally, I agree with a previous commenter that your best bet is unit tests. If you want to be notified of mistakes quickly, use something like Autotest to run your tests constantly.
Avdi
To explain further, `c` at that point might refer to a local variable; a variable defined in an enclosing lexical scope; an instance method; a singleton method; a method defined in a superclass or module... etc. There is no way for a tool to know for a certainty that `c` is invalid and therefor a typo without actually running the code - and that brings us back to unit tests.
Avdi
In fact, 'c' in your initial example will be parsed as a call to a method. And in general Ruby (and any other Ruby tool) can't do enough static analysis when it reads the code to figure out that the method c() isn't defined in scope.
kevinrutherford
I wouldn't mind if the code gets evaled, in order to figure out that the variable is undefined.
Geo
In order to eval the code, you need something to call it. That's called a test.
Avdi
+3  A: 
avdi@lazarus:~$ irb
>> a = 20
=> 20
>> b = 30
=> 30
>> puts c
NameError: undefined local variable or method `c' for main:Object
        from (irb):3
>>

There ya go, the tool is called "IRB". Do I get the bounty?

I'm only half joking. I wrote this second answer to hopefully drive home the point that in Ruby, if you want to know that something is defined or not, you have to run the code.

Avdi
Let's wait a while, before you get the bounty :)
Geo
Um, it's not just irb, it's Ruby. Ruby will issue a warning when you attempt to access an unassigned variable.
meagar
+2  A: 

Hi there,

RubyMine (http://www.jetbrains.com/ruby) does the trick:

alt text

None of the below will do all the analysis that RubyMine does.

  • NetBeans Ruby pack
  • Aptana RadRails
  • gVIM (with syntastic plugin by scrooloose)

Each of these has the capacity to identify syntax errors such as wrong number of parentheses, too many defs, ends, braces, etc. But none will identify invalid method calls the way RubyMine does.

Here's why: it's difficult.

Since Ruby is extremely dynamic (and methods like 'c' could easily be generated on the fly), any editor that tries to identify non-existent variables/methods would need to have a large part of the entire evironment loaded and multiple program flow paths constantly tested in order to get accurate 'validity' results. This is much more difficult than in Java where almost all programming is static (at least it was when I dropped that hat).

This ability to easily generate methods on the fly is one of the reasons the community holds testing to such high esteem. I really do reccomend you try testing as well.

btelles
agreed. Even in this case, the code might be valid if you call ruby -rfoo a.rb, where foo defines a top level c method!
James Deville
I agree with your response, but RubyMine is an entire IDE. I only need one piece of it's functionality.
Geo
Cool cool...If you're really motivated, you could download the Ruby plugin for IntelliJ (which I understand is open source) and extract the part that does that processing. But it might be easier to just create your own parser using ParseTree :-)
btelles
+3  A: 

You could give Diamondback Ruby a try. It does a static typecheck of Ruby code, and will thus blame you for using an undefined variable.

While DRuby is an ongoing research project, it already works quite well for small, self-contained Ruby scripts. Currently, it is unable to analyze much of the Ruby standard library “out-of-the-box”. Currently they are working toward typing Ruby on Rails (see their most recent papers).

Adrian
Thanks Adrian! Exactly what I needed.
Geo
Glad that I was of help.
Adrian
Kudos! Excellent! Wow!
nes1983
+1  A: 

nitpick might be what you're lookng for.

With this code:

class MyString < String
  def awesome
    self.gsub("e", "3").gsub("l", "1").uppercase
  end
end

puts MyString.new("leet").awesome

... it outputs:

$ nitpick misspelling.rb 
*** Nitpick had trouble loading "misspelling.rb":
    NoMethodError undefined method `uppercase' for "133t":MyString
Nothing to report boss! He's clean!
phiggy