lib/macros4cuke/templating/engine.rb in macros4cuke-0.3.00 vs lib/macros4cuke/templating/engine.rb in macros4cuke-0.3.01
- old
+ new
@@ -128,18 +128,35 @@
public
# Add a child element as member of the section
def add_child(aChild)
children << aChild
end
+
+ # Retrieve all placeholder names that appear in the template.
+ # @return [Array] The list of placeholder names.
+ def variables()
+ all_vars = children.each_with_object([]) do |a_child, subResult|
+ case a_child
+ when Placeholder
+ subResult << a_child.name
+ when Section
+ subResult.concat(a_child.variables)
+ else
+ # Do nothing
+ end
+ end
+
+ return all_vars.flatten.uniq
+ end
-protected
+
# Render the placeholder given the passed arguments.
# This method has the same signature as the {Engine#render} method.
# @return [String] The text value assigned to the placeholder.
# Returns an empty string when no value is assigned to the placeholder.
def render(aContextObject, theLocals)
- raise NotImplementedError, "Method Section::#{_method_} must be implemented in subclass(es)."
+ raise NotImplementedError, "Method Section::#{__method__} must be implemented in subclass(es)."
end
end # class
@@ -173,12 +190,18 @@
else
result = ''
end
return result
- end
+ end
+
+ # @return [String] The original text representation of the tag.
+ def to_s()
+ return "<?#{name}>"
+ end
+
end # class
SectionEndMarker = Struct.new(:name)
@@ -230,12 +253,24 @@
# Retrieve all placeholder names that appear in the template.
# @return [Array] The list of placeholder names.
def variables()
# The result will be cached/memoized...
@variables ||= begin
- vars = @representation.select { |element| element.is_a?(Placeholder) }
- vars.map(&:name)
+ vars = @representation.each_with_object([]) do |element, subResult|
+ case element
+ when Placeholder
+ subResult << element.name
+
+ when Section
+ subResult.concat(element.variables)
+
+ else
+ # Do nothing
+ end
+ end
+
+ vars.flatten.uniq
end
return @variables
end
@@ -300,14 +335,48 @@
compiled_lines = raw_lines.map { |line| compile_line(line) }
return compile_sections(compiled_lines.flatten())
end
- # Convert the array of raw entries into full-fledged template elements.
+ # Convert the array of raw entries (per line) into full-fledged template elements.
def compile_line(aRawLine)
line_rep = aRawLine.map { |couple| compile_couple(couple) }
- line_rep << EOLine.new
+
+ # Apply the rule: when a line just consist of spaces and a section element,
+ # then remove all the spaces from that line.
+ section_item = nil
+ line_to_squeeze = 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_squeeze && ! section_item.nil?
+ line_rep = [section_item]
+ else
+ # Apply another rule: if last item in line is an end of section marker,
+ # then place eoline before that item. Otherwise, end the line with a eoline marker.
+ if line_rep.last.is_a?(SectionEndMarker)
+ section_end = line_rep.pop()
+ line_rep << EOLine.new
+ line_rep << section_end
+ else
+ line_rep << EOLine.new
+ end
+ end
+
+ return line_rep
end
# @param aCouple [Array] a two-element array of the form: [kind, text]
# Where kind must be one of :static, :dynamic
@@ -351,22 +420,23 @@
end
return result
end
- # Group the elements by sections.
+ # Transform a flat sequence of elements into a hierarchy of sections.
# @param flat_sequence [Array] a linear list of elements (including sections)
def compile_sections(flat_sequence)
open_sections = [] # The list of nested open sections
+
compiled = flat_sequence.each_with_object([]) do |element, subResult|
case element
when Section
open_sections << element
when SectionEndMarker
if open_sections.empty?
- raise StandardError, "End of section</#{element.name}> found while no corresponding section must be closed."
+ raise StandardError, "End of section</#{element.name}> found while no corresponding section is open."
end
if element.name != open_sections.last.name
raise StandardError, "End of section</#{element.name}> doesn't match current section '#{open_sections.last.name}'."
end
subResult << open_sections.pop()
@@ -378,9 +448,11 @@
open_sections.last.add_child(element)
end
end
end
+
+ raise StandardError, "Unterminated section #{open_sections.last}." unless open_sections.empty?
return compiled
end
end # class
\ No newline at end of file