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.1.1".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`



116
117
118
119
120
121
122
123
124
# File 'lib/dotenv.rb', line 116

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
      raise unless ignore
    end

    hash.merge! env || {}
  end
end

#require_keys(*keys) ⇒ Object

Raises:



126
127
128
129
130
# File 'lib/dotenv.rb', line 126

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, <<~EOE.tr("\n", " ")
      Dotenv.restore is not thread safe. Use `Dotenv.modify { }` to update ENV for the duration
      of the block in a thread safe manner, or call `Dotenv.restore(safe: true)` to ignore
      this error.
    EOE
  end
  instrument(:restore, diff: diff) { ENV.replace(env) }
end

#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) (defaults to: false)

    Overwrite existing ‘ENV` values



98
99
100
101
102
103
104
105
106
107
108
# 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.
        overwrite ? new_value : old_value
      end
    end
    diff.env
  end
end