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