Skip to content

Commit 58342de

Browse files
committed
a stab at wildcards
1 parent 5a4d5e6 commit 58342de

File tree

4 files changed

+224
-22
lines changed

4 files changed

+224
-22
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,14 @@ conf.collect { |key,value| value } # => [ 1, 2.0, :three, 'four' ]
121121
* defaults
122122
* merge configurations recursively
123123
* blank slate for DSL
124+
* wildcard * for chained usage: a.b.*.d
124125

125-
## Fancy usage
126+
## Application
126127

127128
* Dynamic settings by '[]' & '[]=' & 'self'
128129
* Multiple configuration files
129130
* Hierarchial configuration files
131+
* Validation: if a.b.*.d == true
130132

131133
## License
132134

lib/iqeo/configuration.rb

+58-13
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ def self.version
5959
#
6060
# Content should be in eval DSL format.
6161

62-
def self.read string
63-
conf = self.new
62+
def self.read string, options = {}
63+
conf = self.new nil, options
6464
conf.instance_eval string
6565
conf
6666
end
@@ -69,22 +69,31 @@ def self.read string
6969
#
7070
# Content should be in eval DSL format.
7171

72-
def self.load file
72+
def self.load file, options = {}
7373
return self.read file.respond_to?(:read) ? file.read : File.read(file)
7474
end
7575

76-
def self.new_defer_block_for_parent parent, &block
77-
conf = Configuration.new
76+
def self.new_defer_block_for_parent parent, options = {}, &block
77+
conf = Configuration.new nil, options
7878
conf._parent = parent
7979
if block_given? && block.arity > 0
8080
block.call(conf) # this is 'yield self' from the outside
8181
end
8282
conf
8383
end
8484

85-
attr_accessor :_parent, :_items
85+
OPTIONS = {
86+
:blankslate => true,
87+
:case_sensitive => true
88+
}
8689

87-
def initialize default = nil, &block
90+
attr_accessor :_parent, :_items, :_options
91+
92+
# todo: why can't :_parent= be protected ?
93+
#protected :_parent, :_items, :_items= #, :_get, :[], :_set, :[]=
94+
95+
def initialize default = nil, options = {}, &block
96+
_process_options options
8897
@_items = HashWithIndifferentAccess.new
8998
@_parent = nil
9099
_merge! default if default.kind_of?( Configuration )
@@ -105,11 +114,11 @@ def method_missing name, *values, &block
105114

106115
name = name.to_s.chomp('=')
107116

108-
if block_given? # block is a nested configuration
109-
if block.arity == 1 # yield DSL needs deferred block to set parent without binding
110-
return _set name, Configuration.new_defer_block_for_parent( self, &block )
117+
if block_given? # block is a nested configuration
118+
if block.arity == 1 # yield DSL needs deferred block to set parent without binding
119+
return _set name, Configuration.new_defer_block_for_parent( self, @_options, &block )
111120
else
112-
return _set name, Configuration.new( &block ) # eval DSL can set parent from block binding in initialize
121+
return _set name, Configuration.new( nil, @_options, &block ) # eval DSL can set parent from block binding in initialize
113122
end
114123
end
115124

@@ -161,9 +170,45 @@ def _merge other
161170
self.dup._merge! other
162171
end
163172

164-
# todo: why can't :_parent= be protected ?
173+
def _configurations
174+
@_items.values.select { |value| value.kind_of? Configuration }
175+
end
176+
177+
def _process_options options
178+
@_options = OPTIONS.merge options
179+
#_wipe if @_options[:blankslate] # todo: how to make blankslate optional ?
180+
end
181+
182+
# todo: method '*' for wildcard dir glob like selections eg top.*.bottom ?
183+
184+
def *
185+
ConfigurationDelegator.new _configurations
186+
end
187+
188+
end
165189

166-
protected :_parent, :_items, :_items=, :_get, :[], :_set, :[]=
190+
class ConfigurationDelegator # todo: inherit from < Blankslate ?
191+
192+
attr_reader :_confs
193+
194+
# protected :_confs
195+
196+
def initialize confs
197+
@_confs = confs
198+
end
199+
200+
def method_missing name, *values, &block
201+
return @_confs.send( name, *values, &block ) if @_confs.respond_to? name # @_confs methods are highest priority
202+
end
203+
#alias [] method_missing # so we don't have to deal with [ and 'key' separately ( see alias [] _get in Configuration )
204+
205+
def empty?
206+
@_confs.empty?
207+
end
208+
209+
def *
210+
ConfigurationDelegator.new( @_confs.inject([]) { |array,conf| array + conf._configurations } )
211+
end
167212

168213
end
169214

lib/iqeo/configuration/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Iqeo
2-
CONFIGURATION_VERSION = "1.0.1"
2+
CONFIGURATION_VERSION = "1.1.0.pre.0"
33
end

spec/configuration_spec.rb

+162-7
Original file line numberDiff line numberDiff line change
@@ -951,13 +951,168 @@ def nested_configuration_example conf
951951

952952
end # "v1.0"
953953

954-
#context 'v1.1' do
955-
#
956-
# context 'merge' do
957-
#
958-
# end
959-
#
960-
#end #v1.1
954+
def simple_config_1
955+
Configuration.new do
956+
alpha 1
957+
bravo 'one'
958+
charlie 1.0
959+
delta :one
960+
end
961+
end
962+
963+
def simple_config_1_example conf
964+
conf.should_not be_nil
965+
conf.alpha.should == 1 and conf.alpha.should be_a Fixnum
966+
conf.bravo.should == "one" and conf.bravo.should be_a String
967+
conf.charlie.should == 1.0 and conf.charlie.should be_a Float
968+
conf.delta.should == :one and conf.delta.should be_a Symbol
969+
end
970+
971+
def simple_config_2
972+
Configuration.new do
973+
echo 2
974+
foxtrot 'two'
975+
hotel 2.0
976+
india :two
977+
end
978+
end
979+
980+
def simple_config_2_example conf
981+
conf.should_not be_nil
982+
conf.echo.should == 2 and conf.echo.should be_a Fixnum
983+
conf.foxtrot.should == "two" and conf.foxtrot.should be_a String
984+
conf.hotel.should == 2.0 and conf.hotel.should be_a Float
985+
conf.india.should == :two and conf.india.should be_a Symbol
986+
conf['echo']
987+
#and conf[:echo].should be_a Fixnum
988+
989+
end
990+
991+
def simple_config_3
992+
Configuration.new do
993+
juliet 3
994+
kilo 'three'
995+
lima 3.0
996+
mike :three
997+
end
998+
end
999+
1000+
def simple_config_3_example conf
1001+
conf.should_not be_nil
1002+
conf.juliet.should == 3 and conf.juliet.should be_a Fixnum
1003+
conf.kilo.should == "three" and conf.kilo.should be_a String
1004+
conf.lima.should == 3.0 and conf.lima.should be_a Float
1005+
conf.mike.should == :three and conf.mike.should be_a Symbol
1006+
end
1007+
1008+
context 'v1.1' do
1009+
1010+
context 'options' do
1011+
1012+
it 'have defaults at Configuration creation' do
1013+
conf = Configuration.new
1014+
conf._options[:blankslate].should be true
1015+
conf._options[:case_sensitive].should be true
1016+
end
1017+
1018+
it 'are accepted at Configuration creation' do
1019+
conf = Configuration.new nil, :blankslate => false, :case_sensitive => false
1020+
conf._options[:blankslate].should be false
1021+
conf._options[:case_sensitive].should be false
1022+
end
1023+
1024+
end
1025+
1026+
context 'wildcard *' do
1027+
1028+
it 'returns an empty ConfigurationDelegator for subject with no child configurations' do
1029+
conf = simple_config_1
1030+
simple_config_1_example conf
1031+
delegator = conf.*
1032+
delegator.should be_a ConfigurationDelegator
1033+
delegator.should be_empty
1034+
end
1035+
1036+
it 'returns ConfigurationDelegator containing child configurations for subject' do
1037+
conf = simple_config_1
1038+
conf.nested2 = simple_config_2
1039+
conf.nested3 = simple_config_3
1040+
simple_config_1_example conf
1041+
simple_config_2_example conf.nested2
1042+
simple_config_3_example conf.nested3
1043+
delegator = conf.*
1044+
delegator.should be_a ConfigurationDelegator
1045+
delegator.size.should be 2
1046+
delegator[0].should be conf.nested2
1047+
delegator[1].should be conf.nested3
1048+
end
1049+
1050+
end
1051+
1052+
context 'ConfigurationDelegator' do
1053+
1054+
it 'can be created with no child configurations' do
1055+
delegator = ConfigurationDelegator.new []
1056+
delegator.should be_a ConfigurationDelegator
1057+
delegator.should be_empty
1058+
end
1059+
1060+
context 'wildcard *' do
1061+
1062+
# todo: question : should wildcard return nil for already empty ConfigurationDelegator / overshoot ?
1063+
1064+
it 'returns an empty ConfigurationDelegator for ConfigurationDelegator with no child configurations' do
1065+
conf = simple_config_1
1066+
conf.nested2 = simple_config_2
1067+
conf.nested3 = simple_config_3
1068+
simple_config_1_example conf
1069+
simple_config_2_example conf.nested2
1070+
simple_config_3_example conf.nested3
1071+
delegator = conf.*.*
1072+
delegator.should be_a ConfigurationDelegator
1073+
delegator.should be_empty
1074+
end
1075+
1076+
it 'returns an empty ConfigurationDelegator when overshoots' do
1077+
conf = simple_config_1
1078+
conf.nested2 = simple_config_2
1079+
conf.nested3 = simple_config_3
1080+
simple_config_1_example conf
1081+
simple_config_2_example conf.nested2
1082+
simple_config_3_example conf.nested3
1083+
delegator = conf.*.*.*.*.*.*.*.*.*
1084+
delegator.should be_a ConfigurationDelegator
1085+
delegator.should be_empty
1086+
end
1087+
1088+
it 'returns ConfigurationDelegator containing child configurations for ConfigurationDelegator' do
1089+
conf = simple_config_1
1090+
conf.nested2 = simple_config_2
1091+
conf.nested3 = simple_config_3
1092+
conf.nested2.nested2 = simple_config_2
1093+
conf.nested2.nested3 = simple_config_3
1094+
conf.nested3.nested2 = simple_config_2
1095+
conf.nested3.nested3 = simple_config_3
1096+
simple_config_1_example conf
1097+
simple_config_2_example conf.nested2
1098+
simple_config_2_example conf.nested2.nested2
1099+
simple_config_2_example conf.nested3.nested2
1100+
simple_config_3_example conf.nested3
1101+
simple_config_3_example conf.nested2.nested3
1102+
simple_config_3_example conf.nested3.nested3
1103+
delegator = conf.*.*
1104+
delegator.size.should be 4
1105+
delegator[0].should be conf.nested2.nested2
1106+
delegator[1].should be conf.nested2.nested3
1107+
delegator[2].should be conf.nested3.nested2
1108+
delegator[3].should be conf.nested3.nested3
1109+
end
1110+
1111+
end # wildcard *
1112+
1113+
end # ConfigurationDelagator
1114+
1115+
end #v1.1
9611116

9621117
end
9631118

0 commit comments

Comments
 (0)