module Conker

Example that uses the process’s environment:

module Conker
  setup_config!(Rails.env, :A_SECRET => api_credential)
end

Example that uses a supplied hash of values (e.g. read from some file or database):

config_values = {:A_SECRET => 'very_secret'}
module Conker
  setup_config!(Rails.env, config_values, :A_SECRET => api_credential)
end

For convenience, if your config file is YAML, you can supply the path directly and Conker will load and parse the file:

module Conker
  setup_config!(Rails.env, 'config_values.yml', :A_SECRET => api_credential)
end

Constants

DUMMY_API_KEY
DUMMY_CRYPTO_SECRET
ENVIRONMENTS

Public Class Methods

api_credential(declaration_opts={}) click to toggle source

Declare an environment variable to be used as a credential for accessing an external API (e.g. username, password, API key, access token): shorthand for +required_in_production(:type => :string, :default => ‘dummy_api_key’)+

# File lib/conker.rb, line 91
def api_credential(declaration_opts={})
  required_in_production({
    :type => :string,
    :default => DUMMY_API_KEY,
  }.merge(declaration_opts))
end
couchbase_url(opts = {}) click to toggle source

A couchbase_url is required_in_production with development defaulting to localhost/default and test defaulting to localhost/test.

# File lib/conker.rb, line 124
def couchbase_url(opts = {})
  required_in_production({
    :development => 'http://localhost:8091/pools/default/buckets/default',
    :test => 'http://localhost:8091/pools/default/buckets/test',
  }.merge(opts))
end
crypto_secret(declaration_opts={}) click to toggle source

Declare an environment variable to be used as a secret key by some encryption algorithm used in our code.

To generate a secret suitable for production use, try:

openssl rand -hex 256

(which will generate 256 bytes = 2048 bits of randomness).

The distinction between this and api_credential is mainly for documentation purposes, but they also have different defaults.

# File lib/conker.rb, line 107
def crypto_secret(declaration_opts={})
  required_in_production({
    :type => :string,
    :default => DUMMY_CRYPTO_SECRET,
  }.merge(declaration_opts))
end
optional(declaration_opts = {}) click to toggle source

Declare an environment variable, defaulting to other values if not defined.

You must either specify a :default, or specify defaults for each of :production, :test and :development.

# File lib/conker.rb, line 135
def optional(declaration_opts = {})
  VariableDeclaration.new(declaration_opts)
end
redis_url(opts={}) click to toggle source

A redis url is required_in_production with development and test defaulting to localhost.

# File lib/conker.rb, line 115
def redis_url(opts={})
  required_in_production({
    :development => "redis://localhost/1",
    :test => "redis://localhost/3"
  }.merge(opts))
end
required_in_production(declaration_opts={}) click to toggle source

Declare an environment variable that is required to be defined in the production environment, and defaults to other values in the test or development environments.

You must either specify a :default, or specify defaults for each of :test and :development.

# File lib/conker.rb, line 83
def required_in_production(declaration_opts={})
  VariableDeclaration.new(declaration_opts.reverse_merge(:required_in => :production))
end
setup_config!(current_env, *args) click to toggle source

Parse a multi-key hash into globals and raise an informative error message on failure.

# File lib/conker.rb, line 44
def setup_config!(current_env, *args)
  declarations = args.extract_options!
  values = values_hash(current_env, args[0])

  setup_constants(current_env, declarations, values)
end
setup_rack_environment!(*args) click to toggle source

Like setup_config! but uses ENV || ‘development’ as the environment. Also sets constant RACK_ENV.

N.B. if using this method, you don’t need to specify :RACK_ENV in your variable declarations, and it will complain if you do. This is partly to make clear that this method *won’t* read RACK_ENV from your config file, only from the environment variable, for compatibility with other code (e.g. Sinatra) that depends directly on the environment variable.

# File lib/conker.rb, line 59
def setup_rack_environment!(*args)
  ENV['RACK_ENV'] ||= 'development'
  set_constant(:RACK_ENV, ENV['RACK_ENV'])
  current_env = get_constant(:RACK_ENV)

  declarations = args.extract_options!
  values = values_hash(current_env, args[0])

  if declarations.key?('RACK_ENV') || declarations.key?(:RACK_ENV)
    raise Error, "No need to declare RACK_ENV; please remove it to avoid confusion!"
  end
  if ENV.key?('RACK_ENV') && values.key?('RACK_ENV') && (env = ENV['RACK_ENV']) != (conf = values['RACK_ENV'])
    raise "RACK_ENV differs between environment (#{env}) and config (#{conf})!  Please remove it from your config."
  end

  setup_constants(current_env, declarations, values)
end

Private Class Methods

get_constant(varname) click to toggle source
# File lib/conker.rb, line 176
def get_constant(varname)
  Kernel.const_get(varname)
end
set_constant(varname, value) click to toggle source
# File lib/conker.rb, line 172
def set_constant(varname, value)
  Kernel.const_set(varname, value)
end
setup_constants(current_env, declarations, values) click to toggle source
# File lib/conker.rb, line 156
def setup_constants(current_env, declarations, values)
  errors = []
  declarations.each do |varname, declaration|
    begin
      set_constant(varname, declaration.evaluate(current_env, values, varname.to_s))
    rescue => error
      errors << [varname, error.message]
    end
  end

  error_message = errors.sort_by {|v, e| v.to_s }.map do |varname, error|
    varname.to_s + ': ' + error
  end.join(", ")
  raise Error, error_message unless errors.empty?
end
values_hash(current_env, values) click to toggle source
# File lib/conker.rb, line 140
def values_hash(current_env, values)
  case values
  when Hash; values
  when String
    if File.exist?(values)
      require 'yaml'
      YAML.parse_file(values).to_ruby
    elsif 'production' == current_env.to_s
      raise Error, "Missing config file #{values}"
    else
      {}
    end
  else; ENV
  end
end