adhearsion-loquacious 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+
2
+ module Loquacious
3
+
4
+ # Represents an undefined configuration value. An undefined value is
5
+ # assigned to each configuration propery by default. Any method can be
6
+ # invoked on an undefined value, and a warning message will be printed to
7
+ # the IO stream (defaulting to $stderr).
8
+ #
9
+ # The purpose of this class is to provide the user with a helpful message
10
+ # that the configuration values they are trying to use have not been setup
11
+ # correctly.
12
+ #
13
+ class Undefined
14
+
15
+ instance_methods(true).each do |m|
16
+ next if m[::Loquacious::KEEPERS]
17
+ undef_method m
18
+ end
19
+ private_instance_methods(true).each do |m|
20
+ next if m[::Loquacious::KEEPERS]
21
+ undef_method m
22
+ end
23
+ Kernel.methods.each do |m|
24
+ next if m[::Loquacious::KEEPERS]
25
+ module_eval <<-CODE
26
+ def #{m}( *args, &block )
27
+ self.method_missing('#{m}', *args, &block)
28
+ end
29
+ CODE
30
+ end
31
+ undef_method :method_missing rescue nil
32
+
33
+ @io = $stderr
34
+ @first_time = true
35
+
36
+ class << self
37
+ attr_accessor :io
38
+
39
+ # Write a warning message to the Undefined class IO stream. By default,
40
+ # this IO stream is set to the Ruby $stderr output.
41
+ #
42
+ def warn( key )
43
+ if @first_time
44
+ @io.puts <<-__
45
+ ---------------------------------------------------------------------------
46
+ The Loquacious configuration system has detected that one or moe
47
+ settings have an undefined value. An attempt is being made to reference
48
+ sub-properties of these undefined settings. Messages will follow containing
49
+ information about the undefined properties.
50
+ ---------------------------------------------------------------------------
51
+ __
52
+ @first_time = false
53
+ end
54
+
55
+ @io.puts "Access to undefined value #{key.first.inspect}: #{key.join('.')}"
56
+ end
57
+ end
58
+
59
+ # Creates a new undefined value returned from the lookup _key_ in some
60
+ # configuration object. The _key_ is used to alert the user where the
61
+ # undefined value came from.
62
+ #
63
+ def initialize( key )
64
+ @key = Kernel.Array(key)
65
+ end
66
+
67
+ # An undefined value acts like a +nil+ in that it has no value of its own.
68
+ # This method always returns +true+.
69
+ #
70
+ def nil?() true; end
71
+
72
+ # We can respond to any method except :call. The call method is reserved
73
+ # for Procs and lambdas, and it is used internally by loquacious for lazy
74
+ # evaluation of configuration parameters.
75
+ #
76
+ def respond_to_missing?( id, priv = false ) id != :call; end
77
+
78
+ # For every method invoked on an undefined object, generate a warning
79
+ # message describing the undefined value and the method that was called.
80
+ #
81
+ # Returns a new undefined object with the most recent method included in
82
+ # the key name.
83
+ #
84
+ def method_missing( method, *args, &block )
85
+ key = @key.dup << method.to_s
86
+ Undefined.warn key
87
+ return Undefined.new(key)
88
+ end
89
+
90
+ end # class Undefined
91
+ end # module Loquacious
92
+
@@ -0,0 +1,14 @@
1
+ module Loquacious
2
+ class Utility
3
+ class << self
4
+ # Returns the variable name to use for a value to be picked from ENV
5
+ #
6
+ def env_var_name(name, config)
7
+ parent_list = config.parent_list
8
+ parent_part = parent_list.empty? ? nil : parent_list.join("_")
9
+ key_name = name.to_s.split(".").last
10
+ [::Loquacious.env_prefix, parent_part, config.__name, key_name].compact.join("_").upcase
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "loquacious"
5
+ s.version = "1.9.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Tim Pease"]
9
+ s.date = "2012-01-16"
10
+ s.description = "Descriptive configuration files for Ruby written in Ruby.\n\nLoquacious provides a very open configuration system written in ruby and\ndescriptions for each configuration attribute. The attributes and descriptions\ncan be iterated over allowing for helpful information about those attributes to\nbe displayed to the user.\n\nIn the simple case we have a file something like\n\n Loquacious.configuration_for('app') {\n name 'value', :desc => \"Defines the name\"\n foo 'bar', :desc => \"FooBar\"\n id 42, :desc => \"Ara T. Howard\"\n }\n\nWhich can be loaded via the standard Ruby loading mechanisms\n\n Kernel.load 'config/app.rb'\n\nThe attributes and their descriptions can be printed by using a Help object\n\n help = Loquacious.help_for('app')\n help.show :values => true # show the values for the attributes, too\n\nDescriptions are optional, and configurations can be nested arbitrarily deep.\n\n Loquacious.configuration_for('nested') {\n desc \"The outermost level\"\n a {\n desc \"One more level in\"\n b {\n desc \"Finally, a real value\"\n c 'value'\n }\n }\n }\n\n config = Loquacious.configuration_for('nested')\n\n p config.a.b.c #=> \"value\"\n\nAnd as you can see, descriptions can either be given inline after the value or\nthey can appear above the attribute and value on their own line."
11
+ s.email = "tim.pease@gmail.com"
12
+ s.extra_rdoc_files = ["History.txt", "README.rdoc", "lib/.loquacious.rb.swp", "lib/loquacious/.configuration.rb.swp"]
13
+ s.files = [".Rakefile.swp", ".gitignore", "History.txt", "README.rdoc", "Rakefile", "examples/gutters.rb", "examples/nested.rb", "examples/simple.rb", "lib/.loquacious.rb.swp", "lib/loquacious.rb", "lib/loquacious/.configuration.rb.swp", "lib/loquacious/configuration.rb", "lib/loquacious/configuration/help.rb", "lib/loquacious/configuration/iterator.rb", "lib/loquacious/core_ext/string.rb", "lib/loquacious/undefined.rb", "spec/configuration_spec.rb", "spec/help_spec.rb", "spec/iterator_spec.rb", "spec/loquacious_spec.rb", "spec/spec_helper.rb", "spec/string_spec.rb", "version.txt"]
14
+ s.homepage = "http://rubygems.org/gems/loquacious"
15
+ s.rdoc_options = ["--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "loquacious"
18
+ s.rubygems_version = "1.8.10"
19
+ s.summary = "Descriptive configuration files for Ruby written in Ruby."
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_development_dependency(%q<rspec>, ["~> 2.6"])
26
+ else
27
+ s.add_dependency(%q<rspec>, ["~> 2.6"])
28
+ end
29
+ else
30
+ s.add_dependency(%q<rspec>, ["~> 2.6"])
31
+ end
32
+ end
@@ -0,0 +1,513 @@
1
+
2
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
3
+
4
+ describe Loquacious::Configuration do
5
+ before(:each) do
6
+ @obj = Loquacious::Configuration.new
7
+ end
8
+
9
+ it 'should initialize from a block' do
10
+ obj = Loquacious::Configuration.new {
11
+ first 'foo'
12
+ second 'bar'
13
+ }
14
+ obj.first.eql?('foo').should be_true
15
+ obj.second.eql?('bar').should be_true
16
+ obj.third.kind_of?(Loquacious::Undefined).should be_true
17
+ end
18
+
19
+ it 'should respond to any method' do
20
+ @obj.first.kind_of?(Loquacious::Undefined).should be_true
21
+ @obj.first = 'foo'
22
+ @obj.first.eql?('foo').should be_true
23
+
24
+ @obj.second = 'bar'
25
+ @obj.second.eql?('bar').should be_true
26
+ end
27
+
28
+ it 'should deine attribute accessors when first used' do
29
+ @obj.respond_to?(:foo).should be_false
30
+ @obj.respond_to?(:foo=).should be_false
31
+
32
+ @obj.foo
33
+ @obj.respond_to?(:foo).should be_true
34
+ @obj.respond_to?(:foo=).should be_true
35
+ end
36
+
37
+ it 'should provide a hash object for storing method descriptions' do
38
+ h = @obj.__desc
39
+ @obj.__desc.should equal(h)
40
+ end
41
+
42
+ it 'should allow attributes to be assigned hash values' do
43
+ cfg = Loquacious::Configuration.new {
44
+ hash({:one => 1})
45
+ }
46
+ cfg.hash.eql?({:one => 1}).should be_true
47
+ end
48
+
49
+ it 'should provide hash accessor notation for attributes' do
50
+ cfg = Loquacious::Configuration.new {
51
+ one 1
52
+ two 2
53
+ three 3
54
+ }
55
+
56
+ cfg['one'].eql?(1).should be_true
57
+ cfg[:two].eql?(2).should be_true
58
+ cfg['three'].eql?(3).should be_true
59
+
60
+ cfg[:four].kind_of?(Loquacious::Undefined).should be_true
61
+ cfg.four = 4
62
+ cfg[:four].eql?(4).should be_true
63
+
64
+ cfg[:five] = 5
65
+ cfg.five.eql?(5).should be_true
66
+ cfg[:five].eql?(5).should be_true
67
+ end
68
+
69
+ it 'should allow Kernel methods to be treated as configuration attributes' do
70
+ cfg = Loquacious::Configuration.new {
71
+ fork 'spoon knife spork'
72
+ split 'join'
73
+ raise 'double down'
74
+ puts 'not what you think'
75
+ }
76
+
77
+ cfg['fork'].eql?('spoon knife spork').should be_true
78
+ cfg['split'].eql?('join').should be_true
79
+ cfg['raise'].eql?('double down').should be_true
80
+ cfg['puts'].eql?('not what you think').should be_true
81
+
82
+ cfg[:fork].eql?('spoon knife spork').should be_true
83
+ cfg[:split].eql?('join').should be_true
84
+ cfg[:raise].eql?('double down').should be_true
85
+ cfg[:puts].eql?('not what you think').should be_true
86
+
87
+ cfg.fork.eql?('spoon knife spork').should be_true
88
+ cfg.split.eql?('join').should be_true
89
+ cfg.raise.eql?('double down').should be_true
90
+ cfg.puts.eql?('not what you think').should be_true
91
+ end
92
+
93
+ it 'should not be affected by loading other modules like timeout' do
94
+ require 'timeout'
95
+ Loquacious.remove :timeout
96
+ cfg = Loquacious::Configuration.new {
97
+ timeout 10
98
+ foo 'bar'
99
+ baz 'buz'
100
+ }
101
+ cfg.timeout.eql?(10).should be_true
102
+ cfg.foo.eql?('bar').should be_true
103
+ cfg.baz.eql?('buz').should be_true
104
+ end
105
+
106
+ it 'should evaluate Proc objects when fetching values' do
107
+ obj = Loquacious::Configuration.new {
108
+ first 'foo'
109
+ second 'bar'
110
+ }
111
+
112
+ obj.third = Proc.new { obj.first + obj.second }
113
+ obj.third.eql?('foobar').should be_true
114
+
115
+ obj.second = 'baz'
116
+ obj.third.eql?('foobaz').should be_true
117
+
118
+ obj.first = 'Hello '
119
+ obj.second = 'World!'
120
+ obj.third.eql?('Hello World!').should be_true
121
+ end
122
+
123
+ it 'should return a value when evaluating inside the DSL' do
124
+ obj = Loquacious::Configuration.new {
125
+ first 'foo'
126
+ second {
127
+ bar nil
128
+ }
129
+ }
130
+
131
+ obj.first.eql?('foo').should be_true
132
+ obj.second.bar.eql?(nil).should be_true
133
+
134
+ Loquacious::Configuration::DSL.evaluate(:config => obj) {
135
+ first 'bar'
136
+ second.bar 'no longer nil'
137
+ }
138
+
139
+ obj.first.eql?('bar').should be_true
140
+ obj.second.bar.eql?('no longer nil').should be_true
141
+ end
142
+
143
+ it 'should not delete descriptions' do
144
+ obj = Loquacious::Configuration.new {
145
+ first 'foo', :desc => 'the first value'
146
+
147
+ desc 'the second value'
148
+ second {
149
+ bar nil, :desc => 'time to go drinking'
150
+ }
151
+ }
152
+
153
+ obj.first.eql?('foo').should be_true
154
+ obj.second.bar.eql?(nil).should be_true
155
+
156
+ obj.__desc[:first].should be == 'the first value'
157
+ obj.__desc[:second].should be == 'the second value'
158
+ obj.second.__desc[:bar].should be == 'time to go drinking'
159
+
160
+ Loquacious::Configuration::DSL.evaluate(:config => obj) {
161
+ first 'bar'
162
+ second.bar 'no longer nil'
163
+ }
164
+
165
+ obj.first.eql?('bar').should be_true
166
+ obj.second.bar.eql?('no longer nil').should be_true
167
+
168
+ obj.__desc[:first].should be == 'the first value'
169
+ obj.__desc[:second].should be == 'the second value'
170
+ obj.second.__desc[:bar].should be == 'time to go drinking'
171
+ end
172
+
173
+ # -----------------------------------------------------------------------
174
+ describe 'when merging' do
175
+ before :each do
176
+ Loquacious::Configuration.instance_variable_get(:@table).clear
177
+ end
178
+
179
+ it 'should merge the contents of another Configuration' do
180
+ other = Loquacious::Configuration.new {
181
+ first 'foo', :desc => 'foo method'
182
+ second 'bar', :desc => 'bar method'
183
+ }
184
+
185
+ @obj.first.kind_of?(Loquacious::Undefined).should be_true
186
+ @obj.second.kind_of?(Loquacious::Undefined).should be_true
187
+ @obj.__desc.should be == {:first => nil, :second => nil}
188
+
189
+ @obj.merge! other
190
+ @obj.first.eql?('foo').should be_true
191
+ @obj.second.eql?('bar').should be_true
192
+ @obj.__desc.should be == {
193
+ :first => 'foo method',
194
+ :second => 'bar method'
195
+ }
196
+ end
197
+
198
+ it 'should recursively merge nested Configuration' do
199
+ other = Loquacious::Configuration.new {
200
+ first 'foo', :desc => 'foo method'
201
+ second 'bar', :desc => 'bar method'
202
+
203
+ desc 'the third group'
204
+ third {
205
+ answer 42, :desc => 'life the universe and everything'
206
+ }
207
+ }
208
+
209
+ @obj = Loquacious::Configuration.new {
210
+ third {
211
+ question '?', :desc => 'perhaps you do not understand'
212
+ }
213
+ }
214
+
215
+ @obj.merge! other
216
+
217
+ @obj.first.eql?('foo').should be_true
218
+ @obj.second.eql?('bar').should be_true
219
+ @obj.third.question.eql?('?').should be_true
220
+ @obj.third.answer.eql?(42).should be_true
221
+
222
+ @obj.__desc.should be == {
223
+ :first => 'foo method',
224
+ :second => 'bar method',
225
+ :third => 'the third group'
226
+ }
227
+ @obj.third.__desc.should be == {
228
+ :question => 'perhaps you do not understand',
229
+ :answer => 'life the universe and everything'
230
+ }
231
+ end
232
+
233
+ it 'should raise an error when merging with an unknown object' do
234
+ lambda {@obj.merge! 'foo'}.
235
+ should raise_error(Loquacious::Configuration::Error, "can only merge another Configuration")
236
+ end
237
+ end
238
+
239
+ # -----------------------------------------------------------------------
240
+ describe 'when working with descriptions' do
241
+
242
+ it 'should consume leading whitespace' do
243
+ other = Loquacious::Configuration.new {
244
+ desc <<-STR
245
+ This is the first thing we are defining in this config.
246
+ It has a multiline comment.
247
+ STR
248
+ first 'foo'
249
+ second 'bar', :desc => "bar method\n also a multiline comment"
250
+ }
251
+
252
+ other.__desc[:first].should be == "This is the first thing we are defining in this config.\nIt has a multiline comment."
253
+ other.__desc[:second].should be == "bar method\nalso a multiline comment"
254
+ end
255
+
256
+ it 'should leave whitespace after a gutter marker' do
257
+ other = Loquacious::Configuration.new {
258
+ desc <<-STR
259
+ | This is the first thing we are defining in this config.
260
+ | It has a multiline comment.
261
+ STR
262
+ first 'foo'
263
+
264
+ desc <<-DESC
265
+ This is a short explanation
266
+
267
+ Example:
268
+ | do this then that
269
+ | followed by this line
270
+ DESC
271
+ second 'bar'
272
+ }
273
+
274
+ other.__desc[:first].should be == " This is the first thing we are defining in this config.\n It has a multiline comment."
275
+ other.__desc[:second].should be == "This is a short explanation\n\nExample:\n do this then that\n followed by this line"
276
+ end
277
+ end
278
+
279
+ # -----------------------------------------------------------------------
280
+ describe 'when working with defaults' do
281
+ before :each do
282
+ Loquacious::Configuration.instance_variable_get(:@table).clear
283
+ end
284
+
285
+ it 'returns default values when no other value exists' do
286
+ Loquacious::Configuration.defaults_for('test') {
287
+ first 'foo', :desc => 'the first value'
288
+ desc 'the second value'
289
+ second {
290
+ bar nil, :desc => 'time to go drinking'
291
+ }
292
+ }
293
+
294
+ c = Loquacious::Configuration.for 'test'
295
+ c.first.eql?('foo').should be_true
296
+ c.second.bar.eql?(nil).should be_true
297
+ end
298
+
299
+ it 'does not overwrite existing configuration values' do
300
+ c = Loquacious::Configuration.for('test') {
301
+ first 1
302
+ third 3
303
+ }
304
+
305
+ Loquacious::Configuration.defaults_for('test') {
306
+ first 'foo', :desc => 'the first value'
307
+ desc 'the second value'
308
+ second {
309
+ bar nil, :desc => 'time to go drinking'
310
+ }
311
+ }
312
+
313
+ c.first.eql?(1).should be_true
314
+ c.third.eql?(3).should be_true
315
+ c.second.bar.eql?(nil).should be_true
316
+
317
+ c.__desc[:first].should be == 'the first value'
318
+ c.__desc[:second].should be == 'the second value'
319
+ c.second.__desc[:bar].should be == 'time to go drinking'
320
+ c.__desc[:third].should be_nil
321
+ end
322
+
323
+ it 'does not overwrite nested configuration values' do
324
+ c = Loquacious::Configuration.for('test') {
325
+ first 1
326
+ second {
327
+ bar 'pub'
328
+ baz {
329
+ buz 'random text'
330
+ boo 'who'
331
+ }
332
+ }
333
+ third 3
334
+ }
335
+
336
+ Loquacious::Configuration.defaults_for('test') {
337
+ first 'foo', :desc => 'the first value'
338
+ desc 'the second value'
339
+ second {
340
+ bar 'h-bar', :desc => 'time to go drinking'
341
+ desc 'getting weird'
342
+ baz {
343
+ buz 'buz', :desc => 'post drinking feeling'
344
+ boo nil, :desc => 'no need to cry about it'
345
+ }
346
+ }
347
+ }
348
+
349
+ c.first.eql?(1).should be_true
350
+ c.third.eql?(3).should be_true
351
+ c.second.bar.eql?('pub').should be_true
352
+ c.second.baz.buz.eql?('random text').should be_true
353
+ c.second.baz.boo.eql?('who').should be_true
354
+
355
+ c.second.bar = Loquacious::Undefined.new('second.bar')
356
+ c.second.bar.eql?('h-bar').should be_true
357
+
358
+ c.__desc[:first].should be == 'the first value'
359
+ c.__desc[:second].should be == 'the second value'
360
+ c.second.__desc[:bar].should be == 'time to go drinking'
361
+ c.second.__desc[:baz].should be == 'getting weird'
362
+ c.second.baz.__desc[:buz].should be == 'post drinking feeling'
363
+ c.second.baz.__desc[:boo].should be == 'no need to cry about it'
364
+ c.__desc[:third].should be_nil
365
+ end
366
+
367
+ it 'supports differing default type' do
368
+ c = Loquacious::Configuration.for('test') {
369
+ first 1
370
+ second {
371
+ bar 'pub'
372
+ desc 'overwrite me'
373
+ baz {
374
+ buz 'random text'
375
+ boo 'who'
376
+ }
377
+ }
378
+ third 3
379
+ }
380
+
381
+ Loquacious::Configuration.defaults_for('test') {
382
+ first 'foo', :desc => 'the first value'
383
+ desc 'the second value'
384
+ second {
385
+ bar 'h-bar', :desc => 'time to go drinking'
386
+ baz nil, :desc => 'deprecated'
387
+ }
388
+ }
389
+
390
+ c.second.baz.buz.eql?('random text').should be_true
391
+ c.second.baz.boo.eql?('who').should be_true
392
+
393
+ c.second.baz = Loquacious::Undefined.new('second.bar')
394
+ c.second.baz.eql?(nil).should be_true
395
+ c.second.__desc[:baz].should be == 'deprecated'
396
+ end
397
+
398
+ it 'properly handles Proc default values' do
399
+ c = Loquacious::Configuration.for('test') {
400
+ first 1
401
+ second {
402
+ bar 'pub'
403
+ }
404
+ third 3
405
+ }
406
+
407
+ Loquacious::Configuration.defaults_for('test') {
408
+ first 'foo', :desc => 'the first value'
409
+ desc 'the second value'
410
+ second {
411
+ bar 'h-bar', :desc => 'time to go drinking'
412
+ baz(Proc.new { c.third * 12 }, :desc => 'proc will be evaluated')
413
+ }
414
+ }
415
+
416
+ c.second.baz.eql?(36).should be_true
417
+ c.second.__desc[:baz].should be == 'proc will be evaluated'
418
+ end
419
+ end
420
+
421
+ # -----------------------------------------------------------------------
422
+ describe 'when converting to a hash' do
423
+ it "should do so recursively" do
424
+ c = Loquacious::Configuration.new {
425
+ first 1, :desc => 'one is the loneliest number'
426
+ second {
427
+ bar 'pub', :desc => 'where the magic happens'
428
+ desc 'overwrite me'
429
+ baz {
430
+ buz 'random text'
431
+ boo 'who'
432
+ }
433
+ }
434
+ third 3
435
+ }
436
+ c.to_hash.should == {
437
+ :first => 1,
438
+ :second => {
439
+ :bar => 'pub',
440
+ :baz => {
441
+ :buz => 'random text',
442
+ :boo => 'who'
443
+ }
444
+ },
445
+ :third => 3
446
+ }
447
+ end
448
+
449
+ it "just returns an empty hash for an empty configuration" do
450
+ c = Loquacious::Configuration.new { }
451
+ c.to_hash.should == {}
452
+ end
453
+ end
454
+
455
+ # Added tests
456
+ describe "added features for ENV configuration" do
457
+ before(:all) do
458
+ Loquacious.env_config = true
459
+ end
460
+ after(:all) do
461
+ Loquacious.env_config = false
462
+ end
463
+
464
+ let(:obj) {
465
+ Loquacious.configuration_for('app') {
466
+ name :testing, :desc => "Defines the name", :transform => Proc.new{|arg| arg.to_sym }
467
+ foo 'bar', :desc => "FooBar"
468
+ id 42, :desc => "Ara T. Howard"
469
+ bar {
470
+ recur 'sive'
471
+ baz {
472
+ inner 'config'
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ it "sets the name for the created config" do
479
+ obj.__name.eql?("app").should be_true
480
+ end
481
+
482
+ it "sets the name for a nested object" do
483
+ obj.bar.__name.eql?("bar").should be_true
484
+ end
485
+
486
+ it "sets the parent name for a nested object" do
487
+ obj.bar.__parent.__name.eql?("app").should be_true
488
+ end
489
+
490
+ it "stores the transform for a configuration key" do
491
+ obj.__transforms[:name].is_a?(Proc).should be_true
492
+ end
493
+
494
+ it "overrides a value with the correct ENV value" do
495
+ ENV["LOQ_APP_FOO"] = "envbar"
496
+ obj.foo.eql?("envbar").should be_true
497
+ end
498
+
499
+ it "transforms the value using the provided lambda" do
500
+ ENV["LOQ_APP_NAME"] = "envname"
501
+ obj.name.eql?(:envname).should be_true
502
+ obj.name.is_a?(Symbol).should be_true
503
+ end
504
+
505
+ describe "#parent_list" do
506
+ it "returns the correct parent list for a configuration object" do
507
+ obj.bar.baz.parent_list.eql?(["app", "bar"]).should be_true
508
+ end
509
+ end
510
+
511
+ end#added features for ENV
512
+ end
513
+