conf 0.0.5 → 0.0.6
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/VERSION +1 -1
- data/conf.gemspec +1 -1
- data/lib/conf.rb +90 -62
- data/spec/conf_spec.rb +18 -2
- data/spec/spec.opts +1 -1
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/conf.gemspec
CHANGED
data/lib/conf.rb
CHANGED
@@ -2,10 +2,58 @@ class Conf
|
|
2
2
|
|
3
3
|
class InvalidKeyError < StandardError
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
class InvalidStateError < StandardError
|
7
7
|
end
|
8
8
|
|
9
|
+
module ConfigValue
|
10
|
+
def self.create(root, key, obj = Object.new)
|
11
|
+
begin
|
12
|
+
obj.extend(self)
|
13
|
+
obj.__setup__(root, key)
|
14
|
+
rescue TypeError
|
15
|
+
# can't extend numbers, false, nil etc.
|
16
|
+
end
|
17
|
+
|
18
|
+
obj
|
19
|
+
end
|
20
|
+
|
21
|
+
def __setup__(root, key)
|
22
|
+
@__root__ = root
|
23
|
+
@__key__ = key
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(meth, *args, &blk)
|
29
|
+
m = meth.to_s
|
30
|
+
if m =~ /^(\w+)=/ || args.size == 1
|
31
|
+
@__root__.check_lock
|
32
|
+
key = [@__key__, $1 || m].compact.join(".")
|
33
|
+
@__root__[key] = ConfigValue.create(@__root__, key, args.first)
|
34
|
+
else
|
35
|
+
key = [@__key__, m].compact.join(".")
|
36
|
+
|
37
|
+
obj = @__root__.data[key]
|
38
|
+
|
39
|
+
if obj.nil?
|
40
|
+
if @__root__.locked?
|
41
|
+
obj = @__root__.fetch(key) { raise Conf::InvalidKeyError, key }
|
42
|
+
else
|
43
|
+
obj = @__root__.data[key] = ConfigValue.create(@__root__, key)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if blk
|
48
|
+
@__root__.check_lock
|
49
|
+
obj.instance_eval(&blk)
|
50
|
+
end
|
51
|
+
|
52
|
+
obj
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end # ConfigValue
|
56
|
+
|
9
57
|
def self.configs
|
10
58
|
@configs ||= {}
|
11
59
|
end
|
@@ -17,12 +65,13 @@ class Conf
|
|
17
65
|
when Configuration, nil
|
18
66
|
# ok
|
19
67
|
else
|
20
|
-
raise TypeError,
|
68
|
+
raise TypeError,
|
69
|
+
"expected String, Symbol, Configuration or nil, got #{parent.inspect}:#{parent.class}"
|
21
70
|
end
|
22
71
|
|
23
72
|
conf = configs[name] ||= Configuration.new(parent)
|
24
|
-
|
25
73
|
conf.instance_eval(&blk)
|
74
|
+
|
26
75
|
conf.lock!
|
27
76
|
conf
|
28
77
|
end
|
@@ -32,15 +81,17 @@ class Conf
|
|
32
81
|
end
|
33
82
|
|
34
83
|
class Configuration
|
84
|
+
include ConfigValue
|
85
|
+
|
35
86
|
def initialize(parent = nil)
|
36
87
|
if parent and not parent.kind_of? self.class
|
37
88
|
raise TypeError, "expected #{self.class}, got #{parent.inspect}:#{parent.class}"
|
38
89
|
end
|
39
90
|
|
40
|
-
@parent
|
41
|
-
@data
|
42
|
-
@
|
43
|
-
@
|
91
|
+
@parent = parent
|
92
|
+
@data = {}
|
93
|
+
@locked = false
|
94
|
+
@__root__ = self
|
44
95
|
end
|
45
96
|
|
46
97
|
def key?(key)
|
@@ -50,92 +101,69 @@ class Conf
|
|
50
101
|
def lock!
|
51
102
|
@locked = true
|
52
103
|
end
|
53
|
-
|
104
|
+
|
54
105
|
def unlock!
|
55
106
|
@locked = false
|
56
107
|
end
|
57
|
-
|
108
|
+
|
109
|
+
def unlocked(&blk)
|
110
|
+
unlock!
|
111
|
+
yield
|
112
|
+
lock!
|
113
|
+
end
|
114
|
+
|
115
|
+
def check_lock
|
116
|
+
if locked?
|
117
|
+
raise InvalidStateError, "config is locked #{@data.keys.inspect}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
58
121
|
def edit(&blk)
|
59
122
|
edit!
|
60
123
|
instance_eval(&blk)
|
61
124
|
done!
|
62
125
|
end
|
63
|
-
|
126
|
+
|
64
127
|
def locked?
|
65
128
|
@locked
|
66
129
|
end
|
67
130
|
|
68
131
|
def section(start_key)
|
69
132
|
result = @parent ? @parent.section(start_key) : {}
|
133
|
+
rx = /^#{Regexp.escape(start_key).gsub("\\*", ".+?")}/
|
70
134
|
|
71
135
|
@data.each do |key, value|
|
72
|
-
result[key] = value if key =~
|
136
|
+
result[key] = value if key =~ rx and not value.instance_of? Object
|
73
137
|
end
|
74
138
|
|
75
139
|
result
|
76
140
|
end
|
77
141
|
|
78
|
-
protected
|
79
|
-
|
80
142
|
def data() @data end
|
81
143
|
|
82
|
-
def
|
83
|
-
|
84
|
-
val
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
def []=(key, value)
|
89
|
-
@data[expand_key(key)] = value
|
90
|
-
@current_nesting.clear
|
91
|
-
end
|
92
|
-
|
93
|
-
def expand_key(key)
|
94
|
-
[@current_nesting, key].flatten.compact.join "."
|
95
|
-
end
|
96
|
-
|
97
|
-
def method_missing(meth, *args, &blk)
|
98
|
-
m = meth.to_s
|
99
|
-
|
100
|
-
if m =~ /^(\w+)=/ || args.size == 1
|
101
|
-
check_lock
|
102
|
-
key = $1 || m
|
103
|
-
self[key] = args.first
|
104
|
-
elsif blk
|
105
|
-
check_lock
|
106
|
-
@current_nesting << m
|
107
|
-
instance_eval(&blk)
|
108
|
-
@current_nesting.pop
|
144
|
+
def fetch(key, &blk)
|
145
|
+
val = self[key]
|
146
|
+
if val.nil?
|
147
|
+
@data[key] = yield(key)
|
109
148
|
else
|
110
|
-
|
111
|
-
if obj != nil
|
112
|
-
@current_nesting.clear
|
113
|
-
obj
|
114
|
-
else
|
115
|
-
@current_nesting << m
|
116
|
-
validate_nesting if locked?
|
117
|
-
self
|
118
|
-
end
|
149
|
+
val
|
119
150
|
end
|
120
151
|
end
|
121
152
|
|
122
|
-
def validate_nesting
|
123
|
-
current = expand_key(nil)
|
124
|
-
match_proc = Proc.new { |key,_| key =~ /^#{Regexp.escape current}/ }
|
125
153
|
|
126
|
-
|
127
|
-
|
128
|
-
|
154
|
+
def [](key)
|
155
|
+
val = @data[key]
|
156
|
+
|
157
|
+
if val.nil?
|
158
|
+
@parent && @parent[key]
|
159
|
+
else
|
160
|
+
val
|
129
161
|
end
|
130
162
|
end
|
131
163
|
|
132
|
-
def
|
133
|
-
|
134
|
-
@current_nesting.clear
|
135
|
-
raise InvalidStateError, "config is locked"
|
136
|
-
end
|
164
|
+
def []=(key, value)
|
165
|
+
@data[key] = value
|
137
166
|
end
|
138
167
|
end
|
139
|
-
end
|
140
|
-
|
141
168
|
|
169
|
+
end
|
data/spec/conf_spec.rb
CHANGED
@@ -105,11 +105,27 @@ describe "Conf" do
|
|
105
105
|
foo.bla.baz 3
|
106
106
|
}.section("foo.bar").should == {"foo.bar.baz" => 1, "foo.bar.boo" => 2}
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
|
+
it "handles wildcards in section() string" do
|
110
|
+
Conf.define(:tmp) {
|
111
|
+
foo.bar.baz 1
|
112
|
+
foo.bar.boo 2
|
113
|
+
foo.bla.baz 3
|
114
|
+
}.section("foo.*.baz").should == {"foo.bar.baz" => 1, "foo.bla.baz" => 3}
|
115
|
+
end
|
116
|
+
|
109
117
|
it "merges parent data when fetching section" do
|
110
118
|
parent = Conf.define(:parent) { foo.bar.baz 1 }
|
111
119
|
child = Conf.define(:child, parent) { foo.bar.bah 2; }
|
112
|
-
|
120
|
+
|
113
121
|
child.section("foo.bar").should == {"foo.bar.baz" => 1, "foo.bar.bah" => 2}
|
114
122
|
end
|
123
|
+
|
124
|
+
it "should handle nesting under existing values" do
|
125
|
+
Conf.define(:tmp) do
|
126
|
+
foo "bar"
|
127
|
+
foo.bar "baz"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
115
131
|
end
|
data/spec/spec.opts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--color --backtrace
|
1
|
+
--color --backtrace --debugger
|