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 163 def initialize(scanner) 164 @scanner = scanner 165 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 170 def message 171 @issue.nil? ? nil : @issue.format 172 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 180 def scan(skip_leading=false) 181 @mode = :text 182 @skip_leading = skip_leading 183 184 return nil if scanner.eos? 185 s = "" 186 until scanner.eos? 187 part = @scanner.scan_until(/(<%)|\z/) 188 if @skip_leading 189 part.sub!(/^[ \t]*\r?(?:\n|\z)?/,'') 190 @skip_leading = false 191 end 192 # The spec for %%> is to transform it into a literal %>. This is done here, as %%> otherwise would go 193 # undetected in text mode. (i.e. it is not really necessary to escape %> with %%> in text mode unless 194 # adding checks stating that a literal %> is illegal in text (unbalanced). 195 # 196 part.gsub!(/%%>/, '%>') 197 s += part 198 case @scanner.peek(1) 199 when "" 200 # at the end 201 # if s ends with <% then this is an error (unbalanced <% %>) 202 if s.end_with? "<%" 203 @mode = :error 204 @issue = Issues::EPP_UNBALANCED_EXPRESSION 205 end 206 return s 207 208 when "-" 209 # trim trailing whitespace on same line from accumulated s 210 # return text and signal switch to pp mode 211 @scanner.getch # drop the - 212 s.sub!(/[ \t]*<%\z/, '') 213 @mode = :epp 214 return s 215 216 when "%" 217 # verbatim text 218 # keep the scanned <%, and continue scanning after skipping one % 219 # (i.e. do nothing here) 220 @scanner.getch # drop the % to get a literal <% in the output 221 222 when "=" 223 # expression 224 # return text and signal switch to expression mode 225 # drop the scanned <%, and skip past -%>, or %>, but also skip %%> 226 @scanner.getch # drop the = 227 s.slice!(-2..-1) 228 @mode = :expr 229 return s 230 231 when "#" 232 # template comment 233 234 # drop the scanned <%, and skip past -%>, or %>, but also skip %%> 235 s.slice!(-2..-1) 236 237 # unless there is an immediate termination i.e. <%#%> scan for the next %> that is not 238 # preceded by a % (i.e. skip %%>) 239 part = scanner.scan_until(/[^%]%>/) 240 unless part 241 @issue = Issues::EPP_UNBALANCED_COMMENT 242 @mode = :error 243 return s 244 end 245 # Trim leading whitespace on the same line when start was <%#- 246 if part[1] == '-' 247 s.sub!(/[ \t]*\z/, '') 248 end 249 250 @skip_leading = true if part.end_with?("-%>") 251 # Continue scanning for more text 252 253 else 254 # Switch to pp after having removed the <% 255 s.slice!(-2..-1) 256 @mode = :epp 257 return s 258 end 259 end 260 end