class Puppet::Pops::Parser::EppSupport::EppScanner
A scanner specialized in processing text with embedded EPP (Embedded Puppet) tags. The scanner is initialized with a StringScanner which it mutates as scanning takes place. The intent is to use one instance of EppScanner per wanted scan, and this instance represents the state after the scan.
@example Sample usage
a = "some text <% pp code %> some more text" scan = StringScanner.new(a) eppscan = EppScanner.new(scan) str = eppscan.scan eppscan.mode # => :epp eppscan.lines # => 0 eppscan
The scanner supports
-
scanning text until <%, <%-, <%=
-
while scanning text:
-
tokens <%% and %%> are translated to <% and %>, respectively, and is returned as text.
-
tokens <%# and %> (or ending with -%>) and the enclosed text is a comment and is not included in the returned text
-
text following a comment that ends with -%> gets trailing whitespace (up to and including a line break) trimmed and this whitespace is not included in the returned text.
-
-
The continuation {#mode} is set to one of:
-
`:epp` - for a <% token
-
`:expr` - for a <%= token
-
`:text` - when there was no continuation mode (e.g. when input ends with text)
-
':error` - if the tokens are unbalanced (reaching the end without a closing matching token). An error message is then also available via the method {#message}.
-
Note that the intent is to use this specialized scanner to scan the text parts, when continuation mode is `:epp` or `:expr` the pp lexer should advance scanning (using the string scanner) until it reaches and consumes a `-%>` or '%>ยด token. If it finds a `-%> token it should pass this on as a `skip_leading` parameter when it performs the next {#scan}.
Attributes
An error issue if `mode == :error`, `nil` otherwise.
The resulting mode after the scan. The mode is one of `:text` (the initial mode), `:epp` embedded code (no output), `:expr` (embedded expression), or `:error`
The original scanner used by the lexer/container using EppScanner
If the first scan should skip leading whitespace (typically detected by the pp lexer when the pp mode end-token is found (i.e. `-%>`) and then passed on to the scanner.
Public Class Methods
Creates an EppScanner based on a StringScanner that represents the state where EppScanner should start scanning. The given scanner will be mutated (i.e. position moved) to reflect the EppScanner's end state after a scan.
# File lib/puppet/pops/parser/epp_support.rb 164 def initialize(scanner) 165 @scanner = scanner 166 end
Public Instance Methods
Here for backwards compatibility. @deprecated Use issue instead @return [String] the issue message
# File lib/puppet/pops/parser/epp_support.rb 171 def message 172 @issue.nil? ? nil : @issue.format 173 end
Scans from the current position in the configured scanner, advances this scanner's position until the end of the input, or to the first position after a mode switching token (`<%`, `<%-` or `<%=`). Number of processed lines and continuation mode can be obtained via {#lines}, and {#mode}.
@return [String, nil] the scanned and processed text, or nil if at the end of the input.
# File lib/puppet/pops/parser/epp_support.rb 181 def scan(skip_leading=false) 182 @mode = :text 183 @skip_leading = skip_leading 184 185 return nil if scanner.eos? 186 s = String.new 187 until scanner.eos? 188 part = @scanner.scan_until(/(<%)|\z/) 189 if @skip_leading 190 part.sub!(/^[ \t]*\r?(?:\n|\z)?/,'') 191 @skip_leading = false 192 end 193 # The spec for %%> is to transform it into a literal %>. This is done here, as %%> otherwise would go 194 # undetected in text mode. (i.e. it is not really necessary to escape %> with %%> in text mode unless 195 # adding checks stating that a literal %> is illegal in text (unbalanced). 196 # 197 part.gsub!(/%%>/, '%>') 198 s += part 199 case @scanner.peek(1) 200 when "" 201 # at the end 202 # if s ends with <% then this is an error (unbalanced <% %>) 203 if s.end_with? "<%" 204 @mode = :error 205 @issue = Issues::EPP_UNBALANCED_EXPRESSION 206 end 207 return s 208 209 when "-" 210 # trim trailing whitespace on same line from accumulated s 211 # return text and signal switch to pp mode 212 @scanner.getch # drop the - 213 s.sub!(/[ \t]*<%\z/, '') 214 @mode = :epp 215 return s 216 217 when "%" 218 # verbatim text 219 # keep the scanned <%, and continue scanning after skipping one % 220 # (i.e. do nothing here) 221 @scanner.getch # drop the % to get a literal <% in the output 222 223 when "=" 224 # expression 225 # return text and signal switch to expression mode 226 # drop the scanned <%, and skip past -%>, or %>, but also skip %%> 227 @scanner.getch # drop the = 228 s.slice!(-2..-1) 229 @mode = :expr 230 return s 231 232 when "#" 233 # template comment 234 235 # drop the scanned <%, and skip past -%>, or %>, but also skip %%> 236 s.slice!(-2..-1) 237 238 # unless there is an immediate termination i.e. <%#%> scan for the next %> that is not 239 # preceded by a % (i.e. skip %%>) 240 part = scanner.scan_until(/[^%]%>/) 241 unless part 242 @issue = Issues::EPP_UNBALANCED_COMMENT 243 @mode = :error 244 return s 245 end 246 # Trim leading whitespace on the same line when start was <%#- 247 if part[1] == '-' 248 s.sub!(/[ \t]*\z/, '') 249 end 250 251 @skip_leading = true if part.end_with?("-%>") 252 # Continue scanning for more text 253 254 else 255 # Switch to pp after having removed the <% 256 s.slice!(-2..-1) 257 @mode = :epp 258 return s 259 end 260 end 261 end