sfcgeorge / yard-contracts

YARD Plugin for Automatic Param Docs from Contracts.
MIT License
26 stars 3 forks source link

Fails for attr_reader contracts #12

Open alex-fedorov opened 9 years ago

alex-fedorov commented 9 years ago
class Viking
  include Contracts

  Contract None => User
  attr_reader :user

  Contract None => Hat
  attr_reader :hat
end

fails with:

[error]: NoMethodError: undefined method `type' for nil:NilClass
[error]: Stack trace:
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-contracts-0.1.5/lib/yard-contracts/formatters.rb:68:in `type'
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-contracts-0.1.5/lib/yard-contracts/formatters.rb:118:in `block in params'
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-contracts-0.1.5/lib/yard-contracts/formatters.rb:109:in `each'
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-contracts-0.1.5/lib/yard-contracts/formatters.rb:109:in `params'
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-contracts-0.1.5/lib/yard-contracts/contract_handler.rb:45:in `process'
    /Users/waterlink/.rvm/gems/ruby-2.1.1/gems/yard-0.8.7.6/lib/yard/handlers/processor.rb:114:in `block (2 levels) in process'

I assume, that happens because it tries to get parameter list and do something with it. But there is no method definition to get parameter list from..

sfcgeorge commented 9 years ago

yard-contracts is fired on the Contract call, it then scans ahead in the code's AST for the next def statement, which of course there isn't here.

I wasn't going to support any fancy metaprogramming stuff with yard-contracts because it's not easy when all YARD gives us is an AST. But attr_* methods are core and so common that we really should support them (I didn't know Contracts worked with attr_* actually).

So, the first approach that springs to mind is look ahead for the next def, the next `attr_*, look ahead for the next whatever other ways methods can be defined, then out of those choose the nearest one and use that. It'll be a lot of edge cases but I'm not sure how else to do it.

It would be a good idea to ask on YARD if there's a better way of doing this or if we really are stuck gleaning stuff from the AST.

Ooh, another way might be to register TWO handlers. One for the Contract call that registers it in an array and one for the next method definition that then links the two. Of course this would only work if YARD fires the method definition handler for attr_* methods too, which I don't know. Or it might have a special handler for attr_* also.

I won't be able to work on this for at least a week, likely longer so feel free to have a go yourself if you want.

waterlink commented 9 years ago

As I thought, I can take a look )