class TaskGroup attr_reader :file, :path, :tasks def initialize(file, path) @file = file @path = path @tasks = [] end def add_task(text) @tasks.push text end end class TodoSummaryBuilder def initialize @groups = [] @warnings = [] @scanner = DirectoryScanner.new @scanner.on_file { |file, path| next if /\.svn-base$/.match(file) next unless FileTest.readable? path fi = File.open(path, 'r') begin group = nil fi.readlines.each { |line| parts = /\/\/\s*TODO\s*(\S.*)/.match(line) unless parts.nil? if group.nil? group = TaskGroup.new(file,path) @groups.push group end group.add_task parts[1] end } rescue @warnings.push "Warning: error reading file #{path}" ensure fi.close end } end def scan_subtree(parentDir) @scanner.scan_subtree(parentDir) end def save_report(path) out = File.new(path, File::CREAT|File::TRUNC|File::RDWR) begin out.puts < TODOs "); @warnings.each { |text| out.puts("

#{text}

") } out.puts("") ensure out.close end end end
Usage: builder = TodoSummaryBuilder.new builder.scan_subtree('c:\project1') builder.scan_subtree('c:\project2') builder.scan_subtree('c:\project3') builder.save_report('c:\result.html')