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.0".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