require 'rubygems'
require 'fileutils'
require 'nokogiri'
DIRECTORY_HEADER_LEVEL = 3
def asciidoc_header size, name
'=' * size + " #{name}\n\n"
end
class DocumentedClass
attr_accessor :name, :children, :description
def initialize name, description, header_level = DIRECTORY_HEADER_LEVEL + 1
@name = name
@description = description
@children = {}
@hl = header_level
end
def add_child identifier, description
@children[identifier] = description unless identifier == ""
end
def to_s
@name.to_sym
end
def to_asciidoc with_headers = true
doc = ""
doc += asciidoc_header(@hl, @name) + @description + "\n\n" if with_headers
const = @children.delete(:Constructor)
doc += asciidoc_header(@hl + 1, :Constructor) + const + "\n\n" if const
const = @children.delete(:Destructor)
doc += asciidoc_header(@hl + 1, :Destructor) + const + "\n\n" if const
@children.each { |name, desc| doc += asciidoc_header(@hl + 1, name) + desc + "\n\n" }
return doc
end
end
class CommentDocParser
attr_accessor :trunk_dir, :comments, :classes
def initialize section, section_name, trunk_dir = '.'
@trunk_dir = trunk_dir
@section = section
@section_name = section_name
@classes = []
`mkdir -p dia/#{@section}`
`mkdir -p images/#{@section}`
end
def cleaned_comment comment
comment.gsub!(/\/\*+/, '')
comment.gsub!(/^[ \t]*\*/, '')
comment.gsub!(/\n/, '')
comment.gsub!(/@param\s+(\w+)/, 'The parameter `\1` is')
comment.gsub!(/@return/, 'This function returns')
comment.strip!
end
def cleaned_identifier identifier
return :Destructor if identifier.strip =~ /^~/
return :Constructor if identifier.strip =~ /^\w+\(/
result = identifier
result.gsub!(/^(.*?)\s*\*? (\w+)(.*)/, '\2')
result.strip!
return identifier if result == ""
return result.to_sym
end
def to_asciidoc
doc = ""
doc += asciidoc_header(DIRECTORY_HEADER_LEVEL, @section_name)
@classes.each do |klass|
if @got_image_for[klass.name]
# We need to knock other objects out of the dia diagram
xml = Nokogiri::XML(open("dia/#{@section}/#{klass.name}.dia"))
unless xml.xpath('//dia:object').count == 1
new_xml = <<-XML
<?xml version="1.0"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
XML
new_xml += xml.xpath('//dia:diagramdata').to_s
new_xml += ' <dia:layer name="Background" visible="true">'
new_xml += "\n "
right_index = xml.xpath('//dia:object/dia:attribute[@name="name"]/dia:string').inner_text.split('#').delete_if { |a| a == "" }.index(klass.name.to_s)
if right_index
puts "Completely rewriting dia file for #{klass.name} to only include Dia object at index #{right_index}"
new_xml += xml.xpath('//dia:object')[right_index].to_s
new_xml += " </dia:layer>\n</dia:diagram>"
f = File.new("dia/#{@section}/#{klass.name}.dia", "w")
f.write new_xml
f.close
else
doc += klass.to_asciidoc
next
end
end
`dia -t png -e images/#{@section}/#{klass.name}.png dia/#{@section}/#{klass.name}.dia`
doc += asciidoc_header(DIRECTORY_HEADER_LEVEL + 1, klass.name)
doc += "image::images/#{@section}/#{klass.name}.png[scaledwidth=\"75%\"]\n\n"
doc += klass.description + "\n\n"
doc += klass.to_asciidoc false
else
doc += klass.to_asciidoc
end
end
return doc
end
def parse
@comments = {}
@got_image_for = {}
files = Dir["#{@trunk_dir}/clementine/#{@section}/**/*.cxx"] | Dir["#{@trunk_dir}/clementine/#{@section}/**/*.h"]
beginning_comment = /^[ \t]*\/\*/
ending_comment = /^[ \t]*\*\//
files.each do |file|
found_comment_block = false
found_identifier = false
comment_block = ""
handle = File.new(file)
begin
while line = handle.readline
if line =~ beginning_comment
found_comment_block = true
end
if line =~ ending_comment
found_comment_block = false
found_identifier = true
end
if found_comment_block
comment_block += line if found_comment_block
end
if found_identifier
@comments[file] ||= {}
identifier = handle.readline.strip
if identifier =~ /^[ \t]*(class|struct)/
identifier = identifier.gsub(/^[ \t]*(class|struct)[ ]+/, '').to_sym
@classes << DocumentedClass.new(identifier, cleaned_comment(comment_block))
`autodia.pl -l c++ -i #{file} -o dia/#{@section}/#{identifier.to_s}.dia`
@got_image_for[identifier] = ($? == 0) ? true : false
end
if @classes.last
if identifier != @classes.last.name
@classes.last.add_child(cleaned_identifier(identifier), cleaned_comment(comment_block))
end
else
if cleaned_identifier(identifier) != ""
@comments[file][cleaned_identifier(identifier)] = cleaned_comment(comment_block)
end
end
comment_block = ""
found_identifier = false
end
end
rescue EOFError
next
end
end
end
end