class Webgen::Utils::TagParser

This class is used to parse a string for webgen tags and replace them with dynamically generated content. See replace_tags for more information.

Public Class Methods

new(prefix = nil) click to toggle source

Create a new TagParser object, optionally providing a tag prefix.

   # File lib/webgen/utils/tag_parser.rb
23 def initialize(prefix = nil)
24   @start_re = /(\\*)\{#{prefix}(\w+)(::?)/
25   @end_re = /(\\*)\{#{prefix}(\w+)\}/
26 end

Public Instance Methods

parse_params(param_string, tag) click to toggle source

Parse the parameter string and return the result.

    # File lib/webgen/utils/tag_parser.rb
114 def parse_params(param_string, tag)
115   YAML::load("--- #{param_string}")
116 rescue ArgumentError, SyntaxError, YAML::SyntaxError => e
117   raise Error.new("Could not parse parameter string '#{param_string}' for tag '#{tag}': #{e.message}")
118 end
replace_tags(content) { |tag_name, params, body| ... } click to toggle source

Return the content with all webgen tags replaced.

When a webgen tag is encountered by the parser, the method yields all found information and substitutes the returned string for the tag.

    # File lib/webgen/utils/tag_parser.rb
 36 def replace_tags(content) #:yields: tag_name, params, body
 37   scanner = StringScanner.new(content)
 38   data = ProcessingStruct.new(:before_tag)
 39   while true
 40     case data.state
 41     when :before_tag
 42       if scanner.skip_until(@start_re)
 43         data.state = :in_start_tag
 44         data.backslashes = scanner[1].length
 45         data.brackets = 1
 46         data.tag = scanner[2]
 47         data.simple_tag = (scanner[3] == ':')
 48         data.params_start_pos = scanner.pos
 49         data.start_pos = scanner.pos - scanner.matched.length
 50       else
 51         data.state = :done
 52       end
 53 
 54     when :in_start_tag
 55       data.brackets += (scanner[1] == '{' ? 1 : -1) while data.brackets != 0 && scanner.skip_until(BRACKETS_RE)
 56       if data.brackets != 0
 57         raise Error.new("Unbalanced curly brackets found for tag '#{data.tag}'")
 58       else
 59         data.params_end_pos = data.body_end_pos = data.end_pos = scanner.pos - 1
 60         data.state = (data.simple_tag ? :process : :in_body)
 61       end
 62 
 63     when :process
 64       begin
 65         enc = scanner.string.encoding
 66         scanner.string.force_encoding('ASCII-8BIT')
 67         if data.backslashes % 2 == 0
 68           params = parse_params(scanner.string[data.params_start_pos...data.params_end_pos].force_encoding(enc),
 69                                 data.tag)
 70           result = yield(data.tag, params,
 71                          scanner.string[(data.params_end_pos+1)...data.body_end_pos].to_s.force_encoding(enc))
 72           result = result.to_s.force_encoding('ASCII-8BIT')
 73           scanner.string[data.start_pos..data.end_pos] = "\\" * (data.backslashes / 2) + result
 74           scanner.pos = data.start_pos + result.length
 75         else
 76           scanner.string[data.start_pos, 1 + data.backslashes / 2] = ''
 77           scanner.pos -= 1 + data.backslashes / 2
 78         end
 79       ensure
 80         scanner.string.force_encoding(enc)
 81       end
 82       data.state = :before_tag
 83 
 84     when :in_body
 85       while (result = scanner.skip_until(@end_re))
 86         next unless scanner[2] == data.tag
 87         if scanner[1].length % 2 == 1
 88           scanner.string[(scanner.pos - scanner.matched.length), 1 + scanner[1].length / 2] = ''
 89           scanner.pos -= 1 + scanner[1].length / 2
 90         else
 91           break
 92         end
 93       end
 94       if result
 95         data.state = :process
 96         data.end_pos = scanner.pos - 1
 97         data.body_end_pos = scanner.pos - scanner.matched.length + scanner[1].length / 2
 98       else
 99         raise Error.new("Invalid body part - no end tag found for '#{data.tag}'")
100       end
101 
102     when :done
103       break
104     end
105   end
106   scanner.string
107 rescue Error => e
108   e.line = scanner.string[0...data.start_pos].scan("\n").size + 1
109   e.column = data.start_pos - (scanner.string.rindex("\n", data.start_pos) || -1)
110   raise
111 end