Class: TagTreeScanner::Tag
- Inherits:
-
Object
- Object
- TagTreeScanner::Tag
- Defined in:
- lib/tagtreescanner.rb
Overview
Tags are the equivalent of a DOM Element. The majority of tags are created automatically by a TagFactory, but it may be necessary to create them directly in order to augment or replace information in the tag tree.
A Tag may have one or more attributes, which are pairs of key/value strings; attributes are output in the HTML or XML representation of the Tag.
Each tag also has an info hash, which may be used to keep track of extra bits of information about a tag. Example usages might be keeping track of the depth of a list item, or the associated section for a header. Information from the info hash is not output in the HTML or XML representations.
Instance Attribute Summary collapse
-
#attributes ⇒ Object
A hash of key/value attributes to emit in the XML/HTML representation.
-
#child_tags ⇒ Object
An array of child Tag or TextNode instances.
-
#factory ⇒ Object
The TagFactory that created this tag (may be
nil). -
#info ⇒ Object
A hash that may be used to store extra information about a Tag.
-
#name ⇒ Object
A symbol with the name of this tag.
-
#next_sibling ⇒ Object
readonly
The Tag or TextNode which immediately follows this tag (may be
nilif this is the last tag of its parent). -
#parent_tag ⇒ Object
readonly
The Tag to which this tag is attached (may be
nil). -
#previous_sibling ⇒ Object
readonly
The Tag or TextNode which immediately precedes this tag (may be
nilif this is the first tag of its parent).
Instance Method Summary collapse
-
#<<(additional_text) ⇒ Object
- additional_text
-
The text to add to this node.
-
#allowed_genre ⇒ Object
Returns the
allowed_genreproperty of the owning TagFactory, ornilif this tag wasn’t created by a factory. -
#allows_text? ⇒ Boolean
Returns the
allows_textproperty of the owning TagFactory, ortrueif this tag wasn’t created by a factory. -
#append_child(new_child) ⇒ Object
- new_child
-
The Tag or TextNode to add as the last child.
-
#autoclose? ⇒ Boolean
Returns the
autocloseproperty of the owning TagFactory, ornilif this tag wasn’t created by a factory. -
#close_match ⇒ Object
Returns the
close_matchproperty of the owning TagFactory, ornilif this tag wasn’t created by a factory. -
#close_requires_bol? ⇒ Boolean
Returns the
close_requires_bolproperty of the owning TagFactory, ornilif this tag wasn’t created by a factory. -
#dup ⇒ Object
Returns a copy of this tag and its entire hierarchy.
-
#initialize(name, attributes = {}) ⇒ Tag
constructor
- name
- A symbol with the name of this tag attributes
-
A hash of key/value pairs to store with this tag.
-
#inner_text ⇒ Object
Returns the text contents of this tag and its descendants.
-
#insert_after(new_child, reference_child = nil) ⇒ Object
- new_child
-
The Tag or TextNode to add as a child of this tag.
-
#insert_before(new_child, reference_child = nil) ⇒ Object
- new_child
-
The Tag or TextNode to add as a child of this tag.
-
#inspect ⇒ Object
:nodoc:.
-
#method_missing(name, *args) ⇒ Object
Allows for settings HTML or XML-like attributes directly without knowing about the attributes collection.
-
#remove_child(existing_child) ⇒ Object
- existing_child
-
The Tag or TextNode to remove.
-
#replace_child(old_child, new_child) ⇒ Object
- old_child
-
The existing child Tag or TextNode to replace.
-
#replace_with(new_child) ⇒ Object
- new_child
-
The Tag or TextNode to replace this tag.
-
#tags_by_name(name) ⇒ Object
Returns an array of all descendants of this tag whose #name matches the supplied name.
-
#text=(new_contents) ⇒ Object
(also: #inner_text=)
Set the text content of this element to new_contents.
-
#to_hier(level = 0) ⇒ Object
- level
-
The indentation level (tabs) to start at.
-
#to_html ⇒ Object
Returns an HTML representation of this tag and all its descendants.
-
#to_xml(empty_tags_collapsed = true) ⇒ Object
Returns an XML representation of this tag and all its descendants.
Constructor Details
#initialize(name, attributes = {}) ⇒ Tag
- name
-
A symbol with the name of this tag
- attributes
-
A hash of key/value pairs to store with this tag
194 195 196 197 198 199 |
# File 'lib/tagtreescanner.rb', line 194 def initialize( name, attributes={} ) @name = name = [ ] @attributes = attributes @info = {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
Allows for settings HTML or XML-like attributes directly without knowing about the attributes collection. For example:
tag.href = 'http://www.google.com'
tag.class = 'external'
is the same as:
tag.attributes['href'] = 'http://www.google.com'
tag.attributes['class'] = 'external'
…for any attributes (like the above) that don’t have the same name as an existing method or attribute on the Tag class.
210 211 212 213 214 215 216 |
# File 'lib/tagtreescanner.rb', line 210 def method_missing( name, *args ) if (name=name.to_s) =~ /=$/ @attributes[ name[0...-1] ] = (args.size==1 ? args[0] : args ) else @attributes[ name ] end end |
Instance Attribute Details
#attributes ⇒ Object
A hash of key/value attributes to emit in the XML/HTML representation
173 174 175 |
# File 'lib/tagtreescanner.rb', line 173 def attributes @attributes end |
#child_tags ⇒ Object
An array of child Tag or TextNode instances
169 170 171 |
# File 'lib/tagtreescanner.rb', line 169 def end |
#factory ⇒ Object
The TagFactory that created this tag (may be nil)
176 177 178 |
# File 'lib/tagtreescanner.rb', line 176 def factory @factory end |
#info ⇒ Object
A hash that may be used to store extra information about a Tag
179 180 181 |
# File 'lib/tagtreescanner.rb', line 179 def info @info end |
#name ⇒ Object
A symbol with the name of this tag
166 167 168 |
# File 'lib/tagtreescanner.rb', line 166 def name @name end |
#next_sibling ⇒ Object
The Tag or TextNode which immediately follows this tag (may be nil if this is the last tag of its parent)
186 187 188 |
# File 'lib/tagtreescanner.rb', line 186 def next_sibling @next_sibling end |
#parent_tag ⇒ Object
The Tag to which this tag is attached (may be nil)
182 183 184 |
# File 'lib/tagtreescanner.rb', line 182 def parent_tag @parent_tag end |
#previous_sibling ⇒ Object
The Tag or TextNode which immediately precedes this tag (may be nil if this is the first tag of its parent)
190 191 192 |
# File 'lib/tagtreescanner.rb', line 190 def previous_sibling @previous_sibling end |
Instance Method Details
#<<(additional_text) ⇒ Object
- additional_text
-
The text to add to this node.
Appends additional_text to this tag. If the last item in the child_tags collection is a TextNode, the text is added to that item; otherwise, a new TextNode is created with additional_text and added as the last child of this tag.
382 383 384 385 386 387 388 389 |
# File 'lib/tagtreescanner.rb', line 382 def << ( additional_text ) last_child = .last if last_child.is_a? TextNode last_child << additional_text else append_child( TextNode.new( additional_text ) ) end end |
#allowed_genre ⇒ Object
Returns the allowed_genre property of the owning TagFactory, or nil if this tag wasn’t created by a factory.
244 245 246 |
# File 'lib/tagtreescanner.rb', line 244 def allowed_genre @factory && @factory.allowed_genre end |
#allows_text? ⇒ Boolean
Returns the allows_text property of the owning TagFactory, or true if this tag wasn’t created by a factory.
238 239 240 |
# File 'lib/tagtreescanner.rb', line 238 def allows_text? @factory ? @factory.allows_text : true end |
#append_child(new_child) ⇒ Object
- new_child
-
The Tag or TextNode to add as the last child.
Adds new_child to the end of this tag’s +child_tags_ collection. Returns a reference to new_child.
If new_child is a child of another Tag, it is first removed from that tag.
255 256 257 258 |
# File 'lib/tagtreescanner.rb', line 255 def append_child( new_child ) return if new_child == .last insert_after( new_child, .last ) end |
#autoclose? ⇒ Boolean
Returns the autoclose property of the owning TagFactory, or nil if this tag wasn’t created by a factory.
232 233 234 |
# File 'lib/tagtreescanner.rb', line 232 def autoclose? @factory && @factory.autoclose end |
#close_match ⇒ Object
Returns the close_match property of the owning TagFactory, or nil if this tag wasn’t created by a factory.
220 221 222 |
# File 'lib/tagtreescanner.rb', line 220 def close_match @factory && @factory.close_match end |
#close_requires_bol? ⇒ Boolean
Returns the close_requires_bol property of the owning TagFactory, or nil if this tag wasn’t created by a factory.
226 227 228 |
# File 'lib/tagtreescanner.rb', line 226 def close_requires_bol? @factory && @factory.close_requires_bol end |
#dup ⇒ Object
Returns a copy of this tag and its entire hierarchy. All descendant tags/text nodes are also cloned.
The info hash is not preserved.
498 499 500 501 502 |
# File 'lib/tagtreescanner.rb', line 498 def dup tag = self.class.new( self.name, self.attributes.dup ) .each{ |tag2| tag.append_child( tag2.dup ) } tag end |
#inner_text ⇒ Object
Returns the text contents of this tag and its descendants.
450 451 452 453 454 |
# File 'lib/tagtreescanner.rb', line 450 def inner_text .inject(''){ |out,tag| out << ( tag.is_a?( TextNode ) ? tag.text : tag.inner_text ) } end |
#insert_after(new_child, reference_child = nil) ⇒ Object
- new_child
-
The Tag or TextNode to add as a child of this tag.
- reference_child
-
The child to place new_child after.
Adds new_child as a child of this tag, immediately after the location of reference_child. Returns a reference to new_child.
If reference_child is nil, the child is added as the first child of this tag. A RuntimeError is raised if reference_child is not a child of this tag.
If new_child is a child of another Tag, #remove_child is automatically invoked to remove it from that tag.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/tagtreescanner.rb', line 289 def insert_after( new_child, reference_child=nil ) #puts "#{self.inspect}#insert_after( #{new_child.inspect}, #{reference_child.inspect} )" return new_child if reference_child ? ( reference_child.next_sibling == new_child ) : ( new_child == .first ) #Ensure new_child is not not an ancestor of self walker = self while walker raise "#{new_child.inspect} cannot be added under #{self.inspect}, because it is an ancestor of it!" if walker==new_child walker = walker.parent_tag end new_child.parent_tag.remove_child( new_child ) if new_child.parent_tag if reference_child new_idx = .index( reference_child ) raise "#{reference_child.inspect} is not a child of #{self.inspect}" unless new_idx new_idx += 1 else new_idx = 0 end new_child.parent_tag = self succ = [ new_idx ] .insert( new_idx, new_child ) new_child.previous_sibling = reference_child reference_child.next_sibling = new_child if reference_child new_child.next_sibling = succ succ.previous_sibling = new_child if succ new_child end |
#insert_before(new_child, reference_child = nil) ⇒ Object
- new_child
-
The Tag or TextNode to add as a child of this tag.
- reference_child
-
The child to place new_child before.
Adds new_child as a child of this tag, immediately before the location of reference_child. Returns a reference to new_child.
If reference_child is nil, the child is added as the last child of this tag. A RuntimeError is raised if reference_child is not a child of this tag.
If new_child is a child of another Tag, #remove_child is automatically invoked to remove it from that tag.
272 273 274 275 |
# File 'lib/tagtreescanner.rb', line 272 def insert_before( new_child, reference_child=nil ) return new_child if reference_child ? ( reference_child.previous_sibling == new_child ) : ( new_child == .last ) insert_after( new_child, reference_child ? reference_child.previous_sibling : .last ) end |
#inspect ⇒ Object
:nodoc:
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/tagtreescanner.rb', line 456 def inspect #:nodoc: out = "<#{@name}" #out << " @pops=#{@parent_tag ? @parent_tag.name.inspect : 'nil'}" #out << " @prev=#{@previous_sibling ? @previous_sibling.name.inspect : 'nil'}" #out << " @next=#{@next_sibling ? @next_sibling.name.inspect : 'nil'}" @attributes.each{ |k,v| out << " #{k}=\"#{v}\"" } @info.each{ |k,v| out << " @#{k}=>#{v.inspect}" } children = .length if children == 1 && TextNode === .first out << ">#{@child_tags.first}</#{@name}" elsif children == 0 out << '>' else out << " (#{@child_tags.length} child#{@child_tags.length != 1 ? 'ren' : ''})>" end end |
#remove_child(existing_child) ⇒ Object
- existing_child
-
The Tag or TextNode to remove.
Removes existing_child from being a child of this tag. Returns existing_child.
A RuntimeError is raised if existing_child is not a child of this tag.
If new_child is a child of another Tag, #remove_child is automatically invoked to remove it from that tag.
328 329 330 331 332 333 334 335 336 337 |
# File 'lib/tagtreescanner.rb', line 328 def remove_child( existing_child ) idx = .index( existing_child ) raise "#{existing_child.inspect} is not a child of #{self.inspect}" unless idx prev, succ = existing_child.previous_sibling, existing_child.next_sibling prev.next_sibling = succ if prev succ.previous_sibling = prev if succ .delete_at( idx ) existing_child.previous_sibling = existing_child.next_sibling = existing_child.parent_tag = nil existing_child end |
#replace_child(old_child, new_child) ⇒ Object
- old_child
-
The existing child Tag or TextNode to replace.
- new_child
-
The Tag or TextNode to replace old_child.
Replaces old_child with new_child in this collection. Returns old_child.
A RuntimeError is raised if existing_child is not a child of this tag.
If new_child is a child of another Tag, #remove_child is automatically invoked to remove it from that tag.
350 351 352 353 354 355 356 357 358 359 |
# File 'lib/tagtreescanner.rb', line 350 def replace_child( old_child, new_child ) if ( prev = old_child.previous_sibling ) == new_child || old_child.next_sibling == new_child remove_child( old_child ) else new_child.parent_tag.remove_child( new_child ) if new_child.parent_tag remove_child( old_child ) insert_after( new_child, prev ) end old_child end |
#replace_with(new_child) ⇒ Object
- new_child
-
The Tag or TextNode to replace this tag.
Replaces this tag with new_child. Returns new_child.
A RuntimeError is raised if this tag is not a child of another tag.
If new_child is a child of another Tag, #remove_child is automatically invoked to remove it from that tag.
369 370 371 372 373 374 |
# File 'lib/tagtreescanner.rb', line 369 def replace_with( new_child ) return new_child if new_child == self raise "#{self.inspect} is not a child of another tag" unless @parent_tag @parent_tag.replace_child( self, new_child ) new_child end |
#tags_by_name(name) ⇒ Object
Returns an array of all descendants of this tag whose #name matches the supplied name.
438 439 440 441 442 443 444 445 446 447 |
# File 'lib/tagtreescanner.rb', line 438 def ( name ) out = [] .each{ |tag| out << tag if tag.name == name unless tag..empty? out.concat( tag.( name ) ) end } out end |
#text=(new_contents) ⇒ Object Also known as: inner_text=
Set the text content of this element to new_contents. Removes any child tags (and their text).
393 394 395 396 |
# File 'lib/tagtreescanner.rb', line 393 def text=( new_contents ) .clear append_child( TextNode.new( new_contents ) ) end |
#to_hier(level = 0) ⇒ Object
- level
-
The indentation level (tabs) to start at.
Returns a full-hierarchical representation of this tag and its descendants. (Used for debugging.)
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
# File 'lib/tagtreescanner.rb', line 477 def to_hier( level=0 ) #:nodoc: tabs = "\t" * level out = "#{tabs}<#{@name}" @attributes.each{ |k,v| out << " #{k}=\"#{v}\"" } @info.each{ |k,v| out << " @#{k}=>#{v.inspect}" } if .empty? out << " />\n" elsif .length == 1 && TextNode === .first out << ">#{@child_tags.first}</#{@name}>\n" else out << ">\n" .each{ |n| out << n.to_hier(level+1) } out << "#{tabs}</#{@name}>\n" end out end |
#to_html ⇒ Object
Returns an HTML representation of this tag and all its descendants.
This method is the same as #to_xml except that tags without any child_tags use an explicit close tag, e.g. <div></div> instead of XML’s <div />
405 406 407 |
# File 'lib/tagtreescanner.rb', line 405 def to_html to_xml( false ) end |
#to_xml(empty_tags_collapsed = true) ⇒ Object
Returns an XML representation of this tag and all its descendants.
If empty_tags_collapsed is true (the default) then this method is the same as #to_html except that tags without any child_tags use a single closed tag, e.g. <div /> instead of HTML’s <div></div>
If empty_tags_collapsed is false, this is the same as #to_html.
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/tagtreescanner.rb', line 417 def to_xml( =true ) out = "<#{@name}" @attributes.each{ |k,v| out << " #{k}=\"#{v.to_s.gsub( '""', '"' )}\"" } if && .empty? out << ' />' else out << '>' unless .empty? out << "\n" unless self.allows_text? .each{ |tag| out << tag.to_xml( ) } end out << "</#{@name}>" end out << "\n" if @parent_tag && !@parent_tag.allows_text? out end |