Class: RDoc::Markup::AttributeManager
| Relationships & Source Files | |
| Inherits: | Object | 
| Defined in: | lib/rdoc/markup/attribute_manager.rb | 
Overview
Manages changes of attributes in a block of text
Constant Summary
- 
    A_PROTECT =
    Internal use only
    
 # File 'lib/rdoc/markup/attribute_manager.rb', line 30004
- 
    NON_PRINTING_END =
    Internal use only
    
 # File 'lib/rdoc/markup/attribute_manager.rb', line 147"\2"
- 
    NON_PRINTING_START =
    Internal use only
    
 # File 'lib/rdoc/markup/attribute_manager.rb', line 146"\1"
- 
    NULL =
    # File 'lib/rdoc/markup/attribute_manager.rb', line 21The NUL character "\000".freeze 
- 
    PROTECT_ATTR =
    Internal use only
    # File 'lib/rdoc/markup/attribute_manager.rb', line 35Special mask character to prevent inline markup handling A_PROTECT.chr 
Class Method Summary
- 
    
      .new  ⇒ AttributeManager 
    
    constructor
    Creates a new attribute manager that understands bold, emphasized and teletype text. 
Instance Attribute Summary
- 
    
      #attributes  
    
    readonly
    The attributes enabled for this markup object. 
- 
    
      #exclusive_bitmap  
    
    readonly
    A bits of exclusive maps. 
- 
    
      #html_tags  
    
    readonly
    This maps HTML tags to the corresponding attribute char. 
- 
    
      #matching_word_pairs  
    
    readonly
    This maps delimiters that occur around words (such as bold or tt) where the start and end delimiters and the same.
- 
    
      #protectable  
    
    readonly
    A \ in front of a character that would normally be processed turns off processing. 
- 
    
      #regexp_handlings  
    
    readonly
    And this maps _regexp handling_ sequences to a name. 
- 
    
      #word_pair_map  
    
    readonly
    And this is used when the delimiters aren’t the same. 
Instance Method Summary
- 
    
      #add_html(tag, name, exclusive = false)  
    
    Adds a markup class with namefor words surrounded by HTML tagtag.
- 
    
      #add_regexp_handling(pattern, name, exclusive = false)  
    
    Adds a regexp handling for patternwithname.
- 
    
      #add_word_pair(start, stop, name, exclusive = false)  
    
    Adds a markup class with namefor words wrapped in thestartandstopcharacter.
- 
    
      #attribute(turn_on, turn_off)  
    
    Return an attribute object with the given turn_on and turn_off bits set. 
- 
    
      #change_attribute(current, new)  
    
    Changes the current attribute from currentto .new
- 
    
      #changed_attribute_by_name(current_set, new_set)  
    
    Used by the tests to change attributes by name from current_settonew_set
- 
    
      #convert_attrs(str, attrs, exclusive = false)  
    
    Map attributes like textto the sequence 001002<char>001003<char>, where <char> is a per-attribute specific character. 
- 
    
      #convert_html(str, attrs, exclusive = false)  
    
    Converts HTML tags to ::RDoc::RDocattributes.
- 
    
      #convert_regexp_handlings(str, attrs, exclusive = false)  
    
    Converts regexp handling sequences to ::RDoc::RDocattributes.
- 
    
      #copy_string(start_pos, end_pos)  
    
    Copies start_postoend_posfrom the current string.
- 
    
      #display_attributes  
    
    Debug method that prints a string along with its attributes. 
- 
    
      #flow(str)  
    
    Processes strconverting attributes, HTML and regexp handlings.
- 
    
      #mask_protected_sequences  
    
    Escapes regexp handling sequences of text to prevent conversion to ::RDoc::RDoc.
- 
    
      #split_into_flow  
    
    Splits the string into chunks by attribute change. 
- 
    
      #unmask_protected_sequences  
    
    Unescapes regexp handling sequences of text. 
- #convert_attrs_matching_word_pairs(str, attrs, exclusive) Internal use only
- #convert_attrs_word_pair_map(str, attrs, exclusive) Internal use only
- #exclusive?(attr) ⇒ Boolean Internal use only
Constructor Details
    .new  ⇒ AttributeManager 
  
Creates a new attribute manager that understands bold, emphasized and teletype text.
# File 'lib/rdoc/markup/attribute_manager.rb', line 80
def initialize @html_tags = {} @matching_word_pairs = {} @protectable = %w[<] @regexp_handlings = [] @word_pair_map = {} @exclusive_bitmap = 0 @attributes = RDoc::Markup::Attributes.new add_word_pair "*", "*", :BOLD, true add_word_pair "_", "_", :EM, true add_word_pair "+", "+", :TT, true add_html "em", :EM, true add_html "i", :EM, true add_html "b", :BOLD, true add_html "tt", :TT, true add_html "code", :TT, true end
Instance Attribute Details
#attributes (readonly)
The attributes enabled for this markup object.
# File 'lib/rdoc/markup/attribute_manager.rb', line 40
attr_reader :attributes
#exclusive_bitmap (readonly)
A bits of exclusive maps
# File 'lib/rdoc/markup/attribute_manager.rb', line 74
attr_reader :exclusive_bitmap
#html_tags (readonly)
This maps HTML tags to the corresponding attribute char
# File 'lib/rdoc/markup/attribute_manager.rb', line 58
attr_reader :
#matching_word_pairs (readonly)
This maps delimiters that occur around words (such as bold or tt) where the start and end delimiters and the same. This lets us optimize the regexp
# File 'lib/rdoc/markup/attribute_manager.rb', line 47
attr_reader :matching_word_pairs
#protectable (readonly)
A \ in front of a character that would normally be processed turns off processing. We do this by turning < into <#PROTECT
# File 'lib/rdoc/markup/attribute_manager.rb', line 64
attr_reader :protectable
#regexp_handlings (readonly)
And this maps _regexp handling_ sequences to a name. A regexp handling sequence is something like a WikiWord
# File 'lib/rdoc/markup/attribute_manager.rb', line 70
attr_reader :regexp_handlings
#word_pair_map (readonly)
And this is used when the delimiters aren’t the same. In this case the hash maps a pattern to the attribute character
# File 'lib/rdoc/markup/attribute_manager.rb', line 53
attr_reader :word_pair_map
Instance Method Details
#add_html(tag, name, exclusive = false)
Adds a markup class with name for words surrounded by HTML tag tag. To process emphasis tags:
am.add_html 'em', :EM# File 'lib/rdoc/markup/attribute_manager.rb', line 286
def add_html(tag, name, exclusive = false) bitmap = @attributes.bitmap_for name @html_tags[tag.downcase] = bitmap @exclusive_bitmap |= bitmap if exclusive end
#add_regexp_handling(pattern, name, exclusive = false)
Adds a regexp handling for pattern with name.  A simple URL handler would be:
@am.add_regexp_handling(/((https?:)\S+\w)/, :HYPERLINK)# File 'lib/rdoc/markup/attribute_manager.rb', line 298
def add_regexp_handling(pattern, name, exclusive = false) bitmap = @attributes.bitmap_for(name) @regexp_handlings << [pattern, bitmap] @exclusive_bitmap |= bitmap if exclusive end
#add_word_pair(start, stop, name, exclusive = false)
Adds a markup class with name for words wrapped in the start and stop character.  To make words wrapped with “*” bold:
am.add_word_pair '*', '*', :BOLD# File 'lib/rdoc/markup/attribute_manager.rb', line 261
def add_word_pair(start, stop, name, exclusive = false) raise ArgumentError, "Word flags may not start with '<'" if start[0, 1] == '<' bitmap = @attributes.bitmap_for name if start == stop then @matching_word_pairs[start] = bitmap else pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/ @word_pair_map[pattern] = bitmap end @protectable << start[0, 1] @protectable.uniq! @exclusive_bitmap |= bitmap if exclusive end
#attribute(turn_on, turn_off)
Return an attribute object with the given turn_on and turn_off bits set
# File 'lib/rdoc/markup/attribute_manager.rb', line 103
def attribute(turn_on, turn_off) RDoc::Markup::AttrChanger.new turn_on, turn_off end
#change_attribute(current, new)
Changes the current attribute from current to .new
#changed_attribute_by_name(current_set, new_set)
Used by the tests to change attributes by name from current_set to new_set
# File 'lib/rdoc/markup/attribute_manager.rb', line 119
def changed_attribute_by_name(current_set, new_set) current = new = 0 current_set.each do |name| current |= @attributes.bitmap_for(name) end new_set.each do |name| new |= @attributes.bitmap_for(name) end change_attribute(current, new) end
#convert_attrs(str, attrs, exclusive = false)
Map attributes like textto the sequence 001002<char>001003<char>, where <char> is a per-attribute specific character
# File 'lib/rdoc/markup/attribute_manager.rb', line 154
def convert_attrs(str, attrs, exclusive = false) convert_attrs_matching_word_pairs(str, attrs, exclusive) convert_attrs_word_pair_map(str, attrs, exclusive) end
#convert_attrs_matching_word_pairs(str, attrs, exclusive)
# File 'lib/rdoc/markup/attribute_manager.rb', line 160
def convert_attrs_matching_word_pairs(str, attrs, exclusive) # first do matching ones = @matching_word_pairs.select { |start, bitmap| exclusive == exclusive?(bitmap) }.keys return if .empty? = "[#{.join("")}](?!#{PROTECT_ATTR})" = "[#{@matching_word_pairs.keys.join("")}](?!#{PROTECT_ATTR})" re = /(?:^|\W|#{})\K(#{})(\1*[#\\]?[\w:#{PROTECT_ATTR}.\/\[\]-]+?\S?)\1(?!\1)(?=#{}|\W|$)/ 1 while str.gsub!(re) { |orig| a, w = (m = $~).values_at(1, 2) attr = @matching_word_pairs[a] if attrs.set_attrs(m.begin(2), w.length, attr) a = NULL * a.length else a = NON_PRINTING_START + a + NON_PRINTING_END end a + w + a } str.delete!(NON_PRINTING_START + NON_PRINTING_END) end
#convert_attrs_word_pair_map(str, attrs, exclusive)
# File 'lib/rdoc/markup/attribute_manager.rb', line 185
def convert_attrs_word_pair_map(str, attrs, exclusive) # then non-matching unless @word_pair_map.empty? then @word_pair_map.each do |regexp, attr| next unless exclusive == exclusive?(attr) 1 while str.gsub!(regexp) { |orig| w = (m = ($~))[2] updated = attrs.set_attrs(m.begin(2), w.length, attr) if updated NULL * m.match_length(1) + w + NULL * m.match_length(3) else orig end } end end end
#convert_html(str, attrs, exclusive = false)
Converts HTML tags to ::RDoc::RDoc attributes
# File 'lib/rdoc/markup/attribute_manager.rb', line 206
def convert_html(str, attrs, exclusive = false) = @html_tags.select { |start, bitmap| exclusive == exclusive?(bitmap) }.keys.join '|' 1 while str.gsub!(/<(#{})>(.*?)<\/\1>/i) { |orig| attr = @html_tags[$1.downcase] html_length = $~.match_length(1) + 2 # "<>".length seq = NULL * html_length attrs.set_attrs($~.begin(2), $~.match_length(2), attr) seq + $2 + seq + NULL } end
#convert_regexp_handlings(str, attrs, exclusive = false)
Converts regexp handling sequences to ::RDoc::RDoc attributes
# File 'lib/rdoc/markup/attribute_manager.rb', line 223
def convert_regexp_handlings(str, attrs, exclusive = false) @regexp_handlings.each do |regexp, attribute| next unless exclusive == exclusive?(attribute) str.scan(regexp) do capture = $~.size == 1 ? 0 : 1 s, e = $~.offset capture attrs.set_attrs s, e - s, attribute | @attributes.regexp_handling end end end
#copy_string(start_pos, end_pos)
Copies start_pos to end_pos from the current string
# File 'lib/rdoc/markup/attribute_manager.rb', line 135
def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end
#display_attributes
Debug method that prints a string along with its attributes
# File 'lib/rdoc/markup/attribute_manager.rb', line 329
def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end
    #exclusive?(attr)  ⇒ Boolean 
  
  # File 'lib/rdoc/markup/attribute_manager.rb', line 142
def exclusive?(attr) (attr & @exclusive_bitmap) != 0 end
#flow(str)
Processes str converting attributes, HTML and regexp handlings
# File 'lib/rdoc/markup/attribute_manager.rb', line 307
def flow(str) @str = str.dup mask_protected_sequences @attrs = RDoc::Markup::AttrSpan.new @str.length, @exclusive_bitmap convert_attrs @str, @attrs, true convert_html @str, @attrs, true convert_regexp_handlings @str, @attrs, true convert_attrs @str, @attrs convert_html @str, @attrs convert_regexp_handlings @str, @attrs unmask_protected_sequences split_into_flow end
#mask_protected_sequences
Escapes regexp handling sequences of text to prevent conversion to ::RDoc::RDoc
# File 'lib/rdoc/markup/attribute_manager.rb', line 239
def mask_protected_sequences # protect __send__, __FILE__, etc. @str.gsub!(/__([a-z]+)__/i, "_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}") @str.gsub!(/(\A|[^\\])\\([#{Regexp.escape @protectable.join}])/m, "\\1\\2#{PROTECT_ATTR}") @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1") end
#split_into_flow
Splits the string into chunks by attribute change
# File 'lib/rdoc/markup/attribute_manager.rb', line 354
def split_into_flow res = [] current_attr = 0 str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].chr == "\0" start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & @attributes.regexp_handling) != 0 then i += 1 while i < str_len and (@attrs[i] & @attributes.regexp_handling) != 0 res << RDoc::Markup::RegexpHandling.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].chr == "\0" end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 res end
#unmask_protected_sequences
Unescapes regexp handling sequences of text
# File 'lib/rdoc/markup/attribute_manager.rb', line 251
def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end