Class: Sequence::SequenceTemplate::Engine
- Defined in:
- lib/lucid/sequence/sequence_template.rb
Constant Summary collapse
- InvalidInternalElements =
Invalid internal elements refers to spaces, any punctuation sign or delimiter that is forbidden between chevrons <…> template tags.
begin forbidden = ' !"#' + "$%&'()*+,-./:;<=>?[\\]^`{|}~" all_escaped = [] forbidden.each_char() { |ch| all_escaped << Regexp.escape(ch) } pattern = all_escaped.join('|') Regexp.new(pattern) end
Instance Attribute Summary collapse
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Class Method Summary collapse
- .indicate_parsing_error(line) ⇒ Object
-
.parse(line) ⇒ Object
The parse mechanism is designed to break up TDL lines into static and dynamic components.
Instance Method Summary collapse
-
#generate(source) ⇒ Object
To “generate” means to create an internal representation of the template.
- #generate_couple(item) ⇒ Object
- #generate_line(line) ⇒ Object
- #generate_sections(sequence) ⇒ Object
-
#initialize(source) ⇒ Engine
constructor
A new instance of Engine.
- #line_rep_ending(line) ⇒ Object
-
#output(context, params) ⇒ Object
This general output method will provide a final template within the given scope object (Placeholder, StaticText, etc) and with any of the parameters specified.
- #parse_element(text) ⇒ Object
- #validate_section_end(marker, sections) ⇒ Object
-
#variables ⇒ Object
This method is used to retrieve all of the variable elements, which will be placeholder names, that appear in the template.
Constructor Details
#initialize(source) ⇒ Engine
Returns a new instance of Engine.
134 135 136 137 138 139 140 |
# File 'lib/lucid/sequence/sequence_template.rb', line 134 def initialize(source) @source = source # The generated source contains an internal representation of the # given template text. @generated_source = generate(source) end |
Instance Attribute Details
#source ⇒ Object (readonly)
Returns the value of attribute source.
122 123 124 |
# File 'lib/lucid/sequence/sequence_template.rb', line 122 def source @source end |
Class Method Details
.indicate_parsing_error(line) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/lucid/sequence/sequence_template.rb', line 166 def self.indicate_parsing_error(line) # The regular expression will be looking to match \< or \>. Those are # escaped chevrons and will be replaced. no_escaped = line.gsub(/\\[<>]/, '--') unbalance_count = 0 no_escaped.each_char do |ch| case ch when '<' unbalance_count += 1 when '>' unbalance_count -= 1 end raise StandardError, "Nested opening chevron '<'." if unbalance_count > 1 raise StandardError, "Missing opening chevron '<'." if unbalance_count < 0 end raise StandardError, "Missing closing chevron '>'." if unbalance_count == 1 end |
.parse(line) ⇒ Object
The parse mechanism is designed to break up TDL lines into static and dynamic components. Dynamic components will correspond to tagged elements of the string, which indicate parameters in the original TDL phrase.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/lucid/sequence/sequence_template.rb', line 146 def self.parse(line) scanner = StringScanner.new(line) result = [] until scanner.eos? tag_literal = scanner.scan(/<(?:[^\\<>]|\\.)*>/) unless tag_literal.nil? result << [:dynamic, tag_literal.gsub(/^<|>$/, '')] end text_literal = scanner.scan(/(?:[^\\<>]|\\.)+/) result << [:static, text_literal] unless text_literal.nil? indicate_parsing_error(line) if tag_literal.nil? && text_literal.nil? end return result end |
Instance Method Details
#generate(source) ⇒ Object
To “generate” means to create an internal representation of the template.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/lucid/sequence/sequence_template.rb', line 243 def generate(source) input_lines = source.split(/\r\n?|\n/) raw_lines = input_lines.map do |line| line_items = self.class.parse(line) line_items.each do |(kind, text)| if (kind == :dynamic) && text.strip.empty? raise EmptyParameterError.new(line.strip) end end line_items end template_lines = raw_lines.map { |line| generate_line(line) } return generate_sections(template_lines.flatten) end |
#generate_couple(item) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/lucid/sequence/sequence_template.rb', line 289 def generate_couple(item) (kind, text) = item result = case kind when :static StaticText.new(text) when :dynamic parse_element(text) end return result end |
#generate_line(line) ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/lucid/sequence/sequence_template.rb', line 260 def generate_line(line) line_rep = line.map { |item| generate_couple(item) } section_item = nil line_to_despace = line_rep.all? do |item| case item when StaticText item.source =~ /\s+/ when Section, SectionEndMarker if section_item.nil? section_item = item true else false end else false end end if line_to_despace && ! section_item.nil? line_rep = [section_item] else line_rep_ending(line_rep) end return line_rep end |
#generate_sections(sequence) ⇒ Object
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/lucid/sequence/sequence_template.rb', line 302 def generate_sections(sequence) open_sections = [] generated = sequence.each_with_object([]) do |element, result| case element when Section open_sections << element when SectionEndMarker validate_section_end(element, open_sections) result << open_sections.pop() else if open_sections.empty? result << element else open_sections.last.add_child(element) end end end unless open_sections.empty? = "Unterminated section #{open_sections.last}." raise StandardError, end return generated end |
#line_rep_ending(line) ⇒ Object
341 342 343 344 345 346 347 348 349 |
# File 'lib/lucid/sequence/sequence_template.rb', line 341 def line_rep_ending(line) if line.last.is_a?(SectionEndMarker) section_end = line.pop() line << EOLine.new line << section_end else line << EOLine.new end end |
#output(context, params) ⇒ Object
This general output method will provide a final template within the given scope object (Placeholder, StaticText, etc) and with any of the parameters specified.
233 234 235 236 237 238 239 |
# File 'lib/lucid/sequence/sequence_template.rb', line 233 def output(context, params) return '' if @generated_source.empty? result = @generated_source.each_with_object('') do |element, item| item << element.output(context, params) end return result end |
#parse_element(text) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/lucid/sequence/sequence_template.rb', line 187 def parse_element(text) # Check if the text matched is a ? or a / character. If the next bit # of text after the ? or / is a invalid element of if there is an # invalid element at all, an error will be raised. if text =~ /^[\?\/]/ matching = InvalidInternalElements.match(text[1..-1]) else matching = InvalidInternalElements.match(text) end raise InvalidElementError.new(text, matching[0]) if matching result = case text[0, 1] when '/' SectionEndMarker.new(text[1..-1]) when '?' ConditionalSection.new(text[1..-1], true) else Placeholder.new(text) end return result end |
#validate_section_end(marker, sections) ⇒ Object
329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/lucid/sequence/sequence_template.rb', line 329 def validate_section_end(marker, sections) if sections.empty? msg = "End of section </#{marker.name}> found while no corresponding section is open." raise StandardError, msg end if marker.name != sections.last.name msg = "End of section </#{marker.name}> does not match current section '#{sections.last.name}'." raise StandardError, msg end end |
#variables ⇒ Object
This method is used to retrieve all of the variable elements, which will be placeholder names, that appear in the template.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/lucid/sequence/sequence_template.rb', line 213 def variables @variables ||= begin vars = @generated_source.each_with_object([]) do |element, result| case element when Placeholder result << element.name when Section result.concat(element.variables) else # noop end end vars.flatten.uniq end return @variables end |