static_config 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/.autotest ADDED
@@ -0,0 +1,5 @@
1
+ Autotest.add_hook(:initialize) do |at|
2
+ at.add_exception /^\.git/
3
+ at.add_exception /^\.bundle/
4
+ at.add_exception /sw[op]$/
5
+ end
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --debug
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in static_config.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+ gem 'rspec'
8
+ gem 'autotest', :require => nil
9
+ gem 'autotest-growl', :require => nil
10
+ gem 'ruby-debug'
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ Example
2
+ -------
3
+
4
+ MyAppConfig = StaticConfig.build do
5
+ first do
6
+ env_yaml 'my_app_config'
7
+ file Rails.root.join('config/my_app.yml'), :section => Rails.env
8
+ end
9
+ env 'MY_APP'
10
+ end
11
+
12
+ Now you have an object MyAppConfig that you can use anywhere.
13
+
14
+ For instance, if your `config/my_app.yml` looks like this:
15
+
16
+ development:
17
+ user:
18
+ selected:
19
+ color: orange
20
+
21
+ You could get `orange` by doing this:
22
+
23
+ MyAppConfig.user.selected.color
24
+
25
+ You could override it at runtime by setting the environment variable
26
+ `MY_APP_USER_SELECTED_COLOR`.
27
+
28
+ You can also override the entire `config/my_app.yml` file by storing
29
+ some yaml in an environment variable called `my_app_config`.
30
+
31
+ To get your config to reload on each request in Rails, add this:
32
+
33
+ Rails.application.config.to_prepare do
34
+ MyAppConfig.reload!
35
+ end
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ desc 'Run specs'
6
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,11 @@
1
+ require 'static_config/configurer'
2
+
3
+ module StaticConfig
4
+ class << self
5
+ def build(&block)
6
+ config = Configurer.new
7
+ config.instance_eval(&block)
8
+ config.build
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module StaticConfig
2
+ module Aggregation
3
+ class First
4
+ def initialize(readers)
5
+ @readers = readers
6
+ end
7
+
8
+ def read
9
+ @readers.inject(nil) { |res, reader| res || empty_to_nil(reader.read) } || {}
10
+ end
11
+
12
+ private
13
+ def empty_to_nil(hash)
14
+ if hash && hash.size > 0
15
+ hash
16
+ else
17
+ nil
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module StaticConfig
2
+ module Aggregation
3
+ class Merge
4
+ def initialize(readers)
5
+ @readers = readers
6
+ end
7
+
8
+ def read
9
+ @readers.inject({}) { |res, reader| deep_merge res, reader.read }
10
+ end
11
+
12
+ private
13
+ def deep_merge base, overrides
14
+ overrides.inject(base.dup) { |res, (key, value)|
15
+ res[key] =
16
+ if res[key].is_a?(Hash) && value.is_a?(Hash)
17
+ deep_merge res[key], value
18
+ else
19
+ value
20
+ end
21
+ res
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module StaticConfig
2
+ class ConfigHash
3
+ def initialize(data)
4
+ @data = data
5
+ end
6
+
7
+ def method_missing(attr, *args)
8
+ if value = @data[attr.to_s]
9
+ if value.is_a? Hash
10
+ ConfigHash.new value
11
+ else
12
+ value
13
+ end
14
+ else
15
+ nil
16
+ end
17
+ end
18
+
19
+ def ==(other)
20
+ super || @data == other
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'static_config/config_hash'
2
+
3
+ module StaticConfig
4
+ class ConfigProxy
5
+ def initialize(reader)
6
+ @reader = reader
7
+ end
8
+
9
+ def method_missing(*args)
10
+ config.send(*args)
11
+ end
12
+
13
+ def config
14
+ @config ||= ConfigHash.new @reader.read
15
+ end
16
+
17
+ def reload!
18
+ @config = nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ require 'static_config/config_proxy'
2
+ require 'static_config/aggregation/merge'
3
+ require 'static_config/aggregation/first'
4
+ require 'static_config/reader/environment'
5
+ require 'static_config/reader/yaml_env'
6
+ require 'static_config/reader/yaml_file'
7
+
8
+ module StaticConfig
9
+ class Configurer
10
+ def build
11
+ ConfigProxy.new StaticConfig::Aggregation::Merge.new(self.readers)
12
+ end
13
+ def first(&block)
14
+ push_readers do
15
+ instance_eval(&block)
16
+ add StaticConfig::Aggregation::First.new self.readers
17
+ end
18
+ end
19
+ def env(var_prefix)
20
+ add StaticConfig::Reader::Environment.new(:env_prefix => var_prefix)
21
+ end
22
+ def env_yaml(var_name)
23
+ add StaticConfig::Reader::YamlEnv.new(:env => var_name)
24
+ end
25
+ def file(path, opts={})
26
+ add StaticConfig::Reader::YamlFile.new(opts.merge(:file => path))
27
+ end
28
+ def add(reader)
29
+ readers << reader
30
+ end
31
+ def push_readers
32
+ old_readers, self.readers = self.readers, []
33
+ yield
34
+ ensure
35
+ self.readers = old_readers
36
+ end
37
+ def readers
38
+ @readers ||= []
39
+ end
40
+ attr_writer :readers
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ module StaticConfig
2
+ module Reader
3
+ class Base
4
+ class << self
5
+ def read(opts = {})
6
+ new(opts).read
7
+ end
8
+ end
9
+
10
+ def initialize(opts = {})
11
+ end
12
+
13
+ def read
14
+ raw_data || {}
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'static_config/reader/base'
2
+
3
+ module StaticConfig
4
+ module Reader
5
+ class Environment < Base
6
+ def initialize(opts = {})
7
+ super
8
+ @env_prefix = opts[:env_prefix]
9
+ end
10
+
11
+ protected
12
+ def raw_data
13
+ ENV.inject({}) { |res, (name, value)| update(res, name, value) }
14
+ end
15
+
16
+ def update(data, env_name, env_value)
17
+ if env_name =~ /^#{@env_prefix}_(.*)/
18
+ parts = $1.downcase.split(/_/)
19
+ last_part = parts.pop
20
+ parts.inject(data) { |h, k| h[k] ||= {} }[last_part] = env_value
21
+ end
22
+ data
23
+ rescue => e
24
+ raise "Unable to fit #{env_name} into #{data.inspect}"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ require 'static_config/reader/base'
2
+ require 'yaml'
3
+
4
+ module StaticConfig
5
+ module Reader
6
+ class YamlEnv < Base
7
+ def initialize(opts = {})
8
+ super
9
+ @env = opts[:env]
10
+ end
11
+
12
+ protected
13
+ def raw_data
14
+ YAML.load(ENV[@env])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'static_config/reader/base'
2
+ require 'yaml'
3
+
4
+ module StaticConfig
5
+ module Reader
6
+ class YamlFile < Base
7
+ def initialize(opts = {})
8
+ super
9
+ @file = opts[:file]
10
+ @section = opts[:section]
11
+ end
12
+
13
+ protected
14
+ def raw_data
15
+ data = YAML.load_file(@file) if File.exists? @file
16
+ data = data[@section] if data && @section
17
+ data
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module StaticConfig
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1 @@
1
+ # if necessary.
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'static_config/aggregation/first'
3
+
4
+ describe StaticConfig::Aggregation::First do
5
+ let(:subject) { described_class.new(readers) }
6
+
7
+ class Reader
8
+ def initialize(data)
9
+ @read = data
10
+ end
11
+ attr_accessor :read
12
+ end
13
+
14
+ let(:nil_reader) { Reader.new(nil) }
15
+ let(:empty_reader) { Reader.new({}) }
16
+ let(:reader_A) { Reader.new('a' => '1') }
17
+ let(:reader_B) { Reader.new('b' => '1') }
18
+
19
+ context 'with a not-empty reader' do
20
+ let(:readers) { [reader_A] }
21
+ its(:read) { should == {'a' => '1'} }
22
+ end
23
+
24
+ context 'with just a nil reader' do
25
+ let(:readers) { [nil_reader] }
26
+ its(:read) { should == {} }
27
+ end
28
+
29
+ context 'with an empty and not-empty reader' do
30
+ let(:readers) { [empty_reader, reader_A] }
31
+ its(:read) { should == {'a' => '1'} }
32
+ end
33
+
34
+ context 'with two readers' do
35
+ let(:readers) { [reader_B, reader_A] }
36
+ its(:read) { should == {'b' => '1'} }
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'static_config/aggregation/merge'
3
+
4
+ describe StaticConfig::Aggregation::Merge do
5
+ let(:subject) { described_class.new(readers) }
6
+
7
+ class Reader
8
+ def initialize(data)
9
+ @read = data
10
+ end
11
+ attr_accessor :read
12
+ end
13
+
14
+ let(:reader_A) { Reader.new('a' => '1') }
15
+ let(:reader_A2) { Reader.new('a' => '2') }
16
+ let(:reader_B) { Reader.new('b' => '1') }
17
+ let(:deep_reader_A) { Reader.new('really' => { 'deep' => { 'A' => '1' } }) }
18
+ let(:deep_reader_B) { Reader.new('really' => { 'deep' => { 'B' => '1' } }) }
19
+
20
+ context 'with one reader' do
21
+ let(:readers) { [reader_A] }
22
+ its(:read) { should == {'a' => '1'} }
23
+ end
24
+
25
+ context 'with two readers' do
26
+ let(:readers) { [reader_A, reader_B] }
27
+ its(:read) { should == {'a' => '1', 'b' => '1'} }
28
+ end
29
+
30
+ context 'with two readers with the same key' do
31
+ let(:readers) { [reader_A, reader_A2] }
32
+ its(:read) { should == {'a' => '2'} }
33
+ end
34
+
35
+ context 'with two deeply-nested results' do
36
+ let(:readers) { [deep_reader_A, deep_reader_B] }
37
+ its(:read) { should == {'really' => {'deep' => {'A' => '1', 'B' => '1'}}} }
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'static_config/config_hash'
3
+
4
+ describe StaticConfig::ConfigHash do
5
+ let(:subject) { StaticConfig::ConfigHash.new({'a' => 'ok', 'nested' => { 'key' => 'also ok' }}) }
6
+
7
+ its('a') { should == 'ok' }
8
+ its('nested') { should == { 'key' => 'also ok' } }
9
+ its('nested.key') { should == 'also ok' }
10
+ its('missing') { should be_nil }
11
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'static_config/config_proxy'
3
+
4
+ describe StaticConfig::ConfigProxy do
5
+ let(:subject) { described_class.new(reader) }
6
+
7
+ context do
8
+ class SimpleReader
9
+ def read
10
+ {'a' => 'ok', 'nested' => { 'key' => 'also ok' }}
11
+ end
12
+ end
13
+ let(:reader) { SimpleReader.new }
14
+
15
+ its('a') { should == 'ok' }
16
+ its('nested') { should == { 'key' => 'also ok' } }
17
+ its('nested.key') { should == 'also ok' }
18
+ its('missing') { should be_nil }
19
+ end
20
+
21
+ context do
22
+ class ChangeableReader
23
+ attr_accessor :read
24
+ end
25
+ let(:reader) { ChangeableReader.new }
26
+ it 're-reads' do
27
+ reader.read = { 'a' => 'old' }
28
+ expect{subject.reload! ; reader.read = { 'a' => 'new' }}.to change{subject.a}.from('old').to('new')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'static_config/reader/environment'
3
+
4
+ describe StaticConfig::Reader::Environment do
5
+ before do
6
+ ENV['MY_CONFIG_DEV_KEY'] = 'value'
7
+ end
8
+ after do
9
+ ENV['MY_CONFIG_DEV_KEY'] = nil
10
+ end
11
+ let(:subject) { described_class.read(opts) }
12
+
13
+ def opts ; { :env_prefix => 'MY_CONFIG' } ; end
14
+ it('reads environment') { should == { 'dev' => { 'key' => 'value' } } }
15
+ end
16
+
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'static_config/reader/yaml_env'
3
+
4
+ describe StaticConfig::Reader::YamlEnv do
5
+ let(:subject) { described_class.read(opts) }
6
+ after { ENV['my_config_yml'] = nil }
7
+ before { ENV['my_config_yml'] = "dev:\n key: value\n" }
8
+
9
+ def opts ; { :env => 'my_config_yml' } ; end
10
+ it('loads the yaml') { should == { 'dev' => { 'key' => 'value' } } }
11
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'static_config/reader/yaml_file'
3
+
4
+ describe StaticConfig::Reader::YamlFile do
5
+ let(:subject) { described_class.read(opts) }
6
+
7
+ def opts ; { :file => "#{__FILE__}.yml" } ; end
8
+ it('loads the yaml') { should == { 'dev' => { 'key' => 'value' } } }
9
+
10
+ context 'with section' do
11
+ def opts ; super.merge :section => 'dev' ; end
12
+ it('uses the section') { should == { 'key' => 'value' } }
13
+ end
14
+
15
+ context 'with a section that does not exist' do
16
+ def opts ; super.merge :section => 'bad' ; end
17
+ it('is empty') { should == {} }
18
+ end
19
+
20
+ context 'with an empty file' do
21
+ def opts ; { :file => "#{__FILE__}.empty" } ; end
22
+ it('is empty') { should == {} }
23
+
24
+ context 'and a section' do
25
+ def opts ; super.merge :section => 'section' ; end
26
+ it('is empty') { should == {} }
27
+ end
28
+ end
29
+
30
+ context 'with a file that does not exist' do
31
+ def opts ; { :file => "#{__FILE__}.does.not.exist" } ; end
32
+ it('is empty') { should == {} }
33
+ end
34
+ end
File without changes
@@ -0,0 +1,2 @@
1
+ dev:
2
+ key: value
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "static_config/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "static_config"
7
+ s.version = StaticConfig::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Matt Burke"]
10
+ s.email = ["spraints@gmail.com"]
11
+ s.homepage = "http://github.com/spraints/static_config"
12
+ s.summary = %q{Load configuration from yaml and/or environment variables}
13
+ s.description = %q{Load configuration from yaml and/or environment variables}
14
+
15
+ s.rubyforge_project = "static_config"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: static_config
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Matt Burke
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-09 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Load configuration from yaml and/or environment variables
22
+ email:
23
+ - spraints@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .autotest
32
+ - .gitignore
33
+ - .rspec
34
+ - Gemfile
35
+ - README.md
36
+ - Rakefile
37
+ - lib/static_config.rb
38
+ - lib/static_config/aggregation/first.rb
39
+ - lib/static_config/aggregation/merge.rb
40
+ - lib/static_config/config_hash.rb
41
+ - lib/static_config/config_proxy.rb
42
+ - lib/static_config/configurer.rb
43
+ - lib/static_config/reader/base.rb
44
+ - lib/static_config/reader/environment.rb
45
+ - lib/static_config/reader/yaml_env.rb
46
+ - lib/static_config/reader/yaml_file.rb
47
+ - lib/static_config/version.rb
48
+ - spec/spec_helper.rb
49
+ - spec/static_config/aggregation/first_spec.rb
50
+ - spec/static_config/aggregation/merge_spec.rb
51
+ - spec/static_config/config_hash_spec.rb
52
+ - spec/static_config/config_proxy_spec.rb
53
+ - spec/static_config/reader/environment_spec.rb
54
+ - spec/static_config/reader/yaml_env_spec.rb
55
+ - spec/static_config/reader/yaml_file_spec.rb
56
+ - spec/static_config/reader/yaml_file_spec.rb.empty
57
+ - spec/static_config/reader/yaml_file_spec.rb.yml
58
+ - static_config.gemspec
59
+ homepage: http://github.com/spraints/static_config
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project: static_config
88
+ rubygems_version: 1.8.4
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Load configuration from yaml and/or environment variables
92
+ test_files:
93
+ - spec/spec_helper.rb
94
+ - spec/static_config/aggregation/first_spec.rb
95
+ - spec/static_config/aggregation/merge_spec.rb
96
+ - spec/static_config/config_hash_spec.rb
97
+ - spec/static_config/config_proxy_spec.rb
98
+ - spec/static_config/reader/environment_spec.rb
99
+ - spec/static_config/reader/yaml_env_spec.rb
100
+ - spec/static_config/reader/yaml_file_spec.rb
101
+ - spec/static_config/reader/yaml_file_spec.rb.empty
102
+ - spec/static_config/reader/yaml_file_spec.rb.yml