Class: Dacs::AppConfig

Inherits:
Hash
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/dacs/app_config.rb

Overview

This configuration system is for deployment-specific values, such as AWS keys and API URLs.

Configuration values can be accessed anywhere in the app using the AppConfig class, which behaves like a Hash.

Note that all keys are strings - not symbols.

Configuration keys can be set at three levels: hardcoded defaults, in config/<APPNAME>.yml, or in the environment.

  1. Defaults are set below, in the initializer.

  2. Defaults will be overridden by config/<APPNAME>.yml. This file is broken into per-environment sections just like database.yml, so to configure for the development environment, you’d use something like the following in config/<APPNAME>.yml:

    development:

    api_base_uri: http://localhost:4567
    authenticate: false
    aws_access_key: 'XXX...'
    aws_secret_key: 'XXX...'
    simpledb_domain: 'my_sandbox_domain'
    
  3. Values in <APPNAME>.yml will be overidden by <APPNAME>_* environment variables. For instance, to set key ‘foo’ = ‘bar’, set APPNAME_FOO=‘bar’ in the process environment.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAppConfig

Returns a new instance of AppConfig.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/dacs/app_config.rb', line 99

def initialize
  raise "You must initialize with Dacs::AppConfig.init!()" unless @@options
  @app_name     = @@options[:app_name]
  @config_path  = @@options[:config_path]
  @logger       = @@options[:logger]
  @environment  = @@options[:environment]
  @defaults     = self.class.schema.defaults 
  @system       = @@options.fetch(:system){Kernel}
  find_or_create_config_file!

  defaults_source = DefaultSource.new(@defaults)
  file_source     = FileSource.new(config_path, @environment)
  env_source      = EnvironmentSource.new(env_var_prefix)
  sources         = []
  sources    << env_source
  sources    << file_source if file_source.readable?
  sources    << defaults_source
  load_values!(self.class.schema, *sources)
  verify_no_missing_required_values!
end

Instance Attribute Details

#app_nameObject (readonly)

Returns the value of attribute app_name.



94
95
96
# File 'lib/dacs/app_config.rb', line 94

def app_name
  @app_name
end

#config_pathObject (readonly)

Returns the value of attribute config_path.



96
97
98
# File 'lib/dacs/app_config.rb', line 96

def config_path
  @config_path
end

#environmentObject (readonly)

Returns the value of attribute environment.



97
98
99
# File 'lib/dacs/app_config.rb', line 97

def environment
  @environment
end

#loggerObject (readonly)

Returns the value of attribute logger.



95
96
97
# File 'lib/dacs/app_config.rb', line 95

def logger
  @logger
end

Class Method Details

.definition_locationObject



90
91
92
# File 'lib/dacs/app_config.rb', line 90

def self.definition_location
  @@definition_location
end

.environmentObject



86
87
88
# File 'lib/dacs/app_config.rb', line 86

def self.environment
  @@options[:environment]
end

.init!(app_name, options = {}) ⇒ Object

Usage:

Dacs::AppConfig.init!('example', 
  :environment => 'development',
  :logger      => Logger.new($stdout)) do |config|

  config.key 'foo', :default => 'default_foo'
  config.key 'bar', :default => 'default_bar'
  config.key 'baz', :default => 'default_baz'
end


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/dacs/app_config.rb', line 59

def self.init!(app_name, options={})
  @instance = nil
  @@options = options.merge(:app_name => app_name)
  @@options[:app_root]     ||= Pathname(Dir.pwd)
  @@options[:config_path]  ||= @@options[:app_root] + 'config' + "#{app_name}.yml"
  @@options[:logger]       ||= ::Logger.new($stderr)
  @@options[:environment]  ||= :development
  @@options[:defaults]     ||= {}
  @@definition_location    = caller[0]
  if block_given?
    schema = Schema.new
    yield(schema)
    @@schema = schema
  else
    @@schema = PermissiveSchema.new(@@options[:defaults])
  end
  self.instance
end

.instanceObject



78
79
80
# File 'lib/dacs/app_config.rb', line 78

def self.instance
  @instance ||= new
end

.schemaObject



82
83
84
# File 'lib/dacs/app_config.rb', line 82

def self.schema
  @@schema
end

Instance Method Details

#[](key) ⇒ Object



134
135
136
137
# File 'lib/dacs/app_config.rb', line 134

def [](key)
  assert_key_defined!(key)
  super(key).value
end

#definition_locationObject



120
121
122
# File 'lib/dacs/app_config.rb', line 120

def definition_location
  self.class.definition_location
end

#dumpObject



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/dacs/app_config.rb', line 160

def dump
  Hirb::Helpers::AutoTable.render(
    self.values,
    :fields => [:key, :value, :source],
    :headers => {
      :key    => "Key",
      :value  => "Value",
      :source => "Source"
    },
    :description => false) + "\n"
end

#env_var_prefixObject



124
125
126
# File 'lib/dacs/app_config.rb', line 124

def env_var_prefix
  app_name.to_s.upcase + "_"
end

#fetch(key, &block) ⇒ Object



139
140
141
142
143
144
145
# File 'lib/dacs/app_config.rb', line 139

def fetch(key, &block)
  assert_key_defined!(key)
  case result = super(key, &block)
  when ConfiguredValue then result.value
  else result
  end
end

#merge(new_values) ⇒ Object



147
148
149
# File 'lib/dacs/app_config.rb', line 147

def merge(new_values)
  self.clone.merge!(new_values)
end

#merge!(new_values) ⇒ Object



151
152
153
154
155
156
157
158
# File 'lib/dacs/app_config.rb', line 151

def merge!(new_values)
  new_values.each_pair do |k,v|
    self[k.to_s] = ConfiguredValue.new(
      CodeSource.new,
      k.to_s,
      v)
  end
end

#reportObject



172
173
174
175
176
177
178
179
180
181
# File 'lib/dacs/app_config.rb', line 172

def report
  text = ""
  text << "%-22s%s\n" % ["App name:",           app_name]
  text << "%-22s%s\n" % ["Environment:",        environment]
  text << "%-22s%s\n" % ["Configuration file:", config_path]
  text << "%-22s%s\n" % ["Configuration setup:", definition_location]
  text << "%-22s%s\n" % ["Env var prefix:", env_var_prefix]
  text << dump
  text
end

#source(key) ⇒ Object



128
129
130
131
132
# File 'lib/dacs/app_config.rb', line 128

def source(key)
  assert_key_defined!(key)
  # TODO is there a simpler way?
  Hash.instance_method(:[]).bind(self.class.instance).call(key).source.to_s
end

#verify_no_missing_required_values!Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/dacs/app_config.rb', line 183

def verify_no_missing_required_values!
  missing_keys = schema.keys - keys
  missing_required_keys = missing_keys.select{|k| schema.required?(k)}
  unless missing_required_keys.empty?
    logger.fatal "Application not configured; exiting"
    @system.warn "These required configuration keys were missing:"
    missing_required_keys.each do |key|
      @system.warn "    #{key}"
    end
    @system.warn ""
    @system.warn "Please set the required keys in #{config_path} or "\
      "environment and try again."
    @system.exit(1)
  end
end