Class | Webgen::ContentProcessor::Tags |
In: |
lib/webgen/contentprocessor/tags.rb
|
Parent: | Object |
Processes special webgen tags to provide dynamic content.
webgen tags are an easy way to add dynamically generated content to websites, for example menus or breadcrumb trails.
BRACKETS_RE | = | /([{}])/ | ||
ProcessingStruct | = | Struct.new(:state, :tag, :simple_tag, :backslashes, :brackets, :start_pos, :end_pos, :params_start_pos, :params_end_pos, :body_end_pos) |
Replace all webgen tags in the content of context with the rendered content.
# File lib/webgen/contentprocessor/tags.rb, line 24 24: def call(context) 25: replace_tags(context) do |tag, param_string, body| 26: log(:debug) { "Replacing tag #{tag} with data '#{param_string}' and body '#{body}' in <#{context.ref_node}>" } 27: process_tag(tag, param_string, body, context) 28: end 29: context 30: end
Process the tag and return the result. The parameter params needs to be a Hash holding all needed and optional parameters for the tag or a parameter String in YAML format and body is the optional body for the tag. context needs to be a valid Webgen::Context object.
# File lib/webgen/contentprocessor/tags.rb, line 35 35: def process_tag(tag, params, body, context) 36: result = '' 37: processor = processor_for_tag(tag) 38: if !processor.nil? 39: params = if params.kind_of?(String) 40: processor.create_tag_params(params, context.ref_node) 41: else 42: processor.create_params_hash(params, context.ref_node) 43: end 44: 45: processor.set_params(params) 46: result, process_output = processor.call(tag, body, context) 47: processor.set_params(nil) 48: result = call(context.clone(:content => result)).content if process_output 49: else 50: raise Webgen::RenderError.new("No tag processor for '#{tag}' found", self.class.name, 51: context.dest_node, context.ref_node) 52: end 53: result 54: end
Return the tag processor for tag or nil if tag is unknown.
# File lib/webgen/contentprocessor/tags.rb, line 156 156: def processor_for_tag(tag) 157: map = website.config['contentprocessor.tags.map'] 158: klass = if map.has_key?(tag) 159: map[tag] 160: elsif map.has_key?(:default) 161: map[:default] 162: else 163: nil 164: end 165: klass.nil? ? nil : website.cache.instance(klass) 166: end
Return the context.content provided by context.ref_node 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/contentprocessor/tags.rb, line 68 68: def replace_tags(context) #:yields: tag_name, param_string, body 69: scanner = StringScanner.new(context.content) 70: data = ProcessingStruct.new(:before_tag) 71: while true 72: case data.state 73: when :before_tag 74: if scanner.skip_until(@start_re) 75: data.state = :in_start_tag 76: data.backslashes = scanner[1].length 77: data.brackets = 1 78: data.tag = scanner[2] 79: data.simple_tag = (scanner[3] == ':') 80: data.params_start_pos = scanner.pos 81: data.start_pos = scanner.pos - scanner.matched.length 82: else 83: data.state = :done 84: end 85: 86: when :in_start_tag 87: data.brackets += (scanner[1] == '{' ? 1 : -1) while data.brackets != 0 && scanner.skip_until(BRACKETS_RE) 88: if data.brackets != 0 89: raise Webgen::RenderError.new("Unbalanced curly brackets for tag '#{data.tag}'", self.class.name, 90: context.dest_node, context.ref_node) 91: else 92: data.params_end_pos = data.body_end_pos = data.end_pos = scanner.pos - 1 93: data.state = (data.simple_tag ? :process : :in_body) 94: end 95: 96: when :process 97: if RUBY_VERSION >= '1.9' 98: begin 99: enc = scanner.string.encoding 100: scanner.string.force_encoding('ASCII-8BIT') 101: if data.backslashes % 2 == 0 102: result = yield(data.tag, scanner.string[data.params_start_pos...data.params_end_pos].force_encoding(enc), 103: scanner.string[(data.params_end_pos+1)...data.body_end_pos].to_s.force_encoding(enc)).to_s 104: scanner.string[data.start_pos..data.end_pos] = "\\" * (data.backslashes / 2) + result.force_encoding('ASCII-8BIT') 105: scanner.pos = data.start_pos + result.length 106: else 107: scanner.string[data.start_pos, 1 + data.backslashes / 2] = '' 108: scanner.pos -= 1 + data.backslashes / 2 109: end 110: ensure 111: scanner.string.force_encoding(enc) if RUBY_VERSION >= '1.9' 112: end 113: else 114: if data.backslashes % 2 == 0 115: result = yield(data.tag, scanner.string[data.params_start_pos...data.params_end_pos], 116: scanner.string[(data.params_end_pos+1)...data.body_end_pos]).to_s 117: scanner.string[data.start_pos..data.end_pos] = "\\" * (data.backslashes / 2) + result 118: scanner.pos = data.start_pos + result.length 119: else 120: scanner.string[data.start_pos, 1 + data.backslashes / 2] = '' 121: scanner.pos -= 1 + data.backslashes / 2 122: end 123: end 124: data.state = :before_tag 125: 126: when :in_body 127: while (result = scanner.skip_until(@end_re)) 128: next unless scanner[2] == data.tag 129: if scanner[1].length % 2 == 1 130: scanner.string[(scanner.pos - scanner.matched.length), 1 + scanner[1].length / 2] = '' 131: scanner.pos -= 1 + scanner[1].length / 2 132: else 133: break 134: end 135: end 136: if result 137: data.state = :process 138: data.end_pos = scanner.pos - 1 139: data.body_end_pos = scanner.pos - scanner.matched.length + scanner[1].length / 2 140: else 141: raise Webgen::RenderError.new("Invalid body part - no end tag found for '#{data.tag}'", self.class.name, 142: context.dest_node, context.ref_node) 143: end 144: 145: when :done 146: break 147: end 148: end 149: scanner.string 150: rescue Webgen::RenderError => e 151: e.line = scanner.string[0...scanner.pos].scan("\n").size + 1 unless e.line 152: raise 153: end