autoconfig 1.0.0 → 1.1.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/lib/autoconfig.rb +119 -90
- metadata +3 -3
data/lib/autoconfig.rb
CHANGED
@@ -3,122 +3,151 @@ require 'yaml'
|
|
3
3
|
require 'erb'
|
4
4
|
require 'set'
|
5
5
|
|
6
|
-
module StringCamelize
|
7
|
-
# Taken straight from active support inflector.rb, line 161
|
8
|
-
def camelize(first_letter_in_uppercase = true)
|
9
|
-
if first_letter_in_uppercase
|
10
|
-
to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
11
|
-
else
|
12
|
-
first + camelize(self)[1..-1]
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
String.send(:include, StringCamelize) unless String.instance_methods.include?("camelize")
|
17
6
|
|
18
|
-
|
7
|
+
module AutoConfig
|
19
8
|
REQUIRED = :REQUIRED
|
20
9
|
YAML.add_builtin_type( 'REQUIRED' ){ REQUIRED }
|
21
10
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def path
|
33
|
-
ENV['AUTOCONFIG_PATH'] || File.expand_path(pattern, root)
|
11
|
+
module StringCamelize
|
12
|
+
# Taken straight from active support inflector.rb, line 161
|
13
|
+
def camelize(first_letter_in_uppercase = true)
|
14
|
+
if first_letter_in_uppercase
|
15
|
+
to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
16
|
+
else
|
17
|
+
first + camelize(self)[1..-1]
|
18
|
+
end
|
34
19
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
20
|
+
end
|
21
|
+
String.send(:include, StringCamelize) unless String.instance_methods.include?("camelize")
|
22
|
+
|
23
|
+
class OpenStruct < ::OpenStruct
|
24
|
+
def method_missing(mid, *args) # :nodoc:
|
25
|
+
mname = mid.id2name
|
26
|
+
len = args.length
|
27
|
+
if mname.chomp!('=')
|
28
|
+
if len != 1
|
29
|
+
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
|
30
|
+
end
|
31
|
+
modifiable[new_ostruct_member(mname)] = args[0]
|
32
|
+
elsif len == 0 && @table.key?( mid )
|
33
|
+
@table[mid]
|
34
|
+
else
|
35
|
+
raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
|
36
|
+
end
|
38
37
|
end
|
38
|
+
end
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
class Base
|
41
|
+
class << self
|
42
|
+
def root
|
43
|
+
rails_root = (rails? && (Rails.root || File.expand_path('../', ENV['BUNDLE_GEMFILE'])))
|
44
|
+
ENV['AUTOCONFIG_ROOT'] || ENV['APP_ROOT'] || rails_root || Dir.pwd
|
45
|
+
end
|
43
46
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
47
|
+
def pattern
|
48
|
+
ENV['AUTOCONFIG_PATTERN'] || 'config/*.yml'
|
49
|
+
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
begin
|
53
|
-
old_verbose, $VERBOSE = $VERBOSE, nil
|
51
|
+
def path
|
52
|
+
ENV['AUTOCONFIG_PATH'] || File.expand_path(pattern, root)
|
53
|
+
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
def environment
|
56
|
+
ENV['AUTOCONFIG_ENV'] || ENV['APP_ENV'] || (rails? && Rails.env) || 'development'
|
57
|
+
end
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
def rails?
|
60
|
+
Object::const_defined? "Rails"
|
61
|
+
end
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
def ignored_filenames
|
64
|
+
names = ENV['AUTOCONFIG_IGNORE'] ? "database|" + ENV['AUTOCONFIG_IGNORE'].gsub(/\s/,'|') : 'database'
|
65
|
+
Regexp.new(names)
|
66
|
+
end
|
66
67
|
|
67
|
-
|
68
|
-
|
68
|
+
def reload
|
69
|
+
wipe
|
70
|
+
files = Dir.glob(path)
|
71
|
+
begin
|
72
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
73
|
+
|
74
|
+
files.each do |file|
|
75
|
+
name = File.basename(file, '.yml')
|
76
|
+
next if name.match(ignored_filenames)
|
77
|
+
|
78
|
+
constant_name = "#{name}Config".gsub('-','_').camelize
|
79
|
+
begin
|
80
|
+
yaml_config = YAML::load(ERB.new(IO.read(file)).result)
|
81
|
+
|
82
|
+
@ordered_stanza_labels[constant_name] = []
|
83
|
+
@ordered_stanza_labels[constant_name] << 'defaults' if yaml_config.key? 'defaults'
|
84
|
+
@ordered_stanza_labels[constant_name] += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{ |a| a.count(',') }
|
85
|
+
@ordered_stanza_labels[constant_name] << environment if yaml_config.key? environment
|
86
|
+
|
87
|
+
config = @ordered_stanza_labels[constant_name].inject({}) do |acc, label|
|
88
|
+
deep_merge(acc,yaml_config[label])
|
89
|
+
end
|
90
|
+
|
91
|
+
ensure_requirements_met_and_ostructify!(config, constant_name )
|
92
|
+
|
93
|
+
Object::const_set(constant_name.intern, OpenStruct.new(config))
|
94
|
+
rescue StandardError => e
|
95
|
+
@errors << <<-ERROR
|
96
|
+
Error reading file #{file} into #{constant_name}.
|
97
|
+
#{$!.inspect}
|
98
|
+
#{$@}
|
99
|
+
You can skip it by adding it to AUTOCONFIG_IGNORE.
|
100
|
+
ERROR
|
101
|
+
end
|
69
102
|
end
|
70
103
|
|
71
|
-
|
104
|
+
raise @errors.to_a.join( "\n" ) unless @errors.empty?
|
72
105
|
|
73
|
-
|
106
|
+
ensure
|
107
|
+
$VERBOSE = old_verbose
|
74
108
|
end
|
75
|
-
|
76
|
-
raise @errors.to_a.join( "\n" ) unless @errors.empty?
|
77
|
-
|
78
|
-
ensure
|
79
|
-
$VERBOSE = old_verbose
|
80
109
|
end
|
81
|
-
end
|
82
110
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
111
|
+
private
|
112
|
+
# unsets created constants
|
113
|
+
def wipe
|
114
|
+
unless @ordered_stanza_labels.nil?
|
115
|
+
@ordered_stanza_labels.keys.each{|const| Object::const_set(const.intern, nil) }
|
116
|
+
end
|
117
|
+
@ordered_stanza_labels = {}
|
118
|
+
@errors = Set.new
|
88
119
|
end
|
89
|
-
@ordered_stanza_labels = {}
|
90
|
-
@errors = Set.new
|
91
|
-
end
|
92
120
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
121
|
+
# merges two hashes with nested hashes if present
|
122
|
+
def deep_merge( hash1, hash2 )
|
123
|
+
hash1 = hash1.dup
|
124
|
+
( hash1.keys + hash2.keys ).each do | key |
|
125
|
+
if hash1.key?( key ) && hash2.key?( key ) &&
|
126
|
+
hash1[key].is_a?( Hash ) && hash2[key].is_a?( Hash )
|
127
|
+
hash1[key] = deep_merge( hash1[key], hash2[key] )
|
128
|
+
elsif hash2.key?( key )
|
129
|
+
hash1[key] = hash2[key]
|
130
|
+
end
|
102
131
|
end
|
132
|
+
hash1
|
103
133
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
134
|
+
# Mutator method that does two things:
|
135
|
+
# * checks if any of the keys were required and not set. Upon finding
|
136
|
+
# it adds key to the error set
|
137
|
+
# * recursively sets open structs for deep hashes
|
138
|
+
def ensure_requirements_met_and_ostructify!( hash, path )
|
139
|
+
hash.each do | key, value |
|
140
|
+
case
|
141
|
+
when value.respond_to?( :keys ) && value.respond_to?( :values )
|
142
|
+
ensure_requirements_met_and_ostructify!( value, path + '.' + key )
|
143
|
+
when value == REQUIRED
|
144
|
+
@errors << "#{path}.#{key} is REQUIRED"
|
145
|
+
end
|
146
|
+
hash[key] = OpenStruct.new(value) if value.is_a?( Hash )
|
117
147
|
end
|
118
|
-
hash[key] = OpenStruct.new(value) if value.is_a?( Hash )
|
119
148
|
end
|
120
149
|
end
|
121
150
|
end
|
122
151
|
end
|
123
152
|
|
124
|
-
AutoConfig.reload
|
153
|
+
AutoConfig::Base.reload
|
metadata
CHANGED