Class: PuppetLint::Lexer::StringSlurper
- Inherits:
-
Object
- Object
- PuppetLint::Lexer::StringSlurper
- Defined in:
- lib/puppet-lint/lexer/string_slurper.rb
Overview
Document this TODO
Defined Under Namespace
Classes: UnterminatedStringError
Constant Summary collapse
- START_INTERP_PATTERN =
%r{\$\{}- END_INTERP_PATTERN =
%r{\}}- END_STRING_PATTERN =
%r{(\A|[^\\])(\\\\)*"}- UNENC_VAR_PATTERN =
%r{(\A|[^\\])\$(::)?(\w+(-\w+)*::)*\w+(-\w+)*}- ESC_DQUOTE_PATTERN =
%r{\\+"}- LBRACE_PATTERN =
%r{\{}
Instance Attribute Summary collapse
-
#interp_stack ⇒ Object
Returns the value of attribute interp_stack.
-
#results ⇒ Object
Returns the value of attribute results.
-
#scanner ⇒ Object
Returns the value of attribute scanner.
Instance Method Summary collapse
-
#consumed_chars ⇒ Object
Get the number of characters consumed by the StringSlurper.
- #end_heredoc(pattern) ⇒ Object
- #end_interp ⇒ Object
- #end_string ⇒ Object
-
#initialize(string) ⇒ StringSlurper
constructor
A new instance of StringSlurper.
- #parse ⇒ Object
- #parse_heredoc(heredoc_tag) ⇒ Object
- #read_char ⇒ Object
- #start_interp ⇒ Object
- #unenclosed_variable ⇒ Object
- #unenclosed_variable? ⇒ Boolean
Constructor Details
#initialize(string) ⇒ StringSlurper
Returns a new instance of StringSlurper.
21 22 23 24 25 26 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 21 def initialize(string) @scanner = StringScanner.new(string) @results = [] @interp_stack = [] @segment = [] end |
Instance Attribute Details
#interp_stack ⇒ Object
Returns the value of attribute interp_stack.
12 13 14 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 12 def interp_stack @interp_stack end |
#results ⇒ Object
Returns the value of attribute results.
11 12 13 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 11 def results @results end |
#scanner ⇒ Object
Returns the value of attribute scanner.
10 11 12 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 10 def scanner @scanner end |
Instance Method Details
#consumed_chars ⇒ Object
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
110 111 112 113 114 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 110 def consumed_chars return scanner.charpos if scanner.respond_to?(:charpos) (scanner.pre_match + scanner.matched).scan(%r{.}mu).length end |
#end_heredoc(pattern) ⇒ Object
158 159 160 161 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 158 def end_heredoc(pattern) results << [:HEREDOC, @segment.join] results << [:HEREDOC_TERM, scanner.scan(pattern)] end |
#end_interp ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 133 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 ⇒ Object
163 164 165 166 167 168 169 170 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 163 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 ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 28 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) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 61 def parse_heredoc(heredoc_tag) heredoc_name = heredoc_tag[%r{\A"?(.+?)"?(:.+?)?#{PuppetLint::Lexer::WHITESPACE_RE}*(/.*)?\Z}, 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 ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 88 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 ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 116 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 ⇒ Object
150 151 152 153 154 155 156 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 150 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? ⇒ Boolean
55 56 57 58 59 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 55 def unenclosed_variable? interp_stack.empty? && scanner.match?(UNENC_VAR_PATTERN) && (@segment.last.nil? ? true : !@segment.last.end_with?('\\')) end |