conf 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
data/conf.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{conf}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jari Bakken"]
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, "expected String, Symbol, Configuration or nil, got #{parent.inspect}:#{parent.class}"
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 = parent
41
- @data = {}
42
- @current_nesting = []
43
- @locked = false
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 =~ /^#{Regexp.escape start_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 [](key)
83
- k = expand_key(key)
84
- val = @data[k]
85
- val.nil? ? @parent && @parent[k] : val
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
- obj = self[m]
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
- unless @data.any?(&match_proc) || (@parent && @parent.data.any?(&match_proc))
127
- @current_nesting.clear
128
- raise InvalidKeyError, "no such key: #{current.inspect}"
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 check_lock
133
- if locked?
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
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 5
9
- version: 0.0.5
8
+ - 6
9
+ version: 0.0.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jari Bakken