autoconfig 0.1.2 → 1.0.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/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: []
|