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 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