class PuppetLint::Lexer::StringSlurper
Internal: A class for slurping strings from a Puppet manifest.
Constants
- END_INTERP_PATTERN
- END_STRING_PATTERN
- ESC_DQUOTE_PATTERN
- LBRACE_PATTERN
- START_INTERP_PATTERN
- UNENC_VAR_PATTERN
Attributes
interp_stack[RW]
results[RW]
scanner[RW]
Public Class Methods
new(string)
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 16 def initialize(string) @scanner = StringScanner.new(string) @results = [] @interp_stack = [] @segment = [] end
Public Instance Methods
consumed_chars()
click to toggle source
Get the number of characters consumed by the StringSlurper.
StringScanner from Ruby 2.0 onwards supports charpos which returns the number of characters and is multibyte character aware.
Prior to this, Ruby’s multibyte character support in Strings was a bit unusual and neither String#length nor String#split behave as expected, so we use String#scan to split all the consumed text using a UTF-8 aware regex and use the length of the result
# File lib/puppet-lint/lexer/string_slurper.rb, line 105 def consumed_chars return scanner.charpos if scanner.respond_to?(:charpos) (scanner.pre_match + scanner.matched).scan(%r{.}mu).length end
end_heredoc(pattern)
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 153 def end_heredoc(pattern) results << [:HEREDOC, @segment.join] results << [:HEREDOC_TERM, scanner.scan(pattern)] end
end_interp()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 128 def end_interp if interp_stack.empty? @segment << scanner.scan(END_INTERP_PATTERN) return else interp_stack.pop end if interp_stack.empty? results << [:INTERP, @segment.join] @segment = [] scanner.skip(END_INTERP_PATTERN) else @segment << scanner.scan(END_INTERP_PATTERN) end end
end_string()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 158 def end_string if interp_stack.empty? @segment << scanner.scan(END_STRING_PATTERN).gsub!(%r{"\Z}, '') results << [@segment_type, @segment.join] else @segment << scanner.scan(END_STRING_PATTERN) end end
parse()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 23 def parse @segment_type = :STRING until scanner.eos? if scanner.match?(START_INTERP_PATTERN) start_interp elsif !interp_stack.empty? && scanner.match?(LBRACE_PATTERN) read_char elsif scanner.match?(END_INTERP_PATTERN) end_interp elsif unenclosed_variable? unenclosed_variable elsif scanner.match?(END_STRING_PATTERN) end_string break if interp_stack.empty? elsif scanner.match?(ESC_DQUOTE_PATTERN) @segment << scanner.scan(ESC_DQUOTE_PATTERN) else read_char end end raise UnterminatedStringError if results.empty? && scanner.matched? results end
parse_heredoc(heredoc_tag)
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 56 def parse_heredoc(heredoc_tag) heredoc_name = heredoc_tag[%r{\A"?(.+?)"?(:.+?)?#{PuppetLint::Lexer::WHITESPACE_RE}*(/.*)?\Z}o, 1] end_heredoc_pattern = %r{^\|?\s*-?\s*#{Regexp.escape(heredoc_name)}$} interpolation = heredoc_tag.start_with?('"') @segment_type = :HEREDOC until scanner.eos? if scanner.match?(end_heredoc_pattern) end_heredoc(end_heredoc_pattern) break if interp_stack.empty? elsif interpolation && scanner.match?(START_INTERP_PATTERN) start_interp elsif interpolation && !interp_stack.empty? && scanner.match?(LBRACE_PATTERN) read_char elsif interpolation && unenclosed_variable? unenclosed_variable elsif interpolation && scanner.match?(END_INTERP_PATTERN) end_interp else read_char end end results end
read_char()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 83 def read_char @segment << scanner.getch return if interp_stack.empty? case @segment.last when '{' interp_stack.push(true) when '}' interp_stack.pop end end
start_interp()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 111 def start_interp if @segment.last && @segment.last == '\\' read_char return end if interp_stack.empty? scanner.skip(START_INTERP_PATTERN) results << [@segment_type, @segment.join] @segment = [] else @segment << scanner.scan(START_INTERP_PATTERN) end interp_stack.push(true) end
unenclosed_variable()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 145 def unenclosed_variable read_char if scanner.match?(%r{.\$}) results << [@segment_type, @segment.join] results << [:UNENC_VAR, scanner.scan(UNENC_VAR_PATTERN)] @segment = [] end
unenclosed_variable?()
click to toggle source
# File lib/puppet-lint/lexer/string_slurper.rb, line 50 def unenclosed_variable? interp_stack.empty? && scanner.match?(UNENC_VAR_PATTERN) && (@segment.last.nil? ? true : !@segment.last.end_with?('\\')) end