configatron 3.2.0 → 4.5.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 +1 -0
- data/.travis.yml +2 -2
- data/History.txt +72 -0
- data/README.md +25 -24
- data/Rakefile +10 -4
- data/configatron.gemspec +1 -0
- data/lib/configatron.rb +22 -4
- data/lib/configatron/core.rb +6 -6
- data/lib/configatron/ext/kernel.rb +5 -0
- data/lib/configatron/integrations.rb +4 -0
- data/lib/configatron/integrations/minitest.rb +29 -0
- data/lib/configatron/{rails.rb → integrations/rails.rb} +1 -1
- data/lib/configatron/root_store.rb +121 -0
- data/lib/configatron/store.rb +100 -63
- data/lib/configatron/version.rb +1 -1
- data/lib/generators/configatron/install/templates/configatron/defaults.rb +2 -2
- data/lib/generators/configatron/install/templates/configatron/development.rb +2 -2
- data/lib/generators/configatron/install/templates/configatron/production.rb +2 -2
- data/lib/generators/configatron/install/templates/configatron/test.rb +2 -2
- data/lib/generators/configatron/install/templates/initializers/configatron.rb +1 -1
- data/test/_lib.rb +17 -0
- data/test/functional/_lib.rb +10 -0
- data/test/functional/_lib/scripts/core.rb +11 -0
- data/test/functional/configatron.rb +165 -0
- data/test/functional/delayed.rb +18 -0
- data/test/functional/loading.rb +10 -0
- data/test/functional/minitest.rb +18 -0
- data/test/unit/_lib.rb +10 -0
- data/test/unit/configatron/proc.rb +24 -0
- data/test/unit/configatron/root_store.rb +37 -0
- data/test/unit/configatron/store.rb +149 -0
- metadata +73 -30
- checksums.yaml +0 -7
- data/.ruby-version +0 -1
- data/lib/configatron/deep_clone.rb +0 -69
- data/lib/configatron/kernel.rb +0 -21
- data/test/configatron/kernel_test.rb +0 -24
- data/test/configatron/proc_test.rb +0 -27
- data/test/configatron/store_test.rb +0 -256
- data/test/configatron_test.rb +0 -5
- data/test/test_helper.rb +0 -15
data/lib/configatron/store.rb
CHANGED
@@ -1,68 +1,94 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
class Configatron
|
4
|
-
class Store
|
4
|
+
class Store < BasicObject
|
5
5
|
extend ::Forwardable
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@attributes
|
7
|
+
def initialize(root_store, name='configatron', attributes={}, path=[])
|
8
|
+
@root_store = root_store
|
9
|
+
@name = name
|
10
|
+
@attributes = attributes
|
11
|
+
|
12
|
+
# We could derive @name from @path, though this would break
|
13
|
+
# backwards-compatibility.
|
14
|
+
@path = path
|
15
|
+
|
16
|
+
@cow = root_store.__cow
|
17
|
+
end
|
18
|
+
|
19
|
+
def clone
|
20
|
+
Store.new(
|
21
|
+
@root_store,
|
22
|
+
@name,
|
23
|
+
@attributes.clone,
|
24
|
+
@path
|
25
|
+
)
|
11
26
|
end
|
12
27
|
|
13
|
-
def
|
14
|
-
@
|
28
|
+
def __cow
|
29
|
+
@cow
|
15
30
|
end
|
16
31
|
|
17
|
-
def
|
18
|
-
|
32
|
+
def __cow_clone
|
33
|
+
# A temp has started since the last time this was written
|
34
|
+
if @root_store.__cow != @cow
|
35
|
+
self.clone
|
36
|
+
else
|
37
|
+
self
|
38
|
+
end
|
19
39
|
end
|
20
40
|
|
21
41
|
def [](key)
|
22
42
|
val = fetch(key.to_sym) do
|
23
|
-
if @
|
24
|
-
raise Configatron::UndefinedKeyError.new("Key
|
43
|
+
if @root_store.locked?
|
44
|
+
::Kernel.raise ::Configatron::UndefinedKeyError.new("Key not found: #{key} (for locked #{self})")
|
25
45
|
end
|
26
|
-
::Configatron::Store.new
|
46
|
+
::Configatron::Store.new(@root_store, "#{@name}.#{key}", {}, @path + [key])
|
27
47
|
end
|
28
48
|
return val
|
29
49
|
end
|
30
50
|
|
31
51
|
def store(key, value)
|
32
|
-
if @
|
33
|
-
raise Configatron::LockedError.new("
|
52
|
+
if @root_store.locked?
|
53
|
+
::Kernel.raise ::Configatron::LockedError.new("Cannot set key #{key} for locked #{self}")
|
54
|
+
end
|
55
|
+
|
56
|
+
key = key.to_sym
|
57
|
+
if @root_store.__cow != @cow
|
58
|
+
copy = @root_store.__cow_path(@path)
|
59
|
+
# Cow should now match, so this won't recurse. (Note this is
|
60
|
+
# not particularly thread-safe.)
|
61
|
+
copy.store(key, value)
|
62
|
+
else
|
63
|
+
@attributes[key] = value
|
34
64
|
end
|
35
|
-
@attributes[key.to_sym] = value
|
36
65
|
end
|
37
66
|
|
38
67
|
def fetch(key, default_value = nil, &block)
|
39
|
-
|
40
|
-
if
|
41
|
-
|
68
|
+
key = key.to_sym
|
69
|
+
if key?(key)
|
70
|
+
val = @attributes[key]
|
71
|
+
else
|
72
|
+
if block
|
42
73
|
val = block.call
|
43
74
|
elsif default_value
|
44
75
|
val = default_value
|
45
76
|
end
|
46
77
|
store(key, val)
|
47
78
|
end
|
48
|
-
if
|
79
|
+
if ::Configatron::Proc === val
|
49
80
|
val = val.call
|
50
81
|
end
|
51
82
|
return val
|
52
83
|
end
|
53
84
|
|
54
|
-
def nil?
|
55
|
-
@attributes.empty?
|
56
|
-
end
|
57
|
-
|
58
85
|
def key?(key)
|
59
|
-
|
60
|
-
!val.is_a?(Configatron::Store)
|
86
|
+
@attributes.key?(key.to_sym)
|
61
87
|
end
|
62
88
|
|
63
89
|
def configure_from_hash(hash)
|
64
90
|
hash.each do |key, value|
|
65
|
-
if value
|
91
|
+
if ::Hash === value
|
66
92
|
self[key].configure_from_hash(value)
|
67
93
|
else
|
68
94
|
store(key, value)
|
@@ -70,22 +96,58 @@ class Configatron
|
|
70
96
|
end
|
71
97
|
end
|
72
98
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
99
|
+
def to_s
|
100
|
+
@name
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect
|
104
|
+
f_out = []
|
105
|
+
@attributes.each do |k, v|
|
106
|
+
if ::Configatron::Store === v
|
107
|
+
v.inspect.each_line do |line|
|
108
|
+
if line.match(/\n/)
|
109
|
+
line.each_line do |l|
|
110
|
+
l.strip!
|
111
|
+
f_out << l
|
112
|
+
end
|
113
|
+
else
|
114
|
+
line.strip!
|
115
|
+
f_out << line
|
116
|
+
end
|
117
|
+
end
|
118
|
+
else
|
119
|
+
f_out << "#{@name}.#{k} = #{v.inspect}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
f_out.compact.sort.join("\n")
|
123
|
+
end
|
124
|
+
|
125
|
+
def method_missing(name, *args, &block)
|
126
|
+
do_lookup(name, *args, &block)
|
77
127
|
end
|
78
128
|
|
79
|
-
def
|
80
|
-
@
|
129
|
+
def to_h
|
130
|
+
@attributes.each_with_object({}) do |(k, v), h|
|
131
|
+
v = v.call if ::Configatron::Proc === v
|
132
|
+
h[k] = Store === v ? v.to_h : v
|
133
|
+
end
|
81
134
|
end
|
82
135
|
|
83
|
-
|
84
|
-
|
136
|
+
# So that puts works (it expects the object to respond to to_ary)
|
137
|
+
def to_ary
|
138
|
+
nil
|
85
139
|
end
|
86
140
|
|
87
|
-
|
88
|
-
|
141
|
+
# So that we keep backward-compatibility in case people are using nil? to check
|
142
|
+
# configatron settings:
|
143
|
+
def nil?
|
144
|
+
false
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def do_lookup(name, *args, &block)
|
150
|
+
if block
|
89
151
|
yield self[name]
|
90
152
|
else
|
91
153
|
name = name.to_s
|
@@ -96,7 +158,7 @@ class Configatron
|
|
96
158
|
if self.has_key?(key)
|
97
159
|
return self[key]
|
98
160
|
else
|
99
|
-
raise Configatron::UndefinedKeyError.new($1)
|
161
|
+
::Kernel.raise ::Configatron::UndefinedKeyError.new($1)
|
100
162
|
end
|
101
163
|
else
|
102
164
|
return self[name]
|
@@ -104,38 +166,13 @@ class Configatron
|
|
104
166
|
end
|
105
167
|
end
|
106
168
|
|
107
|
-
def inspect(name = 'configatron')
|
108
|
-
f_out = []
|
109
|
-
@attributes.each do |k, v|
|
110
|
-
if v.is_a?(Configatron::Store)
|
111
|
-
v.inspect("#{name}.#{k}").each_line do |line|
|
112
|
-
if line.match(/\n/)
|
113
|
-
line.each_line do |l|
|
114
|
-
l.strip!
|
115
|
-
f_out << l
|
116
|
-
end
|
117
|
-
else
|
118
|
-
line.strip!
|
119
|
-
f_out << line
|
120
|
-
end
|
121
|
-
end
|
122
|
-
else
|
123
|
-
f_out << "#{name}.#{k} = #{v.inspect}"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
f_out.compact.sort.join("\n")
|
127
|
-
end
|
128
|
-
|
129
169
|
alias :[]= :store
|
130
|
-
alias :blank? :nil?
|
131
170
|
alias :has_key? :key?
|
171
|
+
alias :to_hash :to_h
|
132
172
|
|
133
173
|
def_delegator :@attributes, :values
|
134
174
|
def_delegator :@attributes, :keys
|
135
175
|
def_delegator :@attributes, :each
|
136
|
-
def_delegator :@attributes, :empty?
|
137
|
-
def_delegator :@attributes, :to_h
|
138
|
-
def_delegator :@attributes, :to_hash
|
139
176
|
def_delegator :@attributes, :delete
|
140
177
|
# def_delegator :@attributes, :fetch
|
141
178
|
# def_delegator :@attributes, :has_key?
|
data/lib/configatron/version.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'configatron'
|
2
|
-
Configatron::Rails.init
|
2
|
+
Configatron::Integrations::Rails.init
|
data/test/_lib.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
ENV['MT_NO_EXPECTATIONS'] = 'true'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'minitest/spec'
|
7
|
+
require 'mocha/setup'
|
8
|
+
|
9
|
+
require 'configatron'
|
10
|
+
|
11
|
+
module Critic
|
12
|
+
class Test < ::MiniTest::Spec
|
13
|
+
def setup
|
14
|
+
# Put any stubs here that you want to apply globally
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
class Critic::Functional::ConfigatronTest < Critic::Functional::Test
|
4
|
+
before do
|
5
|
+
@kernel = Configatron::RootStore.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'temp' do
|
9
|
+
before do
|
10
|
+
@kernel.a = 'A'
|
11
|
+
@kernel.b = 'B'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows for temporary setting of values' do
|
15
|
+
assert_equal('A', @kernel.a)
|
16
|
+
assert_equal('B', @kernel.b)
|
17
|
+
@kernel.temp do
|
18
|
+
@kernel.a = 'AA'
|
19
|
+
@kernel.c = 'C'
|
20
|
+
assert_equal('AA', @kernel.a)
|
21
|
+
assert_equal('B', @kernel.b)
|
22
|
+
assert_equal('C', @kernel.c)
|
23
|
+
end
|
24
|
+
assert_equal('A', @kernel.a)
|
25
|
+
assert_equal('B', @kernel.b)
|
26
|
+
assert_equal(false, @kernel.key?(:c))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'nested' do
|
30
|
+
@kernel.foo.bar = 'original'
|
31
|
+
@kernel.temp do
|
32
|
+
@kernel.foo.bar = 'temp'
|
33
|
+
assert_equal('temp', @kernel.foo.bar)
|
34
|
+
end
|
35
|
+
assert_equal('original', @kernel.foo.bar)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'cleans up after an exception' do
|
39
|
+
@kernel.foo.bar = 'original'
|
40
|
+
|
41
|
+
assert_raises(RuntimeError) do
|
42
|
+
@kernel.temp do
|
43
|
+
@kernel.foo.bar = 'temp'
|
44
|
+
raise RuntimeError.new('error')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_equal('original', @kernel.foo.bar)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'restores locking state' do
|
52
|
+
@kernel.lock!
|
53
|
+
@kernel.temp do
|
54
|
+
@kernel.unlock!
|
55
|
+
end
|
56
|
+
assert(@kernel.locked?)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'start/end' do
|
60
|
+
it 'allows for temporary setting of values' do
|
61
|
+
assert_equal('A', @kernel.a)
|
62
|
+
assert_equal('B', @kernel.b)
|
63
|
+
@kernel.temp_start
|
64
|
+
@kernel.a = 'AA'
|
65
|
+
@kernel.c = 'C'
|
66
|
+
assert_equal('AA', @kernel.a)
|
67
|
+
assert_equal('B', @kernel.b)
|
68
|
+
assert_equal('C', @kernel.c)
|
69
|
+
@kernel.temp_end
|
70
|
+
assert_equal('A', @kernel.a)
|
71
|
+
assert_equal('B', @kernel.b)
|
72
|
+
assert_equal(false, @kernel.key?(:c))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'lock!' do
|
78
|
+
before do
|
79
|
+
@kernel.a.b.c.d = 'DD'
|
80
|
+
@kernel.lock!
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'raises an error when accessing non-existing values' do
|
84
|
+
assert @kernel.a != nil
|
85
|
+
assert @kernel.a.b != nil
|
86
|
+
assert @kernel.a.b.c != nil
|
87
|
+
assert_equal('DD', @kernel.a.b.c.d)
|
88
|
+
assert_raises(Configatron::UndefinedKeyError) do
|
89
|
+
@kernel.unknown
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'responds to nil? for backward compatibility' do
|
94
|
+
refute_nil @kernel.a
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'raises an error when trying to set a non-existing key' do
|
98
|
+
assert_raises(Configatron::LockedError) do
|
99
|
+
@kernel.unknown = 'known'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'locks during the block argument' do
|
104
|
+
@kernel.unlock!
|
105
|
+
|
106
|
+
@kernel.lock! do
|
107
|
+
assert(@kernel.locked?)
|
108
|
+
end
|
109
|
+
|
110
|
+
assert(!@kernel.locked?)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'executes a block argument' do
|
114
|
+
a = 1
|
115
|
+
@kernel.lock! do
|
116
|
+
a = 2
|
117
|
+
end
|
118
|
+
assert_equal(2, a)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'name' do
|
123
|
+
it 'assigns an appropriate nested name' do
|
124
|
+
name = @kernel.foo.bar.baz.to_s
|
125
|
+
assert_equal(name, 'configatron.foo.bar.baz')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe 'puts' do
|
130
|
+
it 'does not cause an exception' do
|
131
|
+
puts @kernel
|
132
|
+
puts @kernel.hi
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe 'private methods on kernel' do
|
137
|
+
it 'can be accessed through method accessors' do
|
138
|
+
@kernel.catch = 'hi'
|
139
|
+
@kernel.foo.catch = 'hi'
|
140
|
+
|
141
|
+
assert_equal('hi', @kernel.catch)
|
142
|
+
assert_equal('hi', @kernel.foo.catch)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'to_h and to_hash' do
|
147
|
+
before do
|
148
|
+
@kernel.a = 1
|
149
|
+
@kernel.b.c = Configatron::Delayed.new{ @kernel.a + 3 }
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'returns a hash representation' do
|
153
|
+
expected_hash = { a: 1, b: { c: 4 } }
|
154
|
+
assert_equal(expected_hash, @kernel.to_h)
|
155
|
+
assert_equal(expected_hash, @kernel.to_hash)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'nil value' do
|
160
|
+
it 'remembers a nil value' do
|
161
|
+
@kernel.a = nil
|
162
|
+
assert_equal(nil, @kernel.a)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|