configru 0.0.1

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
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "riot", ">= 0"
5
+ gem "bundler", "~> 1.0.0"
6
+ end
7
+
8
+ # Specify your gem's dependencies in configru.gemspec
9
+ gemspec
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Configru
2
+
3
+ Versatile configuration file loader for Ruby
4
+
5
+ ## Desired Example Usage
6
+
7
+ ```yaml
8
+ server: irc.ninthbit.net
9
+ port: 6667
10
+ nick: awesomeface
11
+ powerlevel: 9
12
+ awesome: omgyes
13
+ ```
14
+
15
+ ```ruby
16
+ require 'configru'
17
+
18
+ Configru.load do
19
+ cascade '~/foo.yml', '/etc/foo.yml' # Set files to look in
20
+ defaults do
21
+ server 'irc.freenode.net'
22
+ port 6667
23
+ nick 'bot'
24
+ powerlevel 1
25
+ awesome 'not at all'
26
+ end
27
+ verify do
28
+ server /\S+/ # Must match regex
29
+ nick /\S+/
30
+ port Fixnum # Must be an instance of
31
+ powerlevel 1..10 # Must be in range
32
+ awesome ['not at all', 'omgyes', 'meh'] # Must be one of
33
+ end
34
+ end
35
+
36
+ puts "Connecting to #{Configru.server}:#{Configru.port}"
37
+ ```
38
+
39
+ ## License
40
+
41
+ Copyright (c) 2011, Curtis McEnroe <programble@gmail.com>
42
+
43
+ Permission to use, copy, modify, and/or distribute this software for any
44
+ purpose with or without fee is hereby granted, provided that the above
45
+ copyright notice and this permission notice appear in all copies.
46
+
47
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
48
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
49
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
50
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
51
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
52
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
53
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ desc "Run all tests"
7
+ task :test do
8
+ Rake::TestTask.new do |t|
9
+ t.libs << "test"
10
+ t.pattern = "test/**/*_test.rb"
11
+ t.verbose = false
12
+ end
13
+ end
14
+
15
+ task :default => :test
data/configru.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "configru/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "configru"
7
+ s.version = Configru::VERSION
8
+ s.authors = ["Curtis McEnroe"]
9
+ s.email = ["programble@gmail.com"]
10
+ s.homepage = "https://github.com/programble/configru"
11
+ s.summary = %q{Versatile configuration file loader}
12
+ s.description = s.summary
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
+ end
@@ -0,0 +1,31 @@
1
+ module Configru
2
+ class ConfigHash < Hash
3
+ def initialize(hash={})
4
+ super
5
+ merge!(hash)
6
+ end
7
+
8
+ def merge!(hash)
9
+ hash.each do |key, value|
10
+ if value.is_a?(Hash) && self[key].is_a?(ConfigHash)
11
+ self[key].merge!(value)
12
+ elsif value.is_a?(Hash)
13
+ self[key] = ConfigHash.new(value)
14
+ else
15
+ self[key] = value
16
+ end
17
+ end
18
+ end
19
+
20
+ def [](key)
21
+ key = key.to_s if key.is_a?(Symbol)
22
+ # For some reason, super(key) returns {} instead of nil when the key
23
+ # doesn't exist :\
24
+ super(key) if self.include?(key)
25
+ end
26
+
27
+ def method_missing(key, *args)
28
+ self[key]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ module Configru
2
+ module DSL
3
+ class LoadDSL
4
+ attr_reader :defaults_hash, :verify_hash, :files_array, :load_method
5
+
6
+ def initialize(block)
7
+ @defaults_hash = {}
8
+ @verify_hash = {}
9
+ @files_array = []
10
+ @load_method = :first
11
+ instance_eval(&block)
12
+ end
13
+
14
+ def first_of(*args)
15
+ @load_method = :first
16
+ @files_array = args
17
+ end
18
+
19
+ def cascade(*args)
20
+ @load_method = :cascade
21
+ @files_array = args
22
+ end
23
+
24
+ def defaults(hash=nil, &block)
25
+ if hash
26
+ @defaults_hash = hash
27
+ elsif block
28
+ @defaults_hash = HashDSL.new(block).hash
29
+ end
30
+ end
31
+
32
+ def verify(hash=nil, &block)
33
+ if hash
34
+ @verify_hash = hash
35
+ elsif block
36
+ @verify_hash = HashDSL.new(block).hash
37
+ end
38
+ end
39
+ end
40
+
41
+ class HashDSL
42
+ attr_reader :hash
43
+
44
+ def initialize(block)
45
+ @hash = {}
46
+ instance_eval(&block)
47
+ end
48
+
49
+ def method_missing(method, *args, &block)
50
+ key = method.to_s
51
+ if block
52
+ @hash[key] = HashDSL.new(block).hash
53
+ else
54
+ @hash[key] = args[0]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Configru
2
+ VERSION = "0.0.1"
3
+ end
data/lib/configru.rb ADDED
@@ -0,0 +1,77 @@
1
+ $: << File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
2
+
3
+ require 'configru/confighash'
4
+ require 'configru/dsl'
5
+
6
+ require 'yaml'
7
+
8
+ module Configru
9
+ class ConfigurationError < RuntimeError; end
10
+
11
+ def self.load(load_method=:first, files=[], defaults={}, verify={}, &block)
12
+ if block
13
+ dsl = DSL::LoadDSL.new(block)
14
+ @load_method = dsl.load_method
15
+ @files = dsl.files_array.map {|x| File.expand_path(x)}
16
+ @defaults = dsl.defaults_hash
17
+ @verify = dsl.verify_hash
18
+ else
19
+ @load_method = load_method
20
+ @files = files
21
+ @defaults = defaults
22
+ @verify = verify
23
+ end
24
+ self.reload
25
+ end
26
+
27
+ def self.reload
28
+ @config = ConfigHash.new(@defaults)
29
+
30
+ case @load_method
31
+ when :first
32
+ if file = @files.find {|file| File.file?(file)} # Intended
33
+ @config.merge!(YAML.load_file(file) || {})
34
+ end
35
+ when :cascade
36
+ @files.reverse_each do |file|
37
+ @config.merge!(YAML.load_file(file) || {}) if File.file?(file)
38
+ end
39
+ end
40
+
41
+ self.verify(@config, @verify)
42
+ end
43
+
44
+ @verify_stack = []
45
+ def self.verify(hash, criteria)
46
+ hash.each do |key, value|
47
+ next unless criteria[key]
48
+ @verify_stack.unshift(key)
49
+
50
+ result = case criteria[key]
51
+ when Hash
52
+ self.verify(value, criteria[key])
53
+ true
54
+ when Class
55
+ value.is_a?(criteria[key])
56
+ when Array
57
+ criteria[key].include?(value)
58
+ else
59
+ criteria[key] === value
60
+ end
61
+
62
+ raise ConfigurationError, "configuration option '#{@verify_stack.reverse.join('.')}' is invalid" unless result
63
+
64
+ @verify_stack.shift
65
+ end
66
+ end
67
+
68
+ def self.[](key)
69
+ @config[key]
70
+ end
71
+
72
+ def self.method_missing(key, *args)
73
+ # Simulate NoMethodError if it looks like they really wanted a method
74
+ raise NoMethodError, "undefined method `#{key.to_s}' for #{self.inspect}:#{self.class}" unless args.empty?
75
+ self[key]
76
+ end
77
+ end
@@ -0,0 +1,53 @@
1
+ require 'teststrap'
2
+
3
+ context 'ConfigHash - ' do
4
+ setup { Configru::ConfigHash.new }
5
+
6
+ context 'empty' do
7
+ asserts('[:quux]') { topic[:quux] }.nil
8
+ asserts(:quux).nil
9
+ end
10
+
11
+ context 'non-empty' do
12
+ hookup do
13
+ topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
14
+ end
15
+
16
+ # Testing access methods
17
+ asserts("['foo']") { topic['foo'] }.equals(1)
18
+ asserts('[:foo]') { topic[:foo] }.equals(1)
19
+ asserts(:foo).equals(1)
20
+ end
21
+
22
+ context 'overwriting a value by merge' do
23
+ hookup do
24
+ topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
25
+ topic.merge!({'bar' => 4})
26
+ end
27
+ asserts(:bar).equals(4)
28
+ end
29
+
30
+ context 'merging a nested Hash' do
31
+ hookup do
32
+ topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
33
+ topic.merge!({'bar' => 4})
34
+ topic.merge!({'baz' => {'quux' => 5}})
35
+ end
36
+
37
+ asserts(:baz).kind_of(Configru::ConfigHash)
38
+ asserts('baz.quux') { topic.baz.quux }.equals(5)
39
+ end
40
+
41
+ context 'recursively merging a nested Hash' do
42
+ hookup do
43
+ topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
44
+ topic.merge!({'bar' => 4})
45
+ topic.merge!({'baz' => {'quux' => 5}})
46
+ topic.merge!({'baz' => {'apple' => 6}})
47
+ end
48
+
49
+ asserts(:baz).kind_of(Configru::ConfigHash)
50
+ asserts('baz.apple') { topic.baz.apple }.equals(6)
51
+ asserts('baz.quux') { topic.baz.quux }.equals(5)
52
+ end
53
+ end
data/test/teststrap.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+ require 'riot'
10
+ require 'configru'
11
+
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: configru
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Curtis McEnroe
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-07-14 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Versatile configuration file loader
22
+ email:
23
+ - programble@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - README.md
34
+ - Rakefile
35
+ - configru.gemspec
36
+ - lib/configru.rb
37
+ - lib/configru/confighash.rb
38
+ - lib/configru/dsl.rb
39
+ - lib/configru/version.rb
40
+ - test/confighash_test.rb
41
+ - test/teststrap.rb
42
+ has_rdoc: true
43
+ homepage: https://github.com/programble/configru
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.7
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Versatile configuration file loader
74
+ test_files:
75
+ - test/confighash_test.rb
76
+ - test/teststrap.rb