lib/dotenv/parser.rb in dotenv-2.4.0 vs lib/dotenv/parser.rb in dotenv-2.5.0

- old
+ new

@@ -10,25 +10,25 @@ class Parser @substitutions = [Dotenv::Substitutions::Variable, Dotenv::Substitutions::Command] LINE = / - \A - \s* - (?:export\s+)? # optional export - ([\w\.]+) # key - (?:\s*=\s*|:\s+?) # separator - ( # optional value begin - '(?:\'|[^'])*' # single quoted value - | # or - "(?:\"|[^"])*" # double quoted value - | # or - [^#\n]+ # unquoted value - )? # value end - \s* - (?:\#.*)? # optional comment - \z + (?:^|\A) # beginning of line + \s* # leading whitespace + (?:export\s+)? # optional export + ([\w\.]+) # key + (?:\s*=\s*?|:\s+?) # separator + ( # optional value begin + '(?:\\'|[^'])*' # single quoted value + | # or + "(?:\\"|[^"])*" # double quoted value + | # or + [^\#\r\n]+ # unquoted value + )? # value end + \s* # trailing whitespace + (?:\#.*)? # optional comment + (?:$|\z) # end of line /x class << self attr_reader :substitutions @@ -42,31 +42,35 @@ @hash = {} @is_load = is_load end def call - @string.split(/[\n\r]+/).each do |line| + # Convert line breaks to same format + lines = @string.gsub(/\r\n?/, "\n") + # Process matches + lines.scan(LINE).each do |key, value| + @hash[key] = parse_value(value || "") + end + # Process non-matches + lines.gsub(LINE, "").split(/[\n\r]+/).each do |line| parse_line(line) end @hash end private def parse_line(line) - if (match = line.match(LINE)) - key, value = match.captures - @hash[key] = parse_value(value || "") - elsif line.split.first == "export" + if line.split.first == "export" if variable_not_set?(line) raise FormatError, "Line #{line.inspect} has an unset variable" end end end def parse_value(value) # Remove surrounding quotes - value = value.strip.sub(/\A(['"])(.*)\1\z/, '\2') + value = value.strip.sub(/\A(['"])(.*)\1\z/m, '\2') if Regexp.last_match(1) == '"' value = unescape_characters(expand_newlines(value)) end