nested_config 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ rdoc
6
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.3@nested_config --create
data/.simplecov ADDED
@@ -0,0 +1,7 @@
1
+ require 'simplecov-rcov'
2
+
3
+ SimpleCov.coverage_dir "tmp/coverage"
4
+ SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter if ENV['CI']
5
+ SimpleCov.start do
6
+ add_filter '/test/'
7
+ end
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'simplecov', :require => false
7
+ gem 'simplecov-rcov', :require => false
8
+ end
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = nested_config
2
+
3
+ Simple, static, nested application configuration
4
+
5
+ == Usage
6
+
7
+ require 'nested_config'
8
+
9
+ class MyApp
10
+ def self.configure
11
+ yield config
12
+ end
13
+
14
+ def self.config
15
+ @config ||= MyConfig.new
16
+ end
17
+
18
+ class MyConfig < NestedConfig.new
19
+ end
20
+ end
21
+
22
+ === Basic
23
+
24
+ MyApp.configure do |config|
25
+ config.coins = 1000
26
+ config.user do |user|
27
+ user.max = 5
28
+ end
29
+ config.queue do |queue|
30
+ queue.workers do |workers|
31
+ workers.max = 2
32
+ workers.timeout = 60.seconds
33
+ end
34
+ end
35
+ end
36
+
37
+ MyApp.config.coins # => 1000
38
+ MyApp.config.queue.workers.timeout # => 60
39
+
40
+
41
+ === EvaluateOnce
42
+
43
+ With the module +EvaluateOnce+ you can define config value which will be evaluated lazily. Once.
44
+
45
+ class MyConfig
46
+ include NestedConfig::EvaluateOnce
47
+ end
48
+
49
+ MyApp.configure do |config|
50
+ config.country_list = proc { Country.all }
51
+ end
52
+
53
+ MyApp.config.country_list # => [List of countries]
54
+ MyApp.config.country_list # => [List of countries] (cached)
55
+
56
+ The initial access to key +country_list+ calls (via +call+ method) the proc and replaces the value.
57
+ Subsequent calls just fetch the replaced value.
58
+
59
+
60
+ === Key names
61
+
62
+ *Note*: NestedConfig is not a blank slate so you CANNOT use defined method names as keys like +object_id+.
63
+
64
+ == Installation
65
+
66
+ gem install nested_config
67
+
68
+ == Test
69
+
70
+ rake test
71
+ COVERAGE=1 rake test
72
+
73
+ == Release
74
+
75
+ edit lib/nested_config/version.rb
76
+ rake release
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc 'Default: run unit tests.'
4
+ task :default => :test
5
+
6
+ # Test
7
+ require 'rake/testtask'
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.test_files = FileList.new('test/*_test.rb')
10
+ test.libs << 'test'
11
+ test.verbose = true
12
+ end
13
+
14
+ # RDoc
15
+ require 'rdoc/task'
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'nested config'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
@@ -0,0 +1,30 @@
1
+ class NestedConfig
2
+ # Evaluates a config value once replacing the original value
3
+ # if the value responds to method +call+.
4
+ #
5
+ # == Example
6
+ #
7
+ # class MyConfig < NestedConfig
8
+ # include NestedConfig::EvaluateOnce
9
+ # end
10
+ #
11
+ # config = MyConfig.new
12
+ # config.startup_time = proc { Time.now }
13
+ # config.env = proc { |env| env.to_s.upcase }
14
+ #
15
+ # config.startup_time # => 2012-06-05 15:57:36 +0200
16
+ # config.startup_time # => 2012-06-05 15:57:36 +0200
17
+ #
18
+ # config.env(:development) # => DEVELOPMENT
19
+ # config.env # => DEVELOPMENT
20
+ module EvaluateOnce
21
+ def [](key, *args)
22
+ value = super
23
+ if value.respond_to?(:call)
24
+ self[key] = value.call(*args)
25
+ else
26
+ value
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ class NestedConfig
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,43 @@
1
+ require 'nested_config/version'
2
+
3
+ class NestedConfig
4
+ autoload :EvaluateOnce, 'nested_config/evaluate_once'
5
+
6
+ def initialize
7
+ @hash = {}
8
+ end
9
+
10
+ def [](name, *args)
11
+ @hash[name.to_s]
12
+ end
13
+
14
+ def []=(name, value)
15
+ @hash[name.to_s] = value
16
+ end
17
+
18
+ def __hash__
19
+ @hash
20
+ end
21
+
22
+ def inspect
23
+ @hash
24
+ end
25
+
26
+ def method_missing(name, *args)
27
+ if block_given?
28
+ config = self[name] ||= self.class.new
29
+ yield config
30
+ else
31
+ key = name.to_s.gsub(/=$/, '')
32
+ if $& == '='
33
+ self[key] = args.first
34
+ else
35
+ self[key, *args]
36
+ end
37
+ end
38
+ end
39
+
40
+ def respond_to?(name, include_private=false)
41
+ __hash__.key?(name.to_s) || super
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "nested_config/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "nested_config"
7
+ s.version = NestedConfig::VERSION
8
+ s.authors = ["Peter Suschlik"]
9
+ s.email = ["ps@neopoly.de"]
10
+ s.homepage = "https://github.com/neopoly/nested_config"
11
+ s.summary = %q{Simple, static, nested config}
12
+ s.description = %q{}
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 "rake"
20
+ s.add_development_dependency "minitest"
21
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+ # simplecov
2
+ require 'simplecov' if ENV['COVERAGE']
3
+
4
+ require 'rubygems'
5
+ require 'minitest/spec'
6
+ require 'minitest/autorun'
7
+
8
+ require 'nested_config'
9
+
10
+ class NestedConfigSpec < MiniTest::Spec
11
+ class << self
12
+ alias :test :it
13
+ alias :context :describe
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ class NestedConfigEvaluateOnceTest < NestedConfigSpec
4
+ let(:config) do
5
+ Class.new(NestedConfig) do
6
+ include NestedConfig::EvaluateOnce
7
+ end.new
8
+ end
9
+
10
+ context "evaluates once w/o argument" do
11
+ context "w/o argument" do
12
+ before do
13
+ config.startup_time = proc { Time.now }
14
+ end
15
+
16
+ test "has time value" do
17
+ assert_instance_of Time, config.startup_time
18
+ end
19
+
20
+ test "value does not change" do
21
+ n = config.startup_time
22
+ assert_same n, config.startup_time
23
+ end
24
+ end
25
+
26
+ context "with argument" do
27
+ before do
28
+ config.env = proc { |e| e.to_s.upcase }
29
+ config.env(:development)
30
+ end
31
+
32
+ test "replaces original value" do
33
+ assert_equal "DEVELOPMENT", config.env
34
+ end
35
+
36
+ test "value does not change" do
37
+ env = config.env
38
+ assert_same env, config.env
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ class NestedConfigEvaluateOnceTest < NestedConfigSpec
4
+ let(:config) do
5
+ Class.new(NestedConfig) do
6
+ include NestedConfig::EvaluateOnce
7
+ end.new
8
+ end
9
+
10
+ context "evaluates once w/o argument" do
11
+ context "w/o argument" do
12
+ before do
13
+ config.startup_time = proc { Time.now }
14
+ end
15
+
16
+ test "has time value" do
17
+ assert_instance_of Time, config.startup_time
18
+ end
19
+
20
+ test "value does not change" do
21
+ n = config.startup_time
22
+ assert_same n, config.startup_time
23
+ end
24
+ end
25
+
26
+ context "with argument" do
27
+ before do
28
+ config.env = proc { |e| e.to_s.upcase }
29
+ config.env(:development)
30
+ end
31
+
32
+ test "replaces original value" do
33
+ assert_equal "DEVELOPMENT", config.env
34
+ end
35
+
36
+ test "value does not change" do
37
+ env = config.env
38
+ assert_same env, config.env
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,128 @@
1
+ require 'helper'
2
+
3
+ class NestedConfigTest < NestedConfigSpec
4
+
5
+ context "basic" do
6
+ let(:config) { NestedConfig.new }
7
+
8
+ test "empty" do
9
+ assert config.__hash__.empty?
10
+ end
11
+
12
+ test "is NOT a blank slate right now" do
13
+ Object.instance_methods.each do |method|
14
+ assert config.respond_to?(method)
15
+ end
16
+ end
17
+
18
+ test "inspect retrives __hash__" do
19
+ c = config.tap { |c| c.foo = :bar }
20
+ assert_same c.inspect, c.__hash__
21
+ end
22
+
23
+ test "cannot use defined method names as keys" do
24
+ c = config.tap do |c|
25
+ c.object_id = :foo
26
+ c.class = :bar
27
+ end
28
+ refute_equal :foo, c.object_id
29
+ refute_equal :bar, c.class
30
+ end
31
+
32
+ test "sets values" do
33
+ c = config.tap do |c|
34
+ c.foo = :bar
35
+ c.bar = :baz
36
+ end
37
+
38
+ assert_equal :bar, c.foo
39
+ assert_equal :baz, c.bar
40
+ assert_nil c.unknown
41
+ end
42
+
43
+ test "sets deep values" do
44
+ c = config.tap do |c|
45
+ c.deep do |deep|
46
+ deep.key = :foo
47
+ deep.deeper do |deeper|
48
+ deeper.key = :bar
49
+ end
50
+ end
51
+ c.deep2 do |deep2|
52
+ deep2.key = :baz
53
+ end
54
+ end
55
+
56
+ assert_equal :foo, c.deep.key
57
+ assert_equal :bar, c.deep.deeper.key
58
+ assert_equal :baz, c.deep2.key
59
+ end
60
+
61
+ test "sets arrays as value" do
62
+ c = config.tap do |c|
63
+ c.ary = [ :foo, :bar ]
64
+ c.ary2 = :foo, :bar
65
+ end
66
+
67
+ assert_equal [ :foo, :bar ], c.ary
68
+ assert_equal [ :foo, :bar ], c.ary2
69
+ end
70
+
71
+ test "cannot nest nil" do
72
+ c = config.tap do |c|
73
+ c.key = :foo
74
+ end
75
+
76
+ e = assert_raises NoMethodError do
77
+ c.deep.deeper.key
78
+ end
79
+ assert_match /NilClass/, e.message
80
+ end
81
+
82
+ test "respond_to?" do
83
+ c = config.tap do |c|
84
+ c.foo = :bar
85
+ end
86
+
87
+ assert_respond_to c, :foo
88
+ end
89
+
90
+ test "re-use already defined nested config" do
91
+ c = config.tap do |c|
92
+ c.users do |users|
93
+ users.max = 23
94
+ end
95
+ c.users do |users|
96
+ users.min = 5
97
+ end
98
+ end
99
+
100
+ assert_equal 23, c.users.max
101
+ assert_equal 5, c.users.min
102
+ end
103
+
104
+ context "subclass" do
105
+ let(:subclassed_config) do
106
+ Class.new(NestedConfig) do
107
+ def foo?
108
+ :bar!
109
+ end
110
+ end.new
111
+ end
112
+
113
+ test "has foo?" do
114
+ assert_equal :bar!, subclassed_config.foo?
115
+ end
116
+
117
+ test "nests subclassed config" do
118
+ c = subclassed_config.tap do |c|
119
+ c.users do |users|
120
+ users.max = 23
121
+ end
122
+ end
123
+
124
+ assert_equal :bar!, c.users.foo?
125
+ end
126
+ end
127
+ end
128
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nested_config
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Peter Suschlik
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ''
47
+ email:
48
+ - ps@neopoly.de
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rvmrc
55
+ - .simplecov
56
+ - Gemfile
57
+ - README.rdoc
58
+ - Rakefile
59
+ - lib/nested_config.rb
60
+ - lib/nested_config/evaluate_once.rb
61
+ - lib/nested_config/version.rb
62
+ - nested_config.gemspec
63
+ - test/helper.rb
64
+ - test/neopoly_config_evaluate_once_test.rb
65
+ - test/nested_config_evaluate_once_test.rb
66
+ - test/nested_config_test.rb
67
+ homepage: https://github.com/neopoly/nested_config
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project:
87
+ rubygems_version: 1.8.24
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Simple, static, nested config
91
+ test_files: []