yaml-config-parser 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
4
+ rdoc/
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