dacs 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.3.0 2010-01-14
2
+ * Minor enhancements
3
+ * When an explicit schema is defined (using DSL):
4
+ * Will warn and exit when required keys are not configured
5
+ * Will raise an error when an undefined key is referenced
6
+ * New #report method added to dump a full configuration report
7
+
1
8
  == 0.2.0 2010-01-13
2
9
  * Major enhancements
3
10
  * Added new mini-DSL for defining known configuration keys
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/example/example.rb CHANGED
@@ -17,9 +17,10 @@ puts "foo: #{Dacs::AppConfig['foo']}"
17
17
  puts "bar: #{Dacs::AppConfig['bar']}"
18
18
  puts "baz: #{Dacs::AppConfig['baz']}"
19
19
  puts Dacs::AppConfig.dump # => nil
20
+ puts Dacs::AppConfig.report # => nil
20
21
 
21
- # >> I, [2010-02-13T02:34:46.344705 #25573] INFO -- : Found config file /devver-repos/dacs/example/example.yml.
22
- # >> W, [2010-02-13T02:34:46.345300 #25573] WARN -- : Unknown configuration key 'fuz' in file example.yml
22
+ # >> I, [2010-02-14T09:45:52.703585 #17437] INFO -- : Found config file /devver-repos/dacs/example/example.yml.
23
+ # >> W, [2010-02-14T09:45:52.704092 #17437] WARN -- : Unknown configuration key 'fuz' in file example.yml
23
24
  # >> Running in development mode
24
25
  # >> foo: file_foo
25
26
  # >> bar: env_bar
@@ -31,3 +32,15 @@ puts Dacs::AppConfig.dump # => nil
31
32
  # >> | foo | file_foo | file example.yml |
32
33
  # >> | bar | env_bar | environment |
33
34
  # >> +--------------------------------------+
35
+ # >> App name: example
36
+ # >> Environment: development
37
+ # >> Configuration file: /devver-repos/dacs/example/example.yml
38
+ # >> Configuration setup: -:5
39
+ # >> Env var prefix: EXAMPLE_
40
+ # >> +--------------------------------------+
41
+ # >> | Key | Value | Source |
42
+ # >> +--------------------------------------+
43
+ # >> | baz | default_baz | defaults |
44
+ # >> | foo | file_foo | file example.yml |
45
+ # >> | bar | env_bar | environment |
46
+ # >> +--------------------------------------+
@@ -41,7 +41,7 @@ module Dacs
41
41
 
42
42
  # Delegate a subset of Hash methods to the singleton instance
43
43
  def_delegators :instance, :[], :fetch, :key?, :merge, :merge!, :app_name,
44
- :source, :dump
44
+ :source, :dump, :report
45
45
 
46
46
  def_delegators :schema, :required?, :optional?, :keys, :default_value
47
47
  end
@@ -64,6 +64,7 @@ module Dacs
64
64
  @@options[:logger] ||= ::Logger.new($stderr)
65
65
  @@options[:environment] ||= :development
66
66
  @@options[:defaults] ||= {}
67
+ @@definition_location = caller[0]
67
68
  if block_given?
68
69
  schema = Schema.new
69
70
  yield(schema)
@@ -85,6 +86,10 @@ module Dacs
85
86
  def self.environment
86
87
  @@options[:environment]
87
88
  end
89
+
90
+ def self.definition_location
91
+ @@definition_location
92
+ end
88
93
 
89
94
  attr_reader :app_name
90
95
  attr_reader :logger
@@ -98,27 +103,37 @@ module Dacs
98
103
  @logger = @@options[:logger]
99
104
  @environment = @@options[:environment]
100
105
  @defaults = self.class.schema.defaults
106
+ @system = @@options.fetch(:system){Kernel}
101
107
  find_or_create_config_file!
102
108
 
103
109
  defaults_source = DefaultSource.new(@defaults)
104
110
  file_source = FileSource.new(config_path, @environment)
105
- env_source = EnvironmentSource.new(@app_name)
111
+ env_source = EnvironmentSource.new(env_var_prefix)
106
112
 
107
113
  load_values!(self.class.schema, env_source, file_source, defaults_source)
114
+ verify_no_missing_required_values!
115
+ end
116
+
117
+ def definition_location
118
+ self.class.definition_location
119
+ end
120
+
121
+ def env_var_prefix
122
+ app_name.to_s.upcase + "_"
108
123
  end
109
124
 
110
125
  def source(key)
111
- configured_value = Hash.instance_method(:fetch).bind(self).call(key.to_s) do
112
- raise ConfigurationError, "No such key '#{key}'"
113
- end
126
+ assert_key_defined!(key)
114
127
  configured_value.source.to_s
115
128
  end
116
129
 
117
130
  def [](key)
131
+ assert_key_defined!(key)
118
132
  super(key).value
119
133
  end
120
134
 
121
135
  def fetch(key, &block)
136
+ assert_key_defined!(key)
122
137
  case result = super(key, &block)
123
138
  when ConfiguredValue then result.value
124
139
  else result
@@ -133,8 +148,45 @@ module Dacs
133
148
  table.as(:text)
134
149
  end
135
150
 
151
+ def report
152
+ text = ""
153
+ text << "%-22s%s\n" % ["App name:", app_name]
154
+ text << "%-22s%s\n" % ["Environment:", environment]
155
+ text << "%-22s%s\n" % ["Configuration file:", config_path]
156
+ text << "%-22s%s\n" % ["Configuration setup:", definition_location]
157
+ text << "%-22s%s\n" % ["Env var prefix:", env_var_prefix]
158
+ text << dump
159
+ text
160
+ end
161
+
162
+ def verify_no_missing_required_values!
163
+ missing_keys = schema.keys - keys
164
+ missing_required_keys = missing_keys.select{|k| schema.required?(k)}
165
+ unless missing_required_keys.empty?
166
+ logger.fatal "Application not configured; exiting"
167
+ @system.warn "These required configuration keys were missing:"
168
+ missing_required_keys.each do |key|
169
+ @system.warn " #{key}"
170
+ end
171
+ @system.warn ""
172
+ @system.warn "Please set the required keys in #{config_path} or "\
173
+ "environment and try again."
174
+ @system.exit(1)
175
+ end
176
+ end
177
+
136
178
  private
137
179
 
180
+ def assert_key_defined!(key)
181
+ unless schema.defined?(key.to_s)
182
+ raise UndefinedKeyError, key, caller(3)
183
+ end
184
+ end
185
+
186
+ def schema
187
+ self.class.schema
188
+ end
189
+
138
190
  def find_or_create_config_file!
139
191
  if Pathname(config_path).exist?
140
192
  logger.info "Found config file #{config_path}."
@@ -174,8 +226,8 @@ END
174
226
  def load_values!(schema, *sources)
175
227
  sources.reverse_each do |source|
176
228
  source.each do |configured_value|
177
- if schema.defined?(configured_value.key)
178
- self[configured_value.key] = configured_value
229
+ if schema.defined?(configured_value.key.to_s)
230
+ self[configured_value.key.to_s] = configured_value
179
231
  else
180
232
  key = configured_value.key
181
233
  logger.warn "Unknown configuration key '#{key}' in #{source}"
@@ -1,7 +1,7 @@
1
1
  module Dacs
2
2
  class EnvironmentSource
3
- def initialize(app_name, environment=ENV)
4
- @app_name = app_name.to_s.downcase
3
+ def initialize(prefix, environment=ENV)
4
+ @prefix = prefix
5
5
  @environment = environment
6
6
  end
7
7
 
@@ -11,7 +11,7 @@ module Dacs
11
11
 
12
12
  def each
13
13
  @environment.each_pair do |key, value|
14
- if match = /^#{@app_name}_(.*)$/.match(key.downcase)
14
+ if match = /^#{@prefix.downcase}(.*)$/.match(key.downcase)
15
15
  yield ConfiguredValue.new(self, match[1], value)
16
16
  end
17
17
  end
data/lib/dacs/errors.rb CHANGED
@@ -1,3 +1,8 @@
1
1
  module Dacs
2
2
  ConfigurationError = Class.new(Exception)
3
+ class UndefinedKeyError < ConfigurationError
4
+ def initialize(key)
5
+ super("Unknown configuration key '#{key}'")
6
+ end
7
+ end
3
8
  end
data/lib/dacs/schema.rb CHANGED
@@ -31,7 +31,7 @@ module Dacs
31
31
 
32
32
  def defaults
33
33
  key_defs.inject({}) { |h, key_def|
34
- h[key_def[:name]] = key_def[:default]
34
+ h[key_def[:name]] = key_def[:default] if key_def.key?(:default)
35
35
  h
36
36
  }
37
37
  end
@@ -39,7 +39,7 @@ module Dacs
39
39
  private
40
40
 
41
41
  def assert_key_defined!(key)
42
- !!key_def(key) or raise ConfigurationError, "No configuration key '#{key}' is defined"
42
+ !!key_def(key) or raise UndefinedKeyError, key
43
43
  end
44
44
 
45
45
  def key_defs
@@ -59,6 +59,31 @@ module Dacs
59
59
  end
60
60
  end
61
61
 
62
+ context "given strict definitions and a missing required key" do
63
+ before :each do
64
+ @system = stub("system").as_null_object
65
+ end
66
+
67
+ def do_init
68
+ AppConfig.init!(@app_name, :logger => @logger, :system => @system) do |config|
69
+ config.key "foo"
70
+ config.key "bar"
71
+ end
72
+ end
73
+
74
+ it "should exit the program with an error status" do
75
+ @system.should_receive(:exit).with(1)
76
+ do_init
77
+ end
78
+
79
+ it "should warn the user about the missing config keys" do
80
+ @system.should_receive(:warn).with(/foo/)
81
+ @system.should_receive(:warn).with(/bar/)
82
+ @system.should_receive(:warn).any_number_of_times
83
+ do_init
84
+ end
85
+ end
86
+
62
87
  context "without explicit key definitions" do
63
88
  before :each do
64
89
  AppConfig.init!(@app_name,
@@ -91,12 +116,18 @@ module Dacs
91
116
 
92
117
  context "with explicit key definitions" do
93
118
  before :each do
119
+ ENV['FOO_APP_BAR'] = 'env_bar'
120
+ @def_line = __LINE__ + 1
94
121
  AppConfig.init!(@app_name, :logger => @logger) do |config|
95
122
  config.key :foo, :default => 42
96
123
  config.key 'bar'
97
124
  end
98
125
  end
99
126
 
127
+ after :each do
128
+ ENV.delete('FOO_APP_BAR')
129
+ end
130
+
100
131
  it "should be able to list known keys" do
101
132
  AppConfig.keys.should == ['foo', 'bar']
102
133
  end
@@ -115,6 +146,25 @@ module Dacs
115
146
  AppConfig.optional?(:foo).should be_true
116
147
  end
117
148
 
149
+ it "should raise an exception when an undefined key is referenced" do
150
+ lambda do
151
+ AppConfig['faz']
152
+ end.should raise_error(ConfigurationError)
153
+ end
154
+
155
+ it "should reference the offending line when an undefined key is referenced" do
156
+ @error_line = __LINE__ + 2
157
+ error = begin
158
+ AppConfig['faz']
159
+ rescue ConfigurationError => error
160
+ error
161
+ end
162
+ error.backtrace[0].should match(/#{__FILE__}:#{@error_line}/)
163
+ end
164
+
165
+ it "should remember where the keys were defined" do
166
+ AppConfig.definition_location.should match(/#{__FILE__}:#{@def_line}/)
167
+ end
118
168
  end
119
169
 
120
170
  context "with a mix of default, file, and environment settings" do
@@ -136,6 +186,10 @@ module Dacs
136
186
  end
137
187
  end
138
188
 
189
+ after :each do
190
+ ENV.delete('FOO_APP_BUZ')
191
+ end
192
+
139
193
  it "should have the correct values for each" do
140
194
  AppConfig['foo'].should be == 42
141
195
  AppConfig['bar'].should be == 'file_bar'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dacs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Devver, Inc.
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-13 00:00:00 -05:00
12
+ date: 2010-02-14 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency