Class: PuppetLint::Lexer::StringSlurper
- Inherits:
-
Object
- Object
- PuppetLint::Lexer::StringSlurper
- Defined in:
- lib/puppet-lint/lexer/string_slurper.rb
Overview
Internal: A class for slurping strings from a Puppet manifest.
Defined Under Namespace
Classes: UnterminatedStringError
Constant Summary collapse
- START_INTERP_PATTERN =
%r{\$\{}.freeze
- END_INTERP_PATTERN =
%r{\}}.freeze
- END_STRING_PATTERN =
%r{(\A|[^\\])(\\\\)*"}.freeze
- UNENC_VAR_PATTERN =
%r{(\A|[^\\])\$(::)?(\w+(-\w+)*::)*\w+(-\w+)*}.freeze
- ESC_DQUOTE_PATTERN =
%r{\\+"}.freeze
- LBRACE_PATTERN =
%r{\{}.freeze
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.
16 17 18 19 20 21 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 16 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.
7 8 9 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 7 def interp_stack @interp_stack end |
#results ⇒ Object
Returns the value of attribute results.
7 8 9 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 7 def results @results end |
#scanner ⇒ Object
Returns the value of attribute scanner.
7 8 9 |
# File 'lib/puppet-lint/lexer/string_slurper.rb', line 7 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
105 106 107 108 109 |
# 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) ⇒ Object
153 154 155 156 |
# 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 ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# 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 ⇒ Object
158 159 160 161 162 163 164 165 |
# 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 ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# 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) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# 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 ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 |
# 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 ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# 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 ⇒ Object
145 146 147 148 149 150 151 |
# 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? ⇒ Boolean
50 51 52 53 54 |
# 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 |