autoconfig 0.1.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +47 -2
- data/lib/autoconfig.rb +97 -39
- metadata +7 -6
data/README.markdown
CHANGED
@@ -17,7 +17,7 @@ Autoconfig in an automated way to create flexible configuration structures repre
|
|
17
17
|
1. require 'autoconfig'
|
18
18
|
2. profit!
|
19
19
|
|
20
|
-
## Example
|
20
|
+
## Basic Example
|
21
21
|
|
22
22
|
Lets say you have application.yml in your config folder:
|
23
23
|
|
@@ -33,8 +33,53 @@ Lets say you have application.yml in your config folder:
|
|
33
33
|
After requiring 'autoconfig' you should expect ApplicationConfig structure that will contain all the information. In production environment
|
34
34
|
ApplicationConfig.web.hostname call will return "the.production.com".
|
35
35
|
|
36
|
+
## Advance Example
|
37
|
+
|
38
|
+
Check it out under test/config/one
|
39
|
+
|
40
|
+
defaults:
|
41
|
+
one: !REQUIRED
|
42
|
+
two: two
|
43
|
+
three: three
|
44
|
+
cache_classes: true
|
45
|
+
tree1:
|
46
|
+
tree2: hey
|
47
|
+
tree3:
|
48
|
+
tree4: blah
|
49
|
+
|
50
|
+
defaults[test,cucumber,development]:
|
51
|
+
cache_classes: false
|
52
|
+
|
53
|
+
defaults[test,cucumber]:
|
54
|
+
one: one
|
55
|
+
|
56
|
+
development:
|
57
|
+
one: yup
|
58
|
+
|
59
|
+
test:
|
60
|
+
something: hello
|
61
|
+
tree1:
|
62
|
+
tree3:
|
63
|
+
tree4: bleh
|
64
|
+
|
65
|
+
production:
|
66
|
+
three: five
|
67
|
+
|
68
|
+
Autoconfig can support:
|
69
|
+
* specifying which keys are required via !REQUIRED yaml type
|
70
|
+
* environment specific defaults shared across some environments
|
71
|
+
* deep nested structures
|
72
|
+
|
36
73
|
## Configuration
|
37
74
|
|
38
75
|
By default, it will look at config directory of your project and transfer most of your .yml files (it ignores database ones). However,
|
39
|
-
you have full control over where it needs to look and what it needs to convert.
|
76
|
+
you have full control over where it needs to look and what it needs to convert. Here is a set of environment flags you could use:
|
40
77
|
|
78
|
+
* `AUTOCONFIG_ROOT` - allows setting of the application root. By default it will try to use APP_ROOT, rails root (if rails app) or pwd directory.
|
79
|
+
* `AUTOCONFIG_PATERN` - used to construct a path to your configuration files. By default it is set to config/*.yml
|
80
|
+
* `AUTOCONFIG_PATH` - allows setting a path to your configuration files. If set autoconfig will ignore patern and root, otherwise
|
81
|
+
it look at root and patern to get path to your files.
|
82
|
+
* `AUTOCONFIG_ENV` - allows setting environment in which autoconfig runs, by default it will try to use APP_ENV, Rails.env(if rails app) or
|
83
|
+
development (in that order)
|
84
|
+
* `AUTOCONFIG_IGNORE` - when set it will not create configs for files in the ignore. When not set it will just ignore database.yml. Takes a whitespace
|
85
|
+
separated list. Ex: 'cucumber cache'
|
data/lib/autoconfig.rb
CHANGED
@@ -1,66 +1,124 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
require 'yaml'
|
3
|
+
require 'erb'
|
4
|
+
require 'set'
|
3
5
|
|
4
6
|
module StringCamelize
|
5
7
|
# Taken straight from active support inflector.rb, line 161
|
6
8
|
def camelize(first_letter_in_uppercase = true)
|
7
9
|
if first_letter_in_uppercase
|
8
|
-
|
10
|
+
to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
9
11
|
else
|
10
|
-
|
12
|
+
first + camelize(self)[1..-1]
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
String.send(:include, StringCamelize) unless String.instance_methods.include?("camelize")
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
ENV['AUTOCONFIG_ROOT'] || ENV['APP_ROOT'] || rails_root || base_dir
|
20
|
-
end
|
18
|
+
class AutoConfig
|
19
|
+
REQUIRED = :REQUIRED
|
20
|
+
YAML.add_builtin_type( 'REQUIRED' ){ REQUIRED }
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
class << self
|
23
|
+
def root
|
24
|
+
rails_root = (rails? && (Rails.root || File.expand_path('../', ENV['BUNDLE_GEMFILE'])))
|
25
|
+
ENV['AUTOCONFIG_ROOT'] || ENV['APP_ROOT'] || rails_root || Dir.pwd
|
26
|
+
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
def pattern
|
29
|
+
ENV['AUTOCONFIG_PATTERN'] || 'config/*.yml'
|
30
|
+
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
def path
|
33
|
+
ENV['AUTOCONFIG_PATH'] || File.expand_path(pattern, root)
|
34
|
+
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
def environment
|
37
|
+
ENV['AUTOCONFIG_ENV'] || ENV['APP_ENV'] || (rails? && Rails.env) || 'development'
|
38
|
+
end
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
def rails?
|
41
|
+
Object::const_defined? "Rails"
|
42
|
+
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
def ignored_filenames
|
45
|
+
names = ENV['AUTOCONFIG_IGNORE'] ? "database|" + ENV['AUTOCONFIG_IGNORE'].gsub(/\s/,'|') : 'database'
|
46
|
+
Regexp.new(names)
|
47
|
+
end
|
48
|
+
|
49
|
+
def reload
|
50
|
+
wipe
|
51
|
+
files = Dir.glob(path)
|
52
|
+
begin
|
53
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
54
|
+
|
55
|
+
files.each do |file|
|
56
|
+
name = File.basename(file, '.yml')
|
57
|
+
next if name.match(ignored_filenames)
|
46
58
|
|
47
|
-
|
59
|
+
constant_name = "#{name}Config".gsub('-','_').camelize
|
60
|
+
yaml_config = YAML::load(ERB.new(IO.read(file)).result)
|
48
61
|
|
49
|
-
|
50
|
-
|
62
|
+
@ordered_stanza_labels[constant_name] = []
|
63
|
+
@ordered_stanza_labels[constant_name] << 'defaults' if yaml_config.key? 'defaults'
|
64
|
+
@ordered_stanza_labels[constant_name] += yaml_config.keys.grep(/^defaults\[.*#{environment}/).sort_by{ |a| a.count(',') }
|
65
|
+
@ordered_stanza_labels[constant_name] << environment if yaml_config.key? environment
|
51
66
|
|
52
|
-
|
53
|
-
|
54
|
-
|
67
|
+
config = @ordered_stanza_labels[constant_name].inject({}) do |acc, label|
|
68
|
+
deep_merge(acc,yaml_config[label])
|
69
|
+
end
|
55
70
|
|
56
|
-
|
57
|
-
app_config = config['common'] || {}
|
58
|
-
app_config.update(config['defaults'] || {})
|
59
|
-
app_config.update(config[environment] || {})
|
71
|
+
ensure_requirements_met_and_ostructify!(config, constant_name )
|
60
72
|
|
61
|
-
|
73
|
+
Object::const_set(constant_name.intern, OpenStruct.new(config))
|
74
|
+
end
|
75
|
+
|
76
|
+
raise @errors.to_a.join( "\n" ) unless @errors.empty?
|
77
|
+
|
78
|
+
ensure
|
79
|
+
$VERBOSE = old_verbose
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
# unsets created constants
|
85
|
+
def wipe
|
86
|
+
unless @ordered_stanza_labels.nil?
|
87
|
+
@ordered_stanza_labels.keys.each{|const| Object::const_set(const.intern, nil) }
|
88
|
+
end
|
89
|
+
@ordered_stanza_labels = {}
|
90
|
+
@errors = Set.new
|
91
|
+
end
|
92
|
+
|
93
|
+
# merges two hashes with nested hashes if present
|
94
|
+
def deep_merge( hash1, hash2 )
|
95
|
+
hash1 = hash1.dup
|
96
|
+
( hash1.keys + hash2.keys ).each do | key |
|
97
|
+
if hash1.key?( key ) && hash2.key?( key ) &&
|
98
|
+
hash1[key].is_a?( Hash ) && hash2[key].is_a?( Hash )
|
99
|
+
hash1[key] = deep_merge( hash1[key], hash2[key] )
|
100
|
+
elsif hash2.key?( key )
|
101
|
+
hash1[key] = hash2[key]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
hash1
|
105
|
+
end
|
106
|
+
# Mutator method that does two things:
|
107
|
+
# * checks if any of the keys were required and not set. Upon finding
|
108
|
+
# it adds key to the error set
|
109
|
+
# * recursively sets open structs for deep hashes
|
110
|
+
def ensure_requirements_met_and_ostructify!( hash, path )
|
111
|
+
hash.each do | key, value |
|
112
|
+
case
|
113
|
+
when value.respond_to?( :keys ) && value.respond_to?( :values )
|
114
|
+
ensure_requirements_met_and_ostructify!( value, path + '.' + key )
|
115
|
+
when value == REQUIRED
|
116
|
+
@errors << "#{path}.#{key} is REQUIRED"
|
117
|
+
end
|
118
|
+
hash[key] = OpenStruct.new(value) if value.is_a?( Hash )
|
119
|
+
end
|
62
120
|
end
|
63
|
-
ensure
|
64
|
-
$VERBOSE = old_verbose
|
65
121
|
end
|
66
122
|
end
|
123
|
+
|
124
|
+
AutoConfig.reload
|
metadata
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autoconfig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
-
|
10
|
-
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- tjbladez
|
14
|
+
- timgaleckas
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2011-
|
19
|
+
date: 2011-10-12 00:00:00 -05:00
|
19
20
|
default_executable:
|
20
21
|
dependencies: []
|
21
22
|
|
22
23
|
description: Automated way to create flexible configuration structures representing your YAML configuration
|
23
|
-
email: tjbladez@
|
24
|
+
email: nick@tjbladez.com, tim@galeckas.com
|
24
25
|
executables: []
|
25
26
|
|
26
27
|
extensions: []
|