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?
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 :return
s 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With