configoro 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -fs --color
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '>= 3.0'
4
+ #gem 'activesupport', '>= 3.0'
5
+
6
+ group :development do
7
+ # SPECS
8
+ gem 'rspec'
9
+
10
+ # DOCS
11
+ gem 'yard'
12
+ gem 'RedCloth'
13
+
14
+ # LIBRARIES
15
+ gem 'bundler'
16
+ gem 'jeweler'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,92 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ RedCloth (4.2.7)
5
+ abstract (1.0.0)
6
+ actionmailer (3.0.7)
7
+ actionpack (= 3.0.7)
8
+ mail (~> 2.2.15)
9
+ actionpack (3.0.7)
10
+ activemodel (= 3.0.7)
11
+ activesupport (= 3.0.7)
12
+ builder (~> 2.1.2)
13
+ erubis (~> 2.6.6)
14
+ i18n (~> 0.5.0)
15
+ rack (~> 1.2.1)
16
+ rack-mount (~> 0.6.14)
17
+ rack-test (~> 0.5.7)
18
+ tzinfo (~> 0.3.23)
19
+ activemodel (3.0.7)
20
+ activesupport (= 3.0.7)
21
+ builder (~> 2.1.2)
22
+ i18n (~> 0.5.0)
23
+ activerecord (3.0.7)
24
+ activemodel (= 3.0.7)
25
+ activesupport (= 3.0.7)
26
+ arel (~> 2.0.2)
27
+ tzinfo (~> 0.3.23)
28
+ activeresource (3.0.7)
29
+ activemodel (= 3.0.7)
30
+ activesupport (= 3.0.7)
31
+ activesupport (3.0.7)
32
+ arel (2.0.9)
33
+ builder (2.1.2)
34
+ diff-lcs (1.1.2)
35
+ erubis (2.6.6)
36
+ abstract (>= 1.0.0)
37
+ git (1.2.5)
38
+ i18n (0.5.0)
39
+ jeweler (1.6.0)
40
+ bundler (~> 1.0.0)
41
+ git (>= 1.2.5)
42
+ rake
43
+ mail (2.2.19)
44
+ activesupport (>= 2.3.6)
45
+ i18n (>= 0.4.0)
46
+ mime-types (~> 1.16)
47
+ treetop (~> 1.4.8)
48
+ mime-types (1.16)
49
+ polyglot (0.3.1)
50
+ rack (1.2.2)
51
+ rack-mount (0.6.14)
52
+ rack (>= 1.0.0)
53
+ rack-test (0.5.7)
54
+ rack (>= 1.0)
55
+ rails (3.0.7)
56
+ actionmailer (= 3.0.7)
57
+ actionpack (= 3.0.7)
58
+ activerecord (= 3.0.7)
59
+ activeresource (= 3.0.7)
60
+ activesupport (= 3.0.7)
61
+ bundler (~> 1.0)
62
+ railties (= 3.0.7)
63
+ railties (3.0.7)
64
+ actionpack (= 3.0.7)
65
+ activesupport (= 3.0.7)
66
+ rake (>= 0.8.7)
67
+ thor (~> 0.14.4)
68
+ rake (0.8.7)
69
+ rspec (2.5.0)
70
+ rspec-core (~> 2.5.0)
71
+ rspec-expectations (~> 2.5.0)
72
+ rspec-mocks (~> 2.5.0)
73
+ rspec-core (2.5.2)
74
+ rspec-expectations (2.5.0)
75
+ diff-lcs (~> 1.1.2)
76
+ rspec-mocks (2.5.0)
77
+ thor (0.14.6)
78
+ treetop (1.4.9)
79
+ polyglot (>= 0.3.1)
80
+ tzinfo (0.3.27)
81
+ yard (0.6.8)
82
+
83
+ PLATFORMS
84
+ ruby
85
+
86
+ DEPENDENCIES
87
+ RedCloth
88
+ bundler
89
+ jeweler
90
+ rails (>= 3.0)
91
+ rspec
92
+ yard
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tim Morgan
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.textile ADDED
@@ -0,0 +1,96 @@
1
+ h1. Configoro -- Environment-specific configuration data for Rails apps
2
+
3
+ | *Author* | Tim Morgan |
4
+ | *Version* | 1.0 (May 5, 2011) |
5
+ | *License* | Released under the MIT license. |
6
+
7
+ h2. About
8
+
9
+ Pretty much every Rails app out there needs to store environment-specific
10
+ configuration data: API URLs, Memcache settings, AWS keys, etc. The "quick fix"
11
+ approach is usually to dump this information in, e.g., @development.rb@ as
12
+ constants, like @MAILCHIMP_API_URL@. This creates cluttered and unorganized
13
+ environment files.
14
+
15
+ Configoro creates a configuration object that can be accessed as both a hash and
16
+ struct. It stores common configuration data merged with environment-specific
17
+ data.
18
+
19
+ The data is read from YAML files stored alongside the environment files.
20
+
21
+ h2. Installation
22
+
23
+ To use this gem, simply add
24
+
25
+ <pre><code>
26
+ gem 'configoro'
27
+ </code></pre>
28
+
29
+ to your Gemfile, then run
30
+
31
+ <pre><code>
32
+ rails generate configoro
33
+ </code></pre>
34
+
35
+ to install some default configuration files. Edit these new files with your
36
+ configuration data.
37
+
38
+ h2. Usage
39
+
40
+ Assume your application namespace is @MyApp@ (which is what it
41
+ would be if you had created your Rails project using @rails new my_app@). You
42
+ can find your namespace in your @config/application.rb@ file.
43
+
44
+ In this case, you would access your configuration using the
45
+ @MyApp::Configuration@ object. You can access it as an indifferent hash
46
+
47
+ <pre><code>
48
+ MyApp::Configuration[:mailchimp_api_url]
49
+ MyApp::Configuration['mailchimp_api_url']
50
+ </code></pre>
51
+
52
+ or as a struct.
53
+
54
+ <pre><code>
55
+ MyApp::Configuration.mailchimp_api_url
56
+ </code></pre>
57
+
58
+ If you include any hashes in your configuration YAML files, they will also be
59
+ accessible as indifferent hashes or structs:
60
+
61
+ <pre><code>
62
+ MyApp::Configuration.memcache.timeout
63
+ MyApp::Configuration[:memcache]['timeout']
64
+ MyApp::Configuration['memcache'].timeout
65
+ </code></pre>
66
+
67
+ h2. Configuration Files
68
+
69
+ Configuration is stored within the @config/environments@ directory of your Rails
70
+ app. Files ending in ".yml" are loaded from the @common/@ subdirectory and a
71
+ subdirectory named after the current environment.
72
+
73
+ Each file goes into its own hash in the configuration. For example, if you
74
+ placed a file called @memcache.yml@ within @config/environments/development@,
75
+ you would be able to access your Memcache timeout using
76
+ @MyApp::Configuration.memcache.timeout@.
77
+
78
+ h3. Custom Configuration Locations
79
+
80
+ If you need to do your own configuration loading, you can do so using the
81
+ {Configoro::Hash#<<} method. For example, you could place the following in a
82
+ Ruby file under @config/initializers@:
83
+
84
+ <pre><code>
85
+ MyApp::Configuration << "path/to/additional/yaml_file.yml"
86
+ MyApp::Configuration << { 'additional' => 'configuration' }
87
+
88
+ MyApp::Configuration.additional #=> 'configuration'
89
+ </code></pre>
90
+
91
+ Note that if you pass a path to a YAML file, a key will be created to store the
92
+ contents of the file, named after the file name. If the key already exists, the
93
+ new values will be deep-merged into the existing values.
94
+
95
+ In the example above, the data in the @yaml_file.yml@ file can be accessed using
96
+ @MyApp::Configuration.yaml_file@.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ #################################### BUNDLER ###################################
6
+
7
+ require 'bundler'
8
+ begin
9
+ Bundler.setup(:default, :development)
10
+ rescue Bundler::BundlerError => e
11
+ $stderr.puts e.message
12
+ $stderr.puts "Run `bundle install` to install missing gems"
13
+ exit e.status_code
14
+ end
15
+ require 'rake'
16
+
17
+ #################################### JEWELER ###################################
18
+
19
+ require 'jeweler'
20
+ Jeweler::Tasks.new do |gem|
21
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
22
+ gem.name = "configoro"
23
+ gem.homepage = "http://github.com/RISCfuture/configoro"
24
+ gem.license = "MIT"
25
+ gem.summary = %Q{Configuration object and YAML-based storage for Rails apps}
26
+ gem.description = %Q{Creates a YourApp::Configuration object whose methods are generated from environment-specific YAML files.}
27
+ gem.email = "git@timothymorgan.info"
28
+ gem.authors = [ "Tim Morgan" ]
29
+ # dependencies defined in Gemfile
30
+ end
31
+ Jeweler::RubygemsDotOrgTasks.new
32
+
33
+ ##################################### RSPEC ####################################
34
+
35
+ require 'rspec/core'
36
+ require 'rspec/core/rake_task'
37
+ RSpec::Core::RakeTask.new(:spec) do |spec|
38
+ spec.pattern = FileList['spec/**/*_spec.rb']
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ ##################################### YARD #####################################
44
+
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new do |doc|
47
+ doc.options << "-m" << "textile"
48
+ doc.options << "--protected"
49
+ doc.options << "--no-private"
50
+ doc.options << "-r" << "README.textile"
51
+ doc.options << "-o" << "doc"
52
+ doc.options << "--title" << "Configoro Documentation"
53
+
54
+ doc.files = [ 'lib/**/*', 'README.textile' ]
55
+ end
56
+
57
+ desc "Generate API documentation"
58
+ task :doc => :yard
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/configoro.gemspec ADDED
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{configoro}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tim Morgan"]
12
+ s.date = %q{2011-05-05}
13
+ s.description = %q{Creates a YourApp::Configuration object whose methods are generated from environment-specific YAML files.}
14
+ s.email = %q{git@timothymorgan.info}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.textile",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "configoro.gemspec",
29
+ "generators/configoro_generator.rb",
30
+ "lib/configoro.rb",
31
+ "lib/configoro/base.rb",
32
+ "lib/configoro/hash.rb",
33
+ "lib/configoro/railtie.rb",
34
+ "spec/configoro/hash_spec.rb",
35
+ "spec/configoro_spec.rb",
36
+ "spec/data/config/environments/common/basic.yml",
37
+ "spec/data/config/environments/common/hash_test.yml",
38
+ "spec/data/config/environments/development/basic.yml",
39
+ "spec/data/config/environments/development/hash_test.yml",
40
+ "spec/data/config/environments/production/basic.yml",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/RISCfuture/configoro}
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.7.2}
47
+ s.summary = %q{Configuration object and YAML-based storage for Rails apps}
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<rails>, [">= 3.0"])
54
+ s.add_development_dependency(%q<rspec>, [">= 0"])
55
+ s.add_development_dependency(%q<yard>, [">= 0"])
56
+ s.add_development_dependency(%q<RedCloth>, [">= 0"])
57
+ s.add_development_dependency(%q<bundler>, [">= 0"])
58
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<rails>, [">= 3.0"])
61
+ s.add_dependency(%q<rspec>, [">= 0"])
62
+ s.add_dependency(%q<yard>, [">= 0"])
63
+ s.add_dependency(%q<RedCloth>, [">= 0"])
64
+ s.add_dependency(%q<bundler>, [">= 0"])
65
+ s.add_dependency(%q<jeweler>, [">= 0"])
66
+ end
67
+ else
68
+ s.add_dependency(%q<rails>, [">= 3.0"])
69
+ s.add_dependency(%q<rspec>, [">= 0"])
70
+ s.add_dependency(%q<yard>, [">= 0"])
71
+ s.add_dependency(%q<RedCloth>, [">= 0"])
72
+ s.add_dependency(%q<bundler>, [">= 0"])
73
+ s.add_dependency(%q<jeweler>, [">= 0"])
74
+ end
75
+ end
76
+
@@ -0,0 +1,17 @@
1
+ require 'rails'
2
+ require 'rails/generators'
3
+
4
+ class ConfigoroGenerator < Rails::Generators::Base
5
+ desc "Installs example configuration files for use with Configoro"
6
+
7
+ def create_yaml_files
8
+ create_file "config/environments/common/example.yml",
9
+ { 'common_setting' => true }.to_yaml
10
+ create_file "config/environments/development/example.yml",
11
+ { 'environment_name' => 'Development' }.to_yaml
12
+ create_file "config/environments/test/example.yml",
13
+ { 'environment_name' => 'Test' }.to_yaml
14
+ create_file "config/environments/production/example.yml",
15
+ { 'environment_name' => 'Production' }.to_yaml
16
+ end
17
+ end
data/lib/configoro.rb ADDED
@@ -0,0 +1,10 @@
1
+ raise "Configoro must be used in the context of a Rails 3 application" unless defined?(Rails)
2
+
3
+ require 'yaml'
4
+ require 'bundler'
5
+ Bundler.setup
6
+
7
+ require 'configoro/base'
8
+ require 'configoro/hash'
9
+ require 'configoro/railtie'
10
+ require "#{File.dirname __FILE__}/../generators/configoro_generator"
@@ -0,0 +1,34 @@
1
+ # This module handles initialization of the Configoro object, and contains some
2
+ # utility methods.
3
+
4
+ module Configoro
5
+
6
+ # @return [Module] The Rails application namespace; e.g., @MyApp@ for a Rails
7
+ # app named @MyApp::Application@.
8
+
9
+ def self.namespace
10
+ Object.const_get Rails.application.class.to_s.split('::').first
11
+ end
12
+
13
+ # Creates the configuration dictionary and stores it under
14
+ # @MyApp::Configuration@ (assuming an application named @MyApp@).
15
+
16
+ def self.initialize
17
+ namespace.const_set :Configuration, build_hash(Rails.env)
18
+ end
19
+
20
+ private
21
+
22
+ def self.build_hash(env)
23
+ config = Hash.new
24
+
25
+ load_data config, 'common'
26
+ load_data config, env
27
+
28
+ config
29
+ end
30
+
31
+ def self.load_data(config, env)
32
+ Dir.glob("#{Rails.root}/config/environments/#{env}/*.yml").sort.each { |file| config << file }
33
+ end
34
+ end
@@ -0,0 +1,131 @@
1
+ require 'active_support/hash_with_indifferent_access'
2
+ require 'active_support/core_ext/hash/deep_merge'
3
+
4
+ class Configoro::Hash < HashWithIndifferentAccess
5
+
6
+ # @private
7
+ def initialize(hsh={})
8
+ if hsh.kind_of?(::Hash) then
9
+ super()
10
+ update hsh
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ # Deep-merges additional hash entries into this hash.
17
+ #
18
+ # @return [Configoro::Hash] This object.
19
+ # @overload <<(hash)
20
+ # Adds the entries from another hash.
21
+ # @param [::Hash] hash The additional keys to add.
22
+ # @overload <<(path)
23
+ # Adds the entries from a YAML file. The entries will be added under a
24
+ # sub-hash named after the YAML file's name.
25
+ # @param [String] path The path to a YAML file ending in ".yml".
26
+ # @raise [ArgumentError] If the filename does not end in ".yml".
27
+
28
+ def <<(hsh_or_path)
29
+ case hsh_or_path
30
+ when String
31
+ raise ArgumentError, "Only files ending in .yml can be added" unless File.extname(hsh_or_path) == '.yml'
32
+ return self unless File.exist?(hsh_or_path)
33
+ data = YAML.load_file(hsh_or_path)
34
+ deep_merge! File.basename(hsh_or_path, ".yml") => data
35
+ when ::Hash
36
+ deep_merge! hsh_or_path
37
+ end
38
+ end
39
+
40
+ alias_method :push, :<<
41
+
42
+ # @private
43
+ def dup
44
+ Hash.new(self)
45
+ end
46
+
47
+ # Recursively merges this hash with another hash. All nested hashes are forced
48
+ # to be @Configoro::Hash@ instances.
49
+ #
50
+ # @param [::Hash] other_hash The hash to merge into this one.
51
+ # @return [Configoro::Hash] This object.
52
+
53
+ def deep_merge!(other_hash)
54
+ other_hash.each_pair do |k, v|
55
+ tv = self[k]
56
+ self[k] = if v.kind_of?(::Hash) then
57
+ if tv.kind_of?(::Hash) then
58
+ Configoro::Hash.new(tv).deep_merge!(v)
59
+ else
60
+ Configoro::Hash.new(v)
61
+ end
62
+ else
63
+ v
64
+ end
65
+ end
66
+ self
67
+ end
68
+
69
+ # @private
70
+ #
71
+ # To optimize access, we create a getter method every time we encounter a
72
+ # key that exists in the hash. If the key is later deleted, the method will
73
+ # be removed.
74
+
75
+ def method_missing(meth, *args)
76
+ if include?(meth.to_s) then
77
+ if args.empty? then
78
+ create_getter meth
79
+ else
80
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
81
+ end
82
+ else
83
+ super
84
+ end
85
+ end
86
+
87
+ # @private
88
+ def inspect
89
+ "#{to_hash.inspect}:#{self.class.to_s}"
90
+ end
91
+
92
+ protected
93
+
94
+ def self.new_from_hash_copying_default(hash)
95
+ Configoro::Hash.new(hash).tap do |new_hash|
96
+ new_hash.default = hash.default
97
+ end
98
+ end
99
+
100
+ def convert_value(value)
101
+ if value.is_a?(::Hash)
102
+ self.class.new_from_hash_copying_default(value)
103
+ elsif value.is_a?(Array)
104
+ value.dup.replace(value.map { |e| convert_value(e) })
105
+ else
106
+ value
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def create_getter(meth)
113
+ singleton_class.send(:define_method, meth) do
114
+ if include?(meth.to_s) then
115
+ self[meth.to_s]
116
+ else
117
+ remove_getter meth
118
+ end
119
+ end
120
+
121
+ self[meth.to_s]
122
+ end
123
+
124
+ def remove_getter(meth)
125
+ if methods.include?(meth.to_sym) then
126
+ instance_eval "undef #{meth.to_sym.inspect}"
127
+ end
128
+
129
+ raise NameError, "undefined local variable or method `#{meth}' for #{self.inspect}"
130
+ end
131
+ end
@@ -0,0 +1,7 @@
1
+ # Loads the @Configuration@ object during the Rails initialization process.
2
+
3
+ class Configoro::Railtie < Rails::Railtie
4
+ initializer "Configoro" do
5
+ Configoro.initialize
6
+ end
7
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Configoro::Hash do
4
+ subject { Configoro::Hash.new(:string => 'value', :fixnum => 123, :hash => { :foo => 'bar' }, :array => [ 1, 2, 3 ]) }
5
+
6
+ context "[getters]" do
7
+ it "should allow access by symbol" do
8
+ subject[:string].should eql('value')
9
+ end
10
+
11
+ it "should allow access by string" do
12
+ subject['fixnum'].should eql(123)
13
+ end
14
+
15
+ it "should allow access by method" do
16
+ subject.array.should eql([ 1, 2, 3 ])
17
+ end
18
+ end
19
+
20
+ context "[accessor methods]" do
21
+ it "should define an accessor method upon first access" do
22
+ subject.methods.should_not include(:string)
23
+ subject.string
24
+ subject.methods.should include(:string)
25
+ end
26
+
27
+ it "should remove the accessor method if the key is removed from the hash" do
28
+ subject.string
29
+ subject.methods.should include(:string)
30
+ subject.delete 'string'
31
+ proc { subject.string }.should raise_error(NameError)
32
+ subject.methods.should_not include(:string)
33
+ end
34
+
35
+ it "should not override existing methods" do
36
+ subject['inspect'] = 'wrong!'
37
+ subject.inspect.should_not eql('wrong!')
38
+ end
39
+ end
40
+
41
+ describe "#include?" do
42
+ it "should accept symbols" do
43
+ subject.should include(:string)
44
+ subject.should_not include(:string2)
45
+ end
46
+
47
+ it "should accept strings" do
48
+ subject.should include('fixnum')
49
+ subject.should_not include('fixnum2')
50
+ end
51
+ end
52
+
53
+ describe "#<<" do
54
+ subject { Configoro::Hash.new }
55
+
56
+ it "should deep-merge entries from a hash" do
57
+ subject << { :a => 'b', :b => { :c => 'd' } }
58
+ subject << { :a => 'b', :b => { :d => 'e' } }
59
+
60
+ subject.a.should eql('b')
61
+ subject.b.c.should eql('d')
62
+ subject.b.d.should eql('e')
63
+ end
64
+
65
+ it "should load a YAML file and deep-merge its entries" do
66
+ subject << "#{File.dirname __FILE__}/../data/config/environments/common/hash_test.yml"
67
+ subject << "#{File.dirname __FILE__}/../data/config/environments/development/hash_test.yml"
68
+
69
+ subject.hash_test.akey.should eql('value')
70
+ subject.hash_test.subhash.key1.should eql('val1')
71
+ subject.hash_test.subhash.key2.should eql('newval')
72
+ end
73
+
74
+ it "should raise an error if the file is not a YAML file" do
75
+ lambda { subject << "example.txt" }.should raise_error(ArgumentError)
76
+ end
77
+
78
+ it "should not change the receiver if the file doesn't exist" do
79
+ subject << "example.yml"
80
+ subject.should be_empty
81
+ end
82
+ end
83
+
84
+ describe "#deep_merge!" do
85
+ subject { Configoro::Hash.new }
86
+
87
+ it "should merge in keys and values" do
88
+ subject['a'] = 'old'
89
+ subject.deep_merge! :a => 'new'
90
+ subject.a.should eql('new')
91
+ end
92
+
93
+ it "should deep-merge sub-hashes and convert them to Configoro::Hashes" do
94
+ subject['hsh'] = { 'key1' => 'val1', 'key2' => 'val2' }
95
+ subject.deep_merge! :hsh => { 'key2' => 'newval' }
96
+
97
+ subject.hsh.key1.should eql('val1')
98
+ subject.hsh.key2.should eql('newval')
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module MyApp; end
4
+
5
+ describe Configoro do
6
+ subject { MyApp::Configuration }
7
+
8
+ describe "#initialize" do
9
+ it "should make the configuration available to MyApp::Configuration" do
10
+ subject.should be_kind_of(Configoro::Hash)
11
+ end
12
+
13
+ it "should load data from the config files" do
14
+ subject.basic.common_only.should eql('common')
15
+ end
16
+
17
+ it "should give priority to environment-specific files" do
18
+ subject.basic.env_name.should eql('development')
19
+ end
20
+
21
+ it "should not load data from other environments" do
22
+ subject.basic['should_not_exist'].should be_nil
23
+ end
24
+
25
+ it "should convert hashes recursively" do
26
+ subject.hash_test.akey.should eql('value')
27
+ end
28
+
29
+ it "should deep-merge hashes" do
30
+ subject.hash_test.subhash.key1.should eql('val1')
31
+ subject.hash_test.subhash.key2.should eql('newval')
32
+ end
33
+
34
+ it "should not complain when there is no directory for the current environment" do
35
+ Rails.stub!(:env).and_return('unknown')
36
+ Configoro.initialize
37
+ MyApp::Configuration.should eql({"basic"=>{"common_only"=>"common", "env_name"=>"common"}, "hash_test"=>{"akey"=>"value", "subhash"=>{"key1"=>"val1", "key2"=>"val2"}}})
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ ---
2
+ common_only: common
3
+ env_name: common
@@ -0,0 +1,5 @@
1
+ ---
2
+ akey: value
3
+ subhash:
4
+ key1: val1
5
+ key2: val2
@@ -0,0 +1,5 @@
1
+ ---
2
+ :env_name: development
3
+ hsh:
4
+ subhash:
5
+ key2: newval
@@ -0,0 +1,3 @@
1
+ ---
2
+ subhash:
3
+ key2: newval
@@ -0,0 +1,3 @@
1
+ ---
2
+ :env_name: production
3
+ should_not_exist: true
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'bundler'
5
+ Bundler.require :development
6
+
7
+ require 'yaml'
8
+ Bundler.setup
9
+
10
+ require 'configoro/base'
11
+ require 'configoro/hash'
12
+
13
+ # Requires supporting files with custom matchers and macros, etc,
14
+ # in ./support/ and its subdirectories.
15
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
16
+
17
+ RSpec.configure do |config|
18
+ config.before :each do
19
+ application = mock('Rails.application', :class => 'MyApp::Application')
20
+ ::Rails = mock('Rails', :application => application, :env => 'development', :root => File.join(File.dirname(__FILE__), 'data'))
21
+ Configoro.initialize
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: configoro
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Tim Morgan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-05 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "3.0"
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: yard
39
+ requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: RedCloth
50
+ requirement: &id004 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: bundler
61
+ requirement: &id005 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: jeweler
72
+ requirement: &id006 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *id006
81
+ description: Creates a YourApp::Configuration object whose methods are generated from environment-specific YAML files.
82
+ email: git@timothymorgan.info
83
+ executables: []
84
+
85
+ extensions: []
86
+
87
+ extra_rdoc_files:
88
+ - LICENSE.txt
89
+ - README.textile
90
+ files:
91
+ - .document
92
+ - .rspec
93
+ - Gemfile
94
+ - Gemfile.lock
95
+ - LICENSE.txt
96
+ - README.textile
97
+ - Rakefile
98
+ - VERSION
99
+ - configoro.gemspec
100
+ - generators/configoro_generator.rb
101
+ - lib/configoro.rb
102
+ - lib/configoro/base.rb
103
+ - lib/configoro/hash.rb
104
+ - lib/configoro/railtie.rb
105
+ - spec/configoro/hash_spec.rb
106
+ - spec/configoro_spec.rb
107
+ - spec/data/config/environments/common/basic.yml
108
+ - spec/data/config/environments/common/hash_test.yml
109
+ - spec/data/config/environments/development/basic.yml
110
+ - spec/data/config/environments/development/hash_test.yml
111
+ - spec/data/config/environments/production/basic.yml
112
+ - spec/spec_helper.rb
113
+ homepage: http://github.com/RISCfuture/configoro
114
+ licenses:
115
+ - MIT
116
+ post_install_message:
117
+ rdoc_options: []
118
+
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: -2726389570801720649
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: "0"
136
+ requirements: []
137
+
138
+ rubyforge_project:
139
+ rubygems_version: 1.7.2
140
+ signing_key:
141
+ specification_version: 3
142
+ summary: Configuration object and YAML-based storage for Rails apps
143
+ test_files: []
144
+