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 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