Module: Dotenv

Extended by:
Dotenv
Included in:
Dotenv
Defined in:
lib/dotenv.rb,
lib/dotenv/cli.rb,
lib/dotenv/diff.rb,
lib/dotenv/rails.rb,
lib/dotenv/parser.rb,
lib/dotenv/version.rb,
lib/dotenv/template.rb,
lib/dotenv/environment.rb,
lib/dotenv/missing_keys.rb,
lib/dotenv/replay_logger.rb,
lib/dotenv/log_subscriber.rb,
lib/dotenv/substitutions/command.rb,
lib/dotenv/substitutions/variable.rb

Overview

Shim to load environment variables from ‘.env files into ENV.

Defined Under Namespace

Modules: Substitutions Classes: CLI, Diff, EnvTemplate, Environment, Error, FormatError, LogSubscriber, MissingKeys, Parser, Rails, ReplayLogger

Constant Summary collapse

Railtie =
ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Dotenv::Railtie", "Dotenv::Rails", Dotenv::Rails.deprecator)
VERSION =
"3.2.0".freeze
EXPORT_COMMAND =
"export ".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#instrumenterObject

Returns the value of attribute instrumenter.



15
16
17
# File 'lib/dotenv.rb', line 15

def instrumenter
  @instrumenter
end

Instance Method Details

#load(*filenames, overwrite: false, ignore: true) ⇒ Object

Loads environment variables from one or more .env files. See #parse for more details.



18
19
20
21
22
23
24
# File 'lib/dotenv.rb', line 18

def load(*filenames, overwrite: false, ignore: true)
  parse(*filenames, overwrite: overwrite, ignore: ignore) do |env|
    instrument(:load, env: env) do |payload|
      update(env, overwrite: overwrite)
    end
  end
end

#load!(*filenames) ⇒ Object

Same as #load, but raises Errno::ENOENT if any files don’t exist



27
28
29
# File 'lib/dotenv.rb', line 27

def load!(*filenames)
  load(*filenames, ignore: false)
end

#modify(env = {}, &block) ⇒ Object

Modify ENV for the block and restore it to its previous state afterwards.

Note that the block is synchronized to prevent concurrent modifications to ENV, so multiple threads will be executed serially.

Parameters:

  • env (Hash) (defaults to: {})

    Hash of keys and values to set in ENV



124
125
126
127
128
129
130
131
132
# File 'lib/dotenv.rb', line 124

def modify(env = {}, &block)
  SEMAPHORE.synchronize do
    diff = Dotenv::Diff.new
    update(env, overwrite: true)
    block.call
  ensure
    restore(diff.a, safe: true)
  end
end

#overwrite(*filenames) ⇒ Object Also known as: overload

same as #load, but will overwrite existing values in ENV



32
33
34
# File 'lib/dotenv.rb', line 32

def overwrite(*filenames)
  load(*filenames, overwrite: true)
end

#overwrite!(*filenames) ⇒ Object Also known as: overload!

same as #overwrite, but raises Errno::ENOENT if any files don’t exist



38
39
40
# File 'lib/dotenv.rb', line 38

def overwrite!(*filenames)
  load(*filenames, overwrite: true, ignore: false)
end

#parse(*filenames, overwrite: false, ignore: true, &block) ⇒ Hash

Parses the given files, yielding for each file if a block is given.

Parameters:

  • filenames (String, Array<String>)

    Files to parse

  • overwrite (Boolean) (defaults to: false)

    Overwrite existing ENV values

  • ignore (Boolean) (defaults to: true)

    Ignore non-existent files

  • block (Proc)

    Block to yield for each parsed Dotenv::Environment

Returns:

  • (Hash)

    parsed key/value pairs



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/dotenv.rb', line 50

def parse(*filenames, overwrite: false, ignore: true, &block)
  filenames << ".env" if filenames.empty?
  filenames = filenames.reverse if overwrite

  filenames.reduce({}) do |hash, filename|
    begin
      env = Environment.new(File.expand_path(filename), overwrite: overwrite)
      env = block.call(env) if block
    rescue Errno::ENOENT, Errno::EISDIR
      raise unless ignore
    end

    hash.merge! env || {}
  end
end

#require_keys(*keys) ⇒ Object

Raises:



134
135
136
137
138
# File 'lib/dotenv.rb', line 134

def require_keys(*keys)
  missing_keys = keys.flatten - ::ENV.keys
  return if missing_keys.empty?
  raise MissingKeys, missing_keys
end

#restore(env = @diff&.a, safe: Thread.current == Thread.main) ⇒ Object

Restore ENV to a given state

Parameters:

  • env (Hash) (defaults to: @diff&.a)

    Hash of keys and values to restore, defaults to the last saved state

  • safe (Boolean) (defaults to: Thread.current == Thread.main)

    Is it safe to modify ENV? Defaults to true in the main thread, otherwise raises an error.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dotenv.rb', line 77

def restore(env = @diff&.a, safe: Thread.current == Thread.main)
  # No previously saved or provided state to restore
  return unless env

  diff = Dotenv::Diff.new(b: env)
  return unless diff.any?

  unless safe
    raise ThreadError, "      Dotenv.restore is not thread safe. Use `Dotenv.modify { }` to update ENV for the duration\n      of the block in a thread safe manner, or call `Dotenv.restore(safe: true)` to ignore\n      this error.\n    EOE\n  end\n  instrument(:restore, diff: diff) { ENV.replace(env) }\nend\n".tr("\n", " ")

#saveObject

Save the current ENV to be restored later



67
68
69
70
71
# File 'lib/dotenv.rb', line 67

def save
  instrument(:save) do |payload|
    @diff = payload[:diff] = Dotenv::Diff.new
  end
end

#update(env = {}, overwrite: false) ⇒ Object

Update ENV with the given hash of keys and values

Parameters:

  • env (Hash) (defaults to: {})

    Hash of keys and values to set in ENV

  • overwrite (Boolean|:warn) (defaults to: false)

    Overwrite existing ENV values



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/dotenv.rb', line 98

def update(env = {}, overwrite: false)
  instrument(:update) do |payload|
    diff = payload[:diff] = Dotenv::Diff.new do
      ENV.update(env.transform_keys(&:to_s)) do |key, old_value, new_value|
        # This block is called when a key exists. Return the new value if overwrite is true.
        case overwrite
        when :warn
          # not printing the value since that could be a secret
          warn "Warning: dotenv not overwriting ENV[#{key.inspect}]"
          old_value
        when true then new_value
        when false then old_value
        else raise ArgumentError, "Invalid value for overwrite: #{overwrite.inspect}"
        end
      end
    end
    diff.env
  end
end