Class: ConfigFiles::Base
- Inherits:
-
Object
- Object
- ConfigFiles::Base
- Defined in:
- lib/configfiles.rb
Overview
You should write a read(io) method, taking an IO object and returnig a key-value hash, where keys are symbols, and values are Strings or Enumerable yielding Strings
This result will be passed to YourConfigClass#load, where YourConfigClass inherits from ConfigFiles::Base
Defined Under Namespace
Classes: AlreadyDefinedParameter, ArgumentError, DefaultAlreadySet, NoKeyError, RuntimeError, ValidationFailed, VirtualParameterFound
Constant Summary collapse
- CIRCUMSTANCES =
[:unknown_parameter, :unknown_value]
- PREDEFINED_ACTIONS =
[:accept, :ignore, :fail]
Class Attribute Summary collapse
-
.behavior ⇒ Object
*class instance variables* accessors.
-
.parameters ⇒ Object
*class instance variables* accessors.
-
.validation ⇒ Object
*class instance variables* accessors.
Instance Attribute Summary collapse
-
#data ⇒ Object
readonly
class << self.
Class Method Summary collapse
-
.behavior_on(circumstance) ⇒ Object
circumstance
must be an element ofCIRCUMSTANCES
. - .class_instance_initialize ⇒ Object
-
.default(name, value) ⇒ Object
set default value of a parameter.
-
.enumerator(name, converter = nil, &converter_block) ⇒ Object
A special kind of parameter, with a special kind of converter, which in turn converts an Enumerable yielding Strings into an Enumerator of custom objects.
- .inherited(subclass) ⇒ Object
-
.on(circumstance, action = nil, &block) ⇒ Object
Examples: on :unknown_parameter, :fail # or :accept, or :ignore on :unknown_parameter, {|str| str.to_i}.
-
.parameter(name, converter = nil, &converter_block) ⇒ Object
Add a parameter.
-
.validate(&block) ⇒ Object
Set validation rules.
-
.virtual(name, &block) ⇒ Object
Define a parameter as a function of other parameters.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Like Hash#[], but more rigidly! Raise an Exception on unknown key, instead of returning nil.
-
#[]=(key, val) ⇒ Object
Like Hash#[]=, but more rigidly! New keys are not created automagically.
-
#each(&blk) ⇒ Object
Like Hash#each, iterate over parameter names and values.
-
#initialize ⇒ Base
constructor
A new instance of Base.
-
#load(h, opt_h = {}) ⇒ Object
Load the Hash h onto the ConfigFiles object, carrying on conversions to Ruby objects, validation, and default actions if needed.
-
#validate ⇒ Object
Validate configuration object, according to what declared with the class method.
Constructor Details
#initialize ⇒ Base
Returns a new instance of Base.
205 206 207 |
# File 'lib/configfiles.rb', line 205 def initialize @data = {} end |
Class Attribute Details
.behavior ⇒ Object
*class instance variables* accessors
39 40 41 |
# File 'lib/configfiles.rb', line 39 def behavior @behavior end |
.parameters ⇒ Object
*class instance variables* accessors
39 40 41 |
# File 'lib/configfiles.rb', line 39 def parameters @parameters end |
.validation ⇒ Object
*class instance variables* accessors
39 40 41 |
# File 'lib/configfiles.rb', line 39 def validation @validation end |
Instance Attribute Details
#data ⇒ Object (readonly)
class << self
203 204 205 |
# File 'lib/configfiles.rb', line 203 def data @data end |
Class Method Details
.behavior_on(circumstance) ⇒ Object
circumstance
must be an element of CIRCUMSTANCES
. Returns an element of PREDEFINED_ACTIONS
or a user-defined Proc
84 |
# File 'lib/configfiles.rb', line 84 def behavior_on(circumstance); on(circumstance); end |
.class_instance_initialize ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/configfiles.rb', line 45 def class_instance_initialize @parameters ||= {} @behavior ||= { :unknown_parameter => :ignore, :unknown_value => :fail # when the converter is a Hash, # whose keys represents a fixed set # of allowed strings, and values represents # their "meaning", tipically as a Symbol } @validation ||= lambda {|data| true} end |
.default(name, value) ⇒ Object
set default value of a parameter
137 138 139 140 141 142 143 |
# File 'lib/configfiles.rb', line 137 def default(name, value) if @parameters[name] and @parameters[name][:default] raise DefaultAlreadySet, "Default for \"#{name}\" has been already set (to value: #{@parameters[name][:default]})" end @parameters[name] ||= {} @parameters[name][:default] = value end |
.enumerator(name, converter = nil, &converter_block) ⇒ Object
A special kind of parameter, with a special kind of converter, which in turn converts an Enumerable yielding Strings into an Enumerator of custom objects. You may work with Enumerators instead of Arrays , which is the right thing to do when you deal with very long list of names, IP adresses, URIs etc (lazy evaluation) .
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/configfiles.rb', line 164 def enumerator(name, converter=nil, &converter_block) if block_given? raise ArgumentError, 'you must either specify a symbol or a block' if converter else if converter # converter may be :to_i etc. converter_block = lambda {|x| x.method(converter).call} else converter_block = lambda {|x| x} end end #parameter name do |enumerable| # Enumerator.new do |yielder| # enumerable.each do |string| # yielder << converter_block.call(string) # end # end #end # # Use facets instead parameter name do |enumerable| enumerable.defer.map{|element| converter_block.call(element)} end end |
.inherited(subclass) ⇒ Object
41 42 43 |
# File 'lib/configfiles.rb', line 41 def inherited(subclass) subclass.class_instance_initialize end |
.on(circumstance, action = nil, &block) ⇒ Object
Examples:
on :unknown_parameter, :fail # or :accept, or :ignore
on :unknown_parameter, {|str| str.to_i}
There’s also :unknown_value, to specify behavior when the converter is an Hash and the value found if not among the hash keys. Usage is similar.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/configfiles.rb', line 65 def on(circumstance, action=nil, &block) actions = PREDEFINED_ACTIONS circumstances = CIRCUMSTANCES unless circumstances.include? circumstance raise ArgumentError, "Invalid circumstance: #{circumstance.inspect}. Allowed values are #{circumstances.list_inspect}." end if block @behavior[circumstance] = block elsif actions.include? action @behavior[circumstance] = action elsif action raise ArgumentError, "Invalid action: #{action}. Allowed values are #{actions.list_inspect}." else return @behavior[circumstance] end end |
.parameter(name, converter = nil, &converter_block) ⇒ Object
Add a parameter.
# keep as is
parameter :myparam
# convert to integer
parameter :myparam, :to_i
# do some computation
parameter :myparam do |str|
...
...
my_result
end
# map a set of possible/admitted values; you may call the
# class method +on+(:unknown_value) to customize behavior
parameter :myparam,
'1' => :my_first_option,
'2' => :my_second_one
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/configfiles.rb', line 107 def parameter(name, converter=nil, &converter_block) if @parameters[name] and @parameters[name][:converter] raise AlreadyDefinedParameter, "Already defined parameter \"#{name}\"" end if converter if converter_block raise ArgumentError, 'you must either specify a symbol or a block' elsif converter.is_a? Hash converter_block = lambda do |x| # x is a String from conf file if converter.keys.include? x return converter[x] # returns from lambda, not from method elsif @behavior[:unknown_value] == :fail raise ArgumentError, "Invalid value \"#{x}\" for parameter \"#{name}\". Allowed values are #{converter.keys.list_inspect}." elsif @behavior[:unknown_value] == :accept return x end end else #Symbol converter_block = lambda {|x| x.method(converter).call} end else converter_block ||= lambda {|x| x} end @parameters[name] ||= {} @parameters[name][:converter] = converter_block end |
.validate(&block) ⇒ Object
Set validation rules. For example, if parameter ‘a’ must be smaller than ‘b’:
validate do |confdata|
raise ValidationFailed, "no good!" unless
confdata[:a] <= confdata[:b]
end
197 198 199 |
# File 'lib/configfiles.rb', line 197 def validate(&block) @validation = block end |
.virtual(name, &block) ⇒ Object
Define a parameter as a function of other parameters. Example:
virtual :delta do |confdata|
confdata[:this] - confdata[:that]
end
150 151 152 153 154 155 156 |
# File 'lib/configfiles.rb', line 150 def virtual(name, &block) parameter name do |str| raise VirtualParameterFound, "'#{name}' is a virtual parameter, it shouldn't appear directly!" end default name, block end |
Instance Method Details
#[](key) ⇒ Object
Like Hash#[], but more rigidly! Raise an Exception on unknown key, instead of returning nil.
271 272 273 274 275 276 277 |
# File 'lib/configfiles.rb', line 271 def [](key) if @data.keys.include? key @data[key] else raise NoKeyError, "unknown key '#{key}' for #{self.class}" end end |
#[]=(key, val) ⇒ Object
Like Hash#[]=, but more rigidly! New keys are not created automagically. You should have used ConfigFiles.parameter for that.
281 282 283 284 285 286 287 |
# File 'lib/configfiles.rb', line 281 def []=(key, val) if @data.keys.include? key @data[key] = val else raise NoKeyError, "uknown key '#{key}' for #{self.class}" end end |
#each(&blk) ⇒ Object
Like Hash#each, iterate over parameter names and values.
conf.each{|name, value| puts "#{name} is set to #{value}"}
291 292 293 |
# File 'lib/configfiles.rb', line 291 def each(&blk) @data.each(&blk) end |
#load(h, opt_h = {}) ⇒ Object
Load the Hash h onto the ConfigFiles object, carrying on conversions to Ruby objects, validation, and default actions if needed. h’s keys are Symbols, h’s values are typically Strings or Enumerables yielding Strings. See also ConfigFiles::Base::parameter and ConfigFiles::Base::on.
Option Hash opt_h keys:
-
:compute_defaults
(defaulttrue
)
compute/assign default values to unset params if possible
-
:compute_deferred
(defaulttrue
)
compute/assign parameters which are function of others
-
:validate
(defaulttrue
)
perform validation defined in ConfigFiles::Base::validate
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/configfiles.rb', line 232 def load(h, opt_h={}) opt_h_defaults = { :compute_defaults => true, :compute_deferred => true, :validate => true } opt_h = opt_h_defaults.merge(opt_h) h.each_pair do |id, value| if self.class.parameters[id] and self.class.parameters[id][:converter] @data[id] = self.class.parameters[id][:converter].call(value) elsif self.class.behavior[:unknown_parameter] == :fail raise RuntimeError, "unknown parameter #{key}" # otherwise ignore elsif self.class.behavior[:unknown_parameter] == :accept @data[id] = value elsif self.class.behavior[:unknown_parameter].respond_to? :call block = self.class.behavior[:unknown_parameter] @data[id] = block.call value end end if opt_h[:compute_defaults] # assign default values to the remaining params self.class.parameters.each_pair do |name, h| if !@data[name] and self.class.parameters[name][:default] @data[name] = self.class.parameters[name][:default] end end end @data.merge! deferred_data if opt_h[:compute_deferred] validate if opt_h[:validate] return self end |
#validate ⇒ Object
Validate configuration object, according to what declared with the class method
211 212 213 |
# File 'lib/configfiles.rb', line 211 def validate self.class.validation.call(self) end |