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.0.2".freeze
EXPORT_COMMAND =
"export ".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#instrumenterObject

Returns the value of attribute instrumenter.



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

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.



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

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



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

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



112
113
114
115
116
117
118
119
120
# File 'lib/dotenv.rb', line 112

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



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

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



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

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



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

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:



122
123
124
125
126
# File 'lib/dotenv.rb', line 122

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.



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

def restore(env = @diff&.a, safe: Thread.current == Thread.main)
  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



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

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



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/dotenv.rb', line 94

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