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 new_xml += xml.xpath('//dia:diagramdata').to_s new_xml += ' ' 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 += " \n" 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