Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automagically adding yard doc skeletons to existing Rails legacy code [closed]

I would like be able to insert templated YARD doc style comments into my existing Rails legacy application. At present it has few comments. I would like class headers and method headers that have the params specified (by extraction from the method signatures I presume) and placeholders for return values.

In PHP code I had tools that would examine the code and create the doc header comments inserted into the code in the proper spots. In Ruby with Duck typing etc, I am certain that things like the types of the @params etc, cannot be easily guessed at, and I am ok with that - I expect to review the code files one by one manually after insertion. Would just like to avoid having to insert all the skeleton templates into the code (over 500 files) if possible.

I have searched for a gem, etc. that does this and have come across none so far. Are there any out there?

like image 871
TJChambers Avatar asked May 28 '15 15:05

TJChambers


1 Answers

It seems you will have to write it by yourself, but this is not a big problem havig access to the Ruby's S-expressions, which will parse the source for you. So you can do it like this:

require 'ripper'
def parse_sexp( sexp, stack=[] )
  case sexp[0]
  when :module
    name = sexp[1][1][1]
    line_number = sexp[1][1][2][0]

    parse_sexp(sexp[2], stack+[sexp[0], sexp[1][1][1]])

    puts "#{line_number}: Module: #{name}\n"
  when :class
    name = sexp[1][1][1]
    line_number = sexp[1][1][2][0]

    parse_sexp(sexp[3], stack+[sexp[0], sexp[1][1][1]])
    puts "#{line_number}: Class: #{stack.last}::#{name}\n"
  when :def
    name = sexp[1][1]
    line_number = sexp[1][2][0]

    parse_sexp(sexp[3], stack+[sexp[0], sexp[1][1]])

    puts "#{line_number}: Method: #{stack.last}##{name}\n"
  else
    if sexp.kind_of?(Array)
      sexp.each { |s| parse_sexp(s,stack) if s.kind_of?(Array) }
    end
  end

end


sexp = Ripper.sexp(open 'prog.rb')
parse_sexp(sexp)

Prog.rb was:

$ cat -n prog.rb 
 1  module M1
 2    class C1
 3      def m1c1
 4        a="test"
 5        puts "hello"
 6        return a if a.empty?
 7        puts "hello2"
 8        a
 9      end
10    end
11    class C2 < C3
12      def m1c2
13        puts "hello"
14      end
15    end
16    class C3
17    end
18  end

What you'll get is:

#line_number    #entity
3: Method: C1#m1c1
2: Class: M1::C1
12: Method: C2#m1c2
11: Class: M1::C2
16: Class: M1::C3
1: Module: M1

So you only need to customize the template, and extract the parameters which are available in the same array:

#irb > pp Ripper.sexp("def method(param1);nil; end")
...[:def,
   [:@ident, "method", [1, 4]],
   [:paren,
    [:params, [[:@ident, "param1", [1, 11]]]...

Little bit harder task is to find out what is returned, but still doable - look for :returns while you have :def last in the stack and add it to the last statement of the method.

And finally put those comments above apropriate lines to the source file.

like image 103
Eugene Petrov Avatar answered Oct 04 '22 20:10

Eugene Petrov