Module: Tina4::Env

Defined in:
lib/tina4/env.rb

Constant Summary collapse

DEFAULT_ENV =

NOTE: TINA4_SECRET is deliberately ABSENT here. The default signing secret must never become a guessable built-in. A blank secret is the signal for Auth.ensure_dev_secret to mint a per-machine random dev secret (saved to gitignored .env.local) in dev, or to emit the actionable “set TINA4_SECRET” warning in CI/prod. Parity with the Python master.

{
  "PROJECT_NAME" => "Tina4 Ruby Project",
  "TINA4_SWAGGER_VERSION" => "1.0.0",
  "TINA4_LOCALE" => "en",
  "TINA4_DEBUG" => "true",
  "TINA4_LOG_LEVEL" => "[TINA4_LOG_ALL]"
}.freeze
TRUTHY =

Typed env-var coercion — parity with tina4_python’s Env class, tina4-php’s Tina4Env, and tina4-nodejs’s Env. Truthy values (case-insensitive after strip): “1”, “true”, “on”, “yes”, “y”, “t”. Falsy: “0”, “false”, “off”, “no”, “n”, “f”, empty string. Anything else falls through to default.

%w[1 true on yes y t].freeze
FALSY =
%w[0 false off no n f].freeze

Class Method Summary collapse

Class Method Details

.all_envObject

Return all current ENV vars as a hash



201
202
203
# File 'lib/tina4/env.rb', line 201

def all_env
  ENV.to_h
end

.bool(name, default: false) ⇒ Object

Read an env var and coerce to Boolean. Returns default when the var is unset or holds a value outside the TRUTHY/FALSY tables. Never raises — bad input falls through to default.



114
115
116
117
118
119
120
121
# File 'lib/tina4/env.rb', line 114

def self.bool(name, default: false)
  raw = ENV[name.to_s]
  return default if raw.nil?
  token = raw.strip.downcase
  return true  if TRUTHY.include?(token)
  return false if FALSY.include?(token) || token.empty?
  default
end

.float(name, default: 0.0) ⇒ Object

Read an env var and coerce to Float. Logs a warning via Tina4::Log (if loaded) and returns default on parse failure. Never raises.



136
137
138
139
140
141
142
143
# File 'lib/tina4/env.rb', line 136

def self.float(name, default: 0.0)
  raw = ENV[name.to_s]
  return default if raw.nil?
  Float(raw.strip)
rescue ArgumentError, TypeError
  log_warning("Env.float(#{name.inspect}): could not parse #{raw.inspect} as Float — using default #{default.inspect}")
  default
end

.get_env(key, default = nil) ⇒ Object

Get an env var value, with optional default



191
192
193
# File 'lib/tina4/env.rb', line 191

def get_env(key, default = nil)
  ENV[key.to_s] || default
end

.has_env?(key) ⇒ Boolean

Check if an env var exists

Returns:

  • (Boolean)


196
197
198
# File 'lib/tina4/env.rb', line 196

def has_env?(key)
  ENV.key?(key.to_s)
end

.int(name, default: 0) ⇒ Object

Read an env var and coerce to Integer. Logs a warning via Tina4::Log (if loaded) and returns default on parse failure. Never raises.



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

def self.int(name, default: 0)
  raw = ENV[name.to_s]
  return default if raw.nil?
  Integer(raw.strip)
rescue ArgumentError, TypeError
  log_warning("Env.int(#{name.inspect}): could not parse #{raw.inspect} as Integer — using default #{default.inspect}")
  default
end

.is_truthy(val) ⇒ Object

Check if a value is truthy for env boolean checks.

Accepts: “true”, “True”, “TRUE”, “1”, “yes”, “Yes”, “YES”, “on”, “On”, “ON”. Everything else is falsy (including empty string, nil, not set).



107
108
109
# File 'lib/tina4/env.rb', line 107

def self.is_truthy(val)
  %w[true 1 yes on].include?(val.to_s.strip.downcase)
end

.load_env(root_dir = Dir.pwd) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/tina4/env.rb', line 164

def load_env(root_dir = Dir.pwd)
  env_file = resolve_env_file(root_dir)
  unless File.exist?(env_file)
    create_default_env(env_file)
  end
  # Precedence: real-env > .env.local > .env. Both loads are first-wins
  # (override=false / `ENV[key] ||= value`), so a key already present in
  # the real process environment is NEVER clobbered. .env.local loads
  # FIRST so its values beat .env, but a real env var set before boot
  # still wins over both. This is the security-correct ordering: a stray
  # gitignored .env.local (e.g. a stale auto-generated dev secret) must
  # not override an explicitly-set real TINA4_SECRET. The ensure-dev-secret
  # bootstrap runs AFTER this (only mints a secret if still unset in dev).
  load_local_env(root_dir)
  parse_env_file(env_file)
end

.load_local_env(root_dir = Dir.pwd) ⇒ Object

Load .env.local with first-wins semantics (override=false). A real process env var already present wins; this only fills keys not already set. Loaded BEFORE .env so .env.local beats .env (real-env > .env.local > .env). No-op when the file is absent (common for fresh checkouts).



185
186
187
188
# File 'lib/tina4/env.rb', line 185

def load_local_env(root_dir = Dir.pwd)
  local_file = File.join(root_dir, ".env.local")
  parse_env_file(local_file) if File.exist?(local_file)
end

.require_env!(*keys) ⇒ Object

Raise if any of the given keys are missing from ENV



206
207
208
209
210
211
# File 'lib/tina4/env.rb', line 206

def require_env!(*keys)
  missing = keys.map(&:to_s).reject { |k| ENV.key?(k) }
  unless missing.empty?
    raise KeyError, "Missing required env vars: #{missing.join(', ')}"
  end
end

.reset_envObject

Reset: clear all env vars that were loaded (restore to process defaults)



214
215
216
217
# File 'lib/tina4/env.rb', line 214

def reset_env
  @loaded_keys&.each { |k| ENV.delete(k) }
  @loaded_keys = []
end

.str(name, default: "") ⇒ Object

Read an env var as a String. Returns default when unset. Whitespace is preserved — this is a pass-through for the raw env value, matching Python’s Env.str semantics.



148
149
150
151
152
# File 'lib/tina4/env.rb', line 148

def self.str(name, default: "")
  raw = ENV[name.to_s]
  return default if raw.nil?
  raw
end