nested_config 0.2.0
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 +6 -0
- data/.rvmrc +1 -0
- data/.simplecov +7 -0
- data/Gemfile +8 -0
- data/README.rdoc +76 -0
- data/Rakefile +22 -0
- data/lib/nested_config/evaluate_once.rb +30 -0
- data/lib/nested_config/version.rb +3 -0
- data/lib/nested_config.rb +43 -0
- data/nested_config.gemspec +21 -0
- data/test/helper.rb +15 -0
- data/test/neopoly_config_evaluate_once_test.rb +42 -0
- data/test/nested_config_evaluate_once_test.rb +42 -0
- data/test/nested_config_test.rb +128 -0
- metadata +91 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@nested_config --create
|
data/.simplecov
ADDED
data/Gemfile
ADDED
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,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: []
|