yaml-config-parser 0.1.3
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/.gitignore +4 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +78 -0
- data/Rakefile +82 -0
- data/lib/yaml-config-parser.rb +84 -0
- data/spec/data/config.db.yml +37 -0
- data/spec/data/config.logging.yml +32 -0
- data/spec/data/config.yml +26 -0
- data/spec/yaml-config-parser_spec.rb +56 -0
- data/yaml-config-parser.gemspec +20 -0
- metadata +78 -0
data/.gitignore
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Mario Fernandez
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# YAML Config Parser
|
2
|
+
|
3
|
+
This gem allows to parse multiple YAML configuration files into one
|
4
|
+
Config object. It attempts to solve two different problems:
|
5
|
+
|
6
|
+
* Having multiple environments types. For example, you might want to
|
7
|
+
parse the config choosing between the common __development__,
|
8
|
+
__test__ and __production__ envs. But sometimes that is not
|
9
|
+
enough. If you want to have different settings for your _local_
|
10
|
+
machine and your _integration_ one, and each of them can run in
|
11
|
+
more than one mode, using just one selector doesn't solve it. For
|
12
|
+
that reason, this gem allows to use a hierarchy, so that you can
|
13
|
+
choose something like _local_ > __development__.
|
14
|
+
|
15
|
+
* For many projects, the configuration settings can get very big, and
|
16
|
+
thus you might want multiple configuration files, with the
|
17
|
+
convenience of having only one object with all the settings,
|
18
|
+
separated in namespaces (like 'db' or 'logging'). This gem uses one
|
19
|
+
main file, where the usual settings are saved, but also other
|
20
|
+
configuration files can be used.
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
The Parser is created by passing a path and a list of environments,
|
25
|
+
like this:
|
26
|
+
|
27
|
+
YAMLConfig::Parser.new(File.expand_path('../config', __FILE__), :env => ['local', 'development'])
|
28
|
+
|
29
|
+
The first argument is a path to a directory. It is expected to contain
|
30
|
+
a main settings file, _config.yml_, and optionally multiple extra
|
31
|
+
settings file, in the form of _config.*.yml_. Valid files would be
|
32
|
+
_config.db.yml_ or _config.logging.yml_.
|
33
|
+
|
34
|
+
The second argument defines the environments used to select the
|
35
|
+
contents of the configuration files. For the given example, each
|
36
|
+
configuration file is expected to contain a _local_ key, which should
|
37
|
+
contain a _development_ key inside it as well.
|
38
|
+
|
39
|
+
The settings of the main file are taken without change. For the extra
|
40
|
+
files, a hash with the name of the file (_logging_ for
|
41
|
+
_config.logging.yml_) is built with all the settings, and this hash is
|
42
|
+
put in the result file.
|
43
|
+
|
44
|
+
## Example
|
45
|
+
|
46
|
+
If the given directory contains a _config.yml_ file like:
|
47
|
+
|
48
|
+
local:
|
49
|
+
development:
|
50
|
+
key1 : true
|
51
|
+
|
52
|
+
test:
|
53
|
+
key1 : false
|
54
|
+
|
55
|
+
integration:
|
56
|
+
production:
|
57
|
+
key2 : 3
|
58
|
+
|
59
|
+
and a _config.logging.yml_ file like:
|
60
|
+
|
61
|
+
local:
|
62
|
+
development:
|
63
|
+
level : DEBUG
|
64
|
+
|
65
|
+
test:
|
66
|
+
level : WARN
|
67
|
+
|
68
|
+
integration:
|
69
|
+
production:
|
70
|
+
active : false
|
71
|
+
|
72
|
+
The result of calling the __load__ method would create an
|
73
|
+
__OpenStruct__ object equivalent to the following hash:
|
74
|
+
|
75
|
+
{
|
76
|
+
'key1' => true,
|
77
|
+
'logging' => { 'level' => 'DEBUG' }
|
78
|
+
}
|
data/Rakefile
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
# Helpers
|
5
|
+
def name
|
6
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
7
|
+
end
|
8
|
+
|
9
|
+
def version
|
10
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
11
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def date
|
15
|
+
Date.today.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def rubyforge_project
|
19
|
+
name
|
20
|
+
end
|
21
|
+
|
22
|
+
def gemspec_file
|
23
|
+
"#{name}.gemspec"
|
24
|
+
end
|
25
|
+
|
26
|
+
def gem_file
|
27
|
+
"#{name}-#{version}.gem"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tasks
|
31
|
+
task :default => :spec
|
32
|
+
|
33
|
+
require 'rspec/core/rake_task'
|
34
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
35
|
+
t.pattern = "spec/**/*_spec.rb"
|
36
|
+
t.verbose = true
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Open an irb session preloaded with this library"
|
40
|
+
task :console do
|
41
|
+
sh "irb -rubygems -r ./lib/#{name}.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'rdoc/task'
|
45
|
+
RDoc::Task.new do |rdoc|
|
46
|
+
rdoc.main = "README.markdown"
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "#{name} #{version}"
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
51
|
+
|
52
|
+
# Packaging
|
53
|
+
|
54
|
+
task :release => :build do
|
55
|
+
unless `git branch` =~ /^\* master$/
|
56
|
+
puts "You must be on the master branch to release!"
|
57
|
+
exit!
|
58
|
+
end
|
59
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
60
|
+
sh "git tag v#{version}"
|
61
|
+
sh "git push origin master"
|
62
|
+
sh "git push origin v#{version}"
|
63
|
+
sh "gem push pkg/#{gem_file}"
|
64
|
+
end
|
65
|
+
|
66
|
+
task :build => :validate do
|
67
|
+
sh "mkdir -p pkg"
|
68
|
+
sh "gem build #{gemspec_file}"
|
69
|
+
sh "mv #{gem_file} pkg"
|
70
|
+
end
|
71
|
+
|
72
|
+
task :validate do
|
73
|
+
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
74
|
+
unless libfiles.empty?
|
75
|
+
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
76
|
+
exit!
|
77
|
+
end
|
78
|
+
unless Dir['VERSION*'].empty?
|
79
|
+
puts "A `VERSION` file at root level violates Gem best practices."
|
80
|
+
exit!
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module YAMLConfig
|
5
|
+
VERSION = '0.1.3'
|
6
|
+
|
7
|
+
class Parser
|
8
|
+
|
9
|
+
attr_reader :environment
|
10
|
+
attr_accessor :path, :main, :extra
|
11
|
+
|
12
|
+
# Instantiate a new configuration parser.
|
13
|
+
#
|
14
|
+
# path - The directory where the configuration files are stored
|
15
|
+
# :env - (optional) The list of environments used to choose the
|
16
|
+
# right keys. If there is only one environment it can be passed as
|
17
|
+
# a String. Default is 'development'
|
18
|
+
def initialize(path, args = {})
|
19
|
+
@path = path
|
20
|
+
# TODO: make main and extra files configurable
|
21
|
+
@main = 'config.yml'
|
22
|
+
@extra = 'config.*.yml'
|
23
|
+
self.environment = args[:env] || 'development'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Loads all the config files that can be found under the
|
27
|
+
# given path, chooses the right environments, and merges them
|
28
|
+
# into a new OpenStruct object
|
29
|
+
#
|
30
|
+
# Returns an OpenStruct with the configuration keys
|
31
|
+
def load
|
32
|
+
OpenStruct.new merge_config_files
|
33
|
+
end
|
34
|
+
|
35
|
+
def environment=(env)
|
36
|
+
if env.class == String
|
37
|
+
env = [env]
|
38
|
+
end
|
39
|
+
@environment = env
|
40
|
+
end
|
41
|
+
|
42
|
+
# Gets the path for all the configuration files. The main file is
|
43
|
+
# put first
|
44
|
+
#
|
45
|
+
# Returns an Array of Strings, each one being a path to a
|
46
|
+
# configuration file.
|
47
|
+
def find_config_files
|
48
|
+
main = File.join(@path, @main)
|
49
|
+
raise ArgumentError.new("Main config file #{main} does not exist") unless File.exists? main
|
50
|
+
extra = Dir.glob(File.join(@path, @extra))
|
51
|
+
([main] + extra).uniq
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def file_to_hash file_name
|
57
|
+
h = YAML.load_file file_name
|
58
|
+
@environment.each do |env|
|
59
|
+
h = h[env]
|
60
|
+
raise ArgumentError.new("Environment #{env} does not exist in the file. Are you sure the order of the environments is correct?") if h.nil?
|
61
|
+
end
|
62
|
+
h
|
63
|
+
end
|
64
|
+
|
65
|
+
def choose_key_for_extra_file file_name
|
66
|
+
file_name.gsub(/.yml$/, '').split('.')[-1]
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_to_hash(hash, key, extra)
|
70
|
+
hash.merge!({key => extra}) do |key,_,_|
|
71
|
+
raise ArgumentError.new("The key #{key} is duplicated")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def merge_config_files
|
76
|
+
files = find_config_files
|
77
|
+
h = file_to_hash(files.shift)
|
78
|
+
files.each do |file_name|
|
79
|
+
add_to_hash(h, choose_key_for_extra_file(file_name), file_to_hash(file_name))
|
80
|
+
end
|
81
|
+
h
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
database: db
|
3
|
+
port: 27017
|
4
|
+
|
5
|
+
local:
|
6
|
+
defaults: &local_defaults
|
7
|
+
<<: *defaults
|
8
|
+
|
9
|
+
host: localhost
|
10
|
+
|
11
|
+
development:
|
12
|
+
<<: *local_defaults
|
13
|
+
|
14
|
+
test:
|
15
|
+
<<: *local_defaults
|
16
|
+
|
17
|
+
database: db_test
|
18
|
+
|
19
|
+
integration:
|
20
|
+
defaults: &integration_defaults
|
21
|
+
<<: *defaults
|
22
|
+
|
23
|
+
host: integration.host.com
|
24
|
+
|
25
|
+
test:
|
26
|
+
<<: *integration_defaults
|
27
|
+
|
28
|
+
database: db_test
|
29
|
+
|
30
|
+
production:
|
31
|
+
<<: *integration_defaults
|
32
|
+
|
33
|
+
live:
|
34
|
+
production:
|
35
|
+
<<: *defaults
|
36
|
+
|
37
|
+
host: host.com
|
@@ -0,0 +1,32 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
is_global: true
|
3
|
+
|
4
|
+
local:
|
5
|
+
defaults: &local_defaults
|
6
|
+
<<: *defaults
|
7
|
+
|
8
|
+
level: DEBUG
|
9
|
+
|
10
|
+
development:
|
11
|
+
<<: *local_defaults
|
12
|
+
|
13
|
+
test:
|
14
|
+
<<: *local_defaults
|
15
|
+
|
16
|
+
integration:
|
17
|
+
defaults: &integration_defaults
|
18
|
+
<<: *defaults
|
19
|
+
|
20
|
+
level: WARN
|
21
|
+
|
22
|
+
test:
|
23
|
+
<<: *integration_defaults
|
24
|
+
|
25
|
+
production:
|
26
|
+
<<: *integration_defaults
|
27
|
+
|
28
|
+
live:
|
29
|
+
production:
|
30
|
+
<<: *defaults
|
31
|
+
|
32
|
+
level: INFO
|
@@ -0,0 +1,26 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
is_global: true
|
3
|
+
|
4
|
+
local:
|
5
|
+
defaults: &local_defaults
|
6
|
+
<<: *defaults
|
7
|
+
|
8
|
+
development:
|
9
|
+
<<: *local_defaults
|
10
|
+
|
11
|
+
test:
|
12
|
+
<<: *local_defaults
|
13
|
+
|
14
|
+
integration:
|
15
|
+
defaults: &integration_defaults
|
16
|
+
<<: *defaults
|
17
|
+
|
18
|
+
test:
|
19
|
+
<<: *integration_defaults
|
20
|
+
|
21
|
+
production:
|
22
|
+
<<: *integration_defaults
|
23
|
+
|
24
|
+
live:
|
25
|
+
production:
|
26
|
+
<<: *defaults
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'yaml-config-parser'
|
2
|
+
|
3
|
+
|
4
|
+
describe YAMLConfig do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@parser = YAMLConfig::Parser.new(File.expand_path('../data', __FILE__), :env => ['local', 'development'])
|
8
|
+
@files = @parser.find_config_files
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return an OpenStruct object' do
|
12
|
+
@parser.load.should be_a_kind_of OpenStruct
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should find the files to parse' do
|
16
|
+
@parser.find_config_files.count.should == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should fail if the main configuration file does not exist' do
|
20
|
+
@parser.main = 'doesnt_exist'
|
21
|
+
lambda { @parser.find_config_files }.should raise_error ArgumentError
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should put the main file first' do
|
25
|
+
@parser.find_config_files.first.should satisfy {|f| f.include? 'config.yml' }
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should be able to deal with a single environment' do
|
29
|
+
@parser.environment = 'local'
|
30
|
+
@parser.environment.should == ['local']
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should convert a yml to a hash, using the environments to choose the part of the yml to take' do
|
34
|
+
@parser.send(:file_to_hash, @files.first).should == {"is_global"=>true}
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should fail when trying to use an environment that is not present in the yml file' do
|
38
|
+
@parser.environment = 'NO'
|
39
|
+
lambda { @parser.send(:file_to_hash, @files.first)}.should raise_error ArgumentError
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should fail when trying to use the same key twice for the hash' do
|
43
|
+
lambda { @parser.send(:add_to_hash, { 'a' => 1}, 'a', {})}.should raise_error ArgumentError
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should merge all configuration files to one hash' do
|
47
|
+
@parser.send(:merge_config_files).keys.should == ['is_global', 'db', 'logging']
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should produce a valid OpenStruct object with all the data from the config files' do
|
51
|
+
cfg = @parser.load
|
52
|
+
cfg.is_global.should == true
|
53
|
+
cfg.db.should == {"database"=>"db", "port"=>27017, "host"=>"localhost"}
|
54
|
+
cfg.logging.should == {"is_global"=>true, "level"=>"DEBUG"}
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'yaml-config-parser'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'yaml-config-parser'
|
7
|
+
s.version = YAMLConfig::VERSION
|
8
|
+
s.authors = ['Mario Fernandez']
|
9
|
+
|
10
|
+
s.homepage = 'http://github.com/sirech/parse-yaml-config'
|
11
|
+
s.summary = 'Load settings in one or multiple yaml config files'
|
12
|
+
s.description = 'Parse a number of yaml config files, building one config object. Multiple keys can be specified to choose which part of the file to load'
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_development_dependency('rspec')
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yaml-config-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.3
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mario Fernandez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-10-09 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
description: Parse a number of yaml config files, building one config object. Multiple keys can be specified to choose which part of the file to load
|
28
|
+
email:
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE.txt
|
38
|
+
- README.markdown
|
39
|
+
- Rakefile
|
40
|
+
- lib/yaml-config-parser.rb
|
41
|
+
- spec/data/config.db.yml
|
42
|
+
- spec/data/config.logging.yml
|
43
|
+
- spec/data/config.yml
|
44
|
+
- spec/yaml-config-parser_spec.rb
|
45
|
+
- yaml-config-parser.gemspec
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/sirech/parse-yaml-config
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.6.2
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Load settings in one or multiple yaml config files
|
74
|
+
test_files:
|
75
|
+
- spec/data/config.db.yml
|
76
|
+
- spec/data/config.logging.yml
|
77
|
+
- spec/data/config.yml
|
78
|
+
- spec/yaml-config-parser_spec.rb
|