| 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