Skip to content

Ruby 环境变量

环境变量是在操作系统中定义的动态值,可以影响程序的运行方式。Ruby提供了多种方式来访问和操作环境变量,本章将详细介绍如何在Ruby中使用环境变量。

🌍 什么是环境变量?

环境变量是操作系统级别的配置参数,它们为运行在系统上的程序提供配置信息。常见的环境变量包括:

  • PATH: 可执行文件的搜索路径
  • HOME: 用户主目录
  • USER: 当前用户名
  • LANG: 系统语言设置
  • RUBY_ENV: Ruby应用程序环境(development, production, test)

📦 访问环境变量

使用ENV对象

Ruby通过内置的ENV对象来访问环境变量,它是一个类似哈希的对象:

ruby
# 获取环境变量
home_dir = ENV['HOME']
user_name = ENV['USER']
path = ENV['PATH']

puts "主目录: #{home_dir}"
puts "用户名: #{user_name}"
puts "路径: #{path}"

# 检查环境变量是否存在
if ENV.has_key?('RUBY_ENV')
  puts "Ruby环境: #{ENV['RUBY_ENV']}"
else
  puts "未设置RUBY_ENV环境变量"
end

# 获取所有环境变量
puts "所有环境变量:"
ENV.each do |key, value|
  puts "#{key}: #{value}"
end

安全访问环境变量

ruby
# 提供默认值
database_url = ENV.fetch('DATABASE_URL', 'sqlite://localhost/default.db')
api_key = ENV.fetch('API_KEY') { 'default-api-key' }

# 检查是否存在
if ENV.key?('SECRET_KEY')
  secret_key = ENV['SECRET_KEY']
else
  puts "警告: 未设置SECRET_KEY环境变量"
  secret_key = 'default-secret'
end

# 使用三元运算符
debug_mode = ENV['DEBUG'] ? ENV['DEBUG'] == 'true' : false

🛠️ 设置环境变量

在Ruby程序中设置

ruby
# 设置环境变量
ENV['MY_APP_NAME'] = 'My Ruby Application'
ENV['APP_VERSION'] = '1.0.0'

# 验证设置
puts "应用名称: #{ENV['MY_APP_NAME']}"
puts "应用版本: #{ENV['APP_VERSION']}"

# 删除环境变量
ENV.delete('MY_APP_NAME')
puts "应用名称: #{ENV['MY_APP_NAME']}"  # nil

在不同操作系统中设置

Linux/macOS系统

bash
# 临时设置(当前会话有效)
export DATABASE_URL="postgresql://localhost/myapp"
export API_KEY="your-api-key-here"

# 在shell脚本中设置
#!/bin/bash
export RUBY_ENV=production
ruby my_app.rb

# 在.bashrc或.zshrc中永久设置
echo 'export RUBY_ENV=development' >> ~/.bashrc
source ~/.bashrc

Windows系统

cmd
# 命令行设置(当前会话有效)
set DATABASE_URL=postgresql://localhost/myapp
set API_KEY=your-api-key-here

# PowerShell设置
$env:RUBY_ENV="production"

# 永久设置(系统环境变量)
# 通过系统属性 -> 高级 -> 环境变量设置

🎯 常用Ruby环境变量

Ruby相关环境变量

ruby
# RUBY_ENV - 应用程序环境
ruby_env = ENV.fetch('RUBY_ENV', 'development')
case ruby_env
when 'development'
  puts "开发环境模式"
when 'production'
  puts "生产环境模式"
when 'test'
  puts "测试环境模式"
else
  puts "未知环境: #{ruby_env}"
end

# RUBYLIB - Ruby库路径
ruby_lib_path = ENV['RUBYLIB']
puts "Ruby库路径: #{ruby_lib_path}" if ruby_lib_path

# RUBYOPT - Ruby命令行选项
ruby_options = ENV['RUBYOPT']
puts "Ruby选项: #{ruby_options}" if ruby_options

# GEM_PATH - Gem搜索路径
gem_path = ENV['GEM_PATH']
puts "Gem路径: #{gem_path}" if gem_path

# GEM_HOME - Gem安装目录
gem_home = ENV['GEM_HOME']
puts "Gem主目录: #{gem_home}" if gem_home

应用程序环境变量

ruby
# 数据库配置
database_url = ENV.fetch('DATABASE_URL') do
  case ENV.fetch('RUBY_ENV', 'development')
  when 'development'
    'sqlite://localhost/development.db'
  when 'test'
    'sqlite://localhost/test.db'
  when 'production'
    raise "必须设置DATABASE_URL环境变量"
  end
end

# API密钥
api_key = ENV.fetch('API_KEY') do
  puts "警告: 使用默认API密钥(仅用于开发)"
  'default-api-key'
end

# 服务器配置
server_port = ENV.fetch('PORT', 3000).to_i
server_host = ENV.fetch('HOST', 'localhost')

puts "服务器配置: #{server_host}:#{server_port}"

🛡️ 环境变量安全

敏感信息处理

ruby
class Config
  # 敏感环境变量列表
  SENSITIVE_VARS = %w[
    DATABASE_URL
    API_KEY
    SECRET_KEY
    PASSWORD
    PRIVATE_KEY
  ].freeze
  
  def self.get(key, default = nil)
    value = ENV[key]
    return default if value.nil? || value.empty?
    value
  end
  
  def self.get_required(key)
    value = ENV[key]
    raise "必须设置环境变量: #{key}" if value.nil? || value.empty?
    value
  end
  
  def self.safe_display
    ENV.each do |key, value|
      if SENSITIVE_VARS.any? { |sensitive| key.upcase.include?(sensitive) }
        puts "#{key}: ********"  # 隐藏敏感信息
      else
        puts "#{key}: #{value}"
      end
    end
  end
end

# 使用示例
begin
  db_url = Config.get_required('DATABASE_URL')
  api_key = Config.get('API_KEY', 'default-key')
  puts "配置加载成功"
rescue => e
  puts "配置错误: #{e.message}"
end

环境变量验证

ruby
class EnvironmentValidator
  def self.validate_required(vars)
    missing = []
    vars.each do |var|
      missing << var unless ENV[var] && !ENV[var].empty?
    end
    
    unless missing.empty?
      raise "缺少必需的环境变量: #{missing.join(', ')}"
    end
  end
  
  def self.validate_format(var, pattern, description = nil)
    value = ENV[var]
    return true if value.nil? || value.empty?
    
    unless value.match?(pattern)
      desc = description || "#{var}格式不正确"
      raise "环境变量验证失败: #{desc}"
    end
    
    true
  end
  
  def self.validate_numeric(var, min = nil, max = nil)
    value = ENV[var]
    return true if value.nil? || value.empty?
    
    begin
      num = Integer(value)
      if min && num < min
        raise "环境变量#{var}必须大于等于#{min}"
      end
      if max && num > max
        raise "环境变量#{var}必须小于等于#{max}"
      end
    rescue ArgumentError
      raise "环境变量#{var}必须是数字"
    end
    
    true
  end
end

# 使用示例
begin
  # 验证必需的环境变量
  EnvironmentValidator.validate_required(['DATABASE_URL', 'API_KEY'])
  
  # 验证邮箱格式
  EnvironmentValidator.validate_format('ADMIN_EMAIL', 
                                     /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i,
                                     '管理员邮箱格式不正确')
  
  # 验证端口号
  EnvironmentValidator.validate_numeric('PORT', 1, 65535)
  
  puts "环境变量验证通过"
rescue => e
  puts "环境变量验证失败: #{e.message}"
  exit 1
end

📁 环境配置管理

使用配置文件

ruby
require 'yaml'

class EnvironmentConfig
  def self.load_config(config_file = 'config.yml')
    # 加载配置文件
    config = YAML.load_file(config_file) rescue {}
    
    # 合并环境变量
    env = ENV.fetch('RUBY_ENV', 'development')
    config.merge(config[env] || {})
  end
  
  def self.database_config
    {
      url: ENV.fetch('DATABASE_URL') { default_database_url },
      pool: ENV.fetch('DB_POOL_SIZE', 5).to_i,
      timeout: ENV.fetch('DB_TIMEOUT', 5000).to_i
    }
  end
  
  private
  
  def self.default_database_url
    case ENV.fetch('RUBY_ENV', 'development')
    when 'development'
      'sqlite://localhost/development.db'
    when 'test'
      'sqlite://localhost/test.db'
    when 'production'
      raise "生产环境必须设置DATABASE_URL"
    end
  end
end

# config.yml示例
=begin
---
development:
  database_url: sqlite://localhost/dev.db
  api_key: dev-key
  debug: true

production:
  debug: false

test:
  database_url: sqlite://localhost/test.db
  api_key: test-key
=end

# 使用配置
config = EnvironmentConfig.load_config
puts "数据库URL: #{config['database_url']}"

环境特定配置

ruby
class AppConfig
  def self.environment
    @environment ||= ENV.fetch('RUBY_ENV', 'development')
  end
  
  def self.development?
    environment == 'development'
  end
  
  def self.production?
    environment == 'production'
  end
  
  def self.test?
    environment == 'test'
  end
  
  def self.log_level
    if development?
      'debug'
    elsif production?
      'warn'
    else
      'info'
    end
  end
  
  def self.cache_enabled?
    return false if development?
    ENV.fetch('CACHE_ENABLED', 'true') == 'true'
  end
  
  def self.worker_processes
    if production?
      ENV.fetch('WORKER_PROCESSES', 4).to_i
    else
      1
    end
  end
end

# 根据环境配置应用
puts "当前环境: #{AppConfig.environment}"
puts "日志级别: #{AppConfig.log_level}"
puts "缓存启用: #{AppConfig.cache_enabled?}"
puts "工作进程数: #{AppConfig.worker_processes}"

🧪 环境变量测试

测试环境变量

ruby
# 测试环境变量设置和获取
RSpec.describe 'Environment Variables' do
  before do
    @original_env = ENV.to_hash
  end
  
  after do
    ENV.replace(@original_env)
  end
  
  it 'should get environment variable' do
    ENV['TEST_VAR'] = 'test_value'
    expect(ENV['TEST_VAR']).to eq('test_value')
  end
  
  it 'should provide default value' do
    expect(ENV.fetch('NON_EXISTENT_VAR', 'default')).to eq('default')
  end
  
  it 'should handle required variables' do
    expect { ENV.fetch('REQUIRED_VAR') }.to raise_error(KeyError)
  end
end

# 简单的测试脚本
def test_environment_variables
  puts "=== 环境变量测试 ==="
  
  # 测试基本操作
  ENV['TEST_VAR'] = 'test_value'
  puts "设置测试变量: #{ENV['TEST_VAR']}"
  
  # 测试默认值
  default_value = ENV.fetch('NON_EXISTENT', 'default')
  puts "默认值测试: #{default_value}"
  
  # 测试存在性检查
  exists = ENV.key?('PATH')
  puts "PATH变量存在: #{exists}"
  
  # 清理测试变量
  ENV.delete('TEST_VAR')
  puts "清理测试变量完成"
  
  puts "=== 测试完成 ==="
end

# 运行测试
test_environment_variables if __FILE__ == $0

🎯 最佳实践

1. 使用dotenv管理开发环境变量

ruby
# Gemfile
# gem 'dotenv-rails'  # Rails应用
# gem 'dotenv'        # 普通Ruby应用

# .env文件示例
=begin
# 开发环境配置
DATABASE_URL=sqlite://localhost/development.db
API_KEY=dev-api-key
DEBUG=true
SECRET_KEY=dev-secret-key
=end

# 加载dotenv(在应用启动时)
require 'dotenv/load' if development?

# 访问环境变量
database_url = ENV['DATABASE_URL']
api_key = ENV['API_KEY']

2. 环境变量文档化

ruby
# environment_variables.rb
class EnvironmentVariables
  # 应用程序环境变量文档
  VARIABLES = {
    'DATABASE_URL' => {
      description: '数据库连接URL',
      required: true,
      default: nil,
      example: 'postgresql://user:pass@localhost/dbname'
    },
    'API_KEY' => {
      description: '第三方API密钥',
      required: false,
      default: 'default-key',
      example: 'sk-xxxxxxxxxxxxxxxxxxxxxxxx'
    },
    'PORT' => {
      description: '服务器端口',
      required: false,
      default: '3000',
      example: '3000'
    },
    'RUBY_ENV' => {
      description: '应用程序环境',
      required: false,
      default: 'development',
      example: 'development|production|test'
    }
  }.freeze
  
  def self.document
    puts "应用程序环境变量说明:"
    puts "=" * 50
    VARIABLES.each do |name, info|
      puts "变量名: #{name}"
      puts "  描述: #{info[:description]}"
      puts "  必需: #{info[:required] ? '是' : '否'}"
      puts "  默认: #{info[:default] || '无'}"
      puts "  示例: #{info[:example]}"
      puts
    end
  end
end

# 生成文档
# EnvironmentVariables.document

3. 环境隔离

ruby
class EnvironmentManager
  def self.setup_environment
    case ENV.fetch('RUBY_ENV', 'development')
    when 'development'
      setup_development
    when 'production'
      setup_production
    when 'test'
      setup_test
    else
      puts "未知环境: #{ENV['RUBY_ENV']}"
    end
  end
  
  private
  
  def self.setup_development
    puts "设置开发环境"
    # 开发环境特定配置
  end
  
  def self.setup_production
    puts "设置生产环境"
    # 生产环境特定配置
    disable_debug_output
    enable_caching
  end
  
  def self.setup_test
    puts "设置测试环境"
    # 测试环境特定配置
  end
  
  def self.disable_debug_output
    # 禁用调试输出
  end
  
  def self.enable_caching
    # 启用缓存
  end
end

# 应用启动时调用
EnvironmentManager.setup_environment

📚 下一步学习

掌握了Ruby环境变量的使用后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。