1## 2# A Document containing lists, headings, paragraphs, etc. 3 4class RDoc::Markup::Document 5 6 include Enumerable 7 8 ## 9 # The file this document was created from. See also 10 # RDoc::ClassModule#add_comment 11 12 attr_reader :file 13 14 ## 15 # If a heading is below the given level it will be omitted from the 16 # table_of_contents 17 18 attr_accessor :omit_headings_below 19 20 ## 21 # The parts of the Document 22 23 attr_reader :parts 24 25 ## 26 # Creates a new Document with +parts+ 27 28 def initialize *parts 29 @parts = [] 30 @parts.concat parts 31 32 @file = nil 33 @omit_headings_from_table_of_contents_below = nil 34 end 35 36 ## 37 # Appends +part+ to the document 38 39 def << part 40 case part 41 when RDoc::Markup::Document then 42 unless part.empty? then 43 parts.concat part.parts 44 parts << RDoc::Markup::BlankLine.new 45 end 46 when String then 47 raise ArgumentError, 48 "expected RDoc::Markup::Document and friends, got String" unless 49 part.empty? 50 else 51 parts << part 52 end 53 end 54 55 def == other # :nodoc: 56 self.class == other.class and 57 @file == other.file and 58 @parts == other.parts 59 end 60 61 ## 62 # Runs this document and all its #items through +visitor+ 63 64 def accept visitor 65 visitor.start_accepting 66 67 visitor.accept_document self 68 69 visitor.end_accepting 70 end 71 72 ## 73 # Concatenates the given +parts+ onto the document 74 75 def concat parts 76 self.parts.concat parts 77 end 78 79 ## 80 # Enumerator for the parts of this document 81 82 def each &block 83 @parts.each(&block) 84 end 85 86 ## 87 # Does this document have no parts? 88 89 def empty? 90 @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?) 91 end 92 93 ## 94 # The file this Document was created from. 95 96 def file= location 97 @file = case location 98 when RDoc::TopLevel then 99 location.relative_name 100 else 101 location 102 end 103 end 104 105 ## 106 # When this is a collection of documents (#file is not set and this document 107 # contains only other documents as its direct children) #merge replaces 108 # documents in this class with documents from +other+ when the file matches 109 # and adds documents from +other+ when the files do not. 110 # 111 # The information in +other+ is preferred over the receiver 112 113 def merge other 114 if empty? then 115 @parts = other.parts 116 return self 117 end 118 119 other.parts.each do |other_part| 120 self.parts.delete_if do |self_part| 121 self_part.file and self_part.file == other_part.file 122 end 123 124 self.parts << other_part 125 end 126 127 self 128 end 129 130 ## 131 # Does this Document contain other Documents? 132 133 def merged? 134 RDoc::Markup::Document === @parts.first 135 end 136 137 def pretty_print q # :nodoc: 138 start = @file ? "[doc (#{@file}): " : '[doc: ' 139 140 q.group 2, start, ']' do 141 q.seplist @parts do |part| 142 q.pp part 143 end 144 end 145 end 146 147 ## 148 # Appends +parts+ to the document 149 150 def push *parts 151 self.parts.concat parts 152 end 153 154 ## 155 # Returns an Array of headings in the document. 156 # 157 # Require 'rdoc/markup/formatter' before calling this method. 158 159 def table_of_contents 160 accept RDoc::Markup::ToTableOfContents.to_toc 161 end 162 163end 164 165