Class: Jeckyl::Config
Overview
This is the main Jeckyl class from which to create specific application classes. For example, to create a new set of parameters, define a class as
class MyConfig < Jeckyl::Config
More details are available in the Readme file
Class Method Summary collapse
-
.check_config(config_file, report_file = nil) ⇒ Boolean
a class method to check a given config file one item at a time.
-
.descendants ⇒ Array
return a list of descendant classes in the current context.
-
.generate_config(local = false) ⇒ Object
a class method to generate a config file from the class definition.
-
.get_config_opt(args, c_file) ⇒ Object
get a config file option from the given command line args.
-
.intersection(full_config) ⇒ Hash
extract only those parameters in a hash that are from the given class.
Instance Method Summary collapse
-
#_comments ⇒ Object
gives access to a hash containing an entry for each parameter and the comments defined by the class definitions - used internally by class methods.
-
#_defaults ⇒ Object
this contains a hash of the defaults for each parameter - used internally by class methods.
-
#_descriptions ⇒ Object
return has of descriptions.
-
#_options ⇒ Object
return hash of options - used internally to generate files etc.
-
#_order ⇒ Object
This contains an array of the parameter names - used internally by class methods.
-
#complement(conf_to_remove) ⇒ Object
Delete those parameters that are in the given hash from this instance of Jeckyl::Config.
-
#initialize(config_file = nil, opts = {}) ⇒ Config
constructor
create a configuration hash by evaluating the parameters defined in the given config file.
-
#merge(conf_file) ⇒ Object
Read, check and merge another parameter file into this one, being of the same config class.
-
#optparse(args = ARGV) { ... } ⇒ Object
parse the given command line using the defined options.
-
#prefix ⇒ Object
set the prefix to the parameter names that should be used for corresponding parameter methods defined for a subclass.
-
#to_s(opts = {}) ⇒ Object
output the hash as a formatted set.
Methods included from Helpers
#a_boolean, #a_flag, #a_hash, #a_matching_string, #a_member_of, #a_number, #a_positive_number, #a_readable_dir, #a_readable_file, #a_string, #a_type_of, #a_writable_dir, #an_array, #an_array_of, #an_executable, #in_range
Constructor Details
#initialize(config_file = nil, opts = {}) ⇒ Config
create a configuration hash by evaluating the parameters defined in the given config file.
If no config file is given then the hash of options returned will only have the defaults defined for the given class.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/jeckyl.rb', line 59 def initialize(config_file=nil, opts={}) # do whatever a hash has to do super() flag_errors_on_defaults = opts[:flag_errors_on_defaults] || false local = opts[:local] || false @_relax = opts[:relax] || false # somewhere to save the most recently set symbol @_last_symbol = nil # hash for comments accessed with the same symbol @_comments = {} # hash for input defaults @_defaults = {} # hash for optparse options = {} # hash for short descriptions @_descriptions = {} # save order in which methods are defined for generating config files @_order = Array.new # get the defaults defined in the config parser get_defaults(:local=> local, :flag_errors => flag_errors_on_defaults) self[:config_files] = Array.new return self if config_file.nil? # remember where the config file itself is self[:config_files] = [config_file] # and finally get the values from the config file itself self.instance_eval(File.read(config_file), config_file) rescue SyntaxError => err raise ConfigSyntaxError, err. rescue Errno::ENOENT # duff file path so tell the caller raise ConfigFileMissing, "#{config_file}" end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symb, parameter) ⇒ Object (private)
decides what to do with parameters that have not been defined. unless @_relax then it will raise an exception. Otherwise it will create a key value pair
This method also remembers the method name as the key to prevent the parsers etc from having to carry this around just to do things like report on it.
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/jeckyl.rb', line 440 def method_missing(symb, parameter) @_last_symbol = symb #@parameter = parameter method_to_call = ("#{self.prefix}_" + symb.to_s).to_sym set_method = self.method(method_to_call) self[@_last_symbol] = set_method.call(parameter) rescue NameError #raise if @@debug # no parser method defined. unless @_relax then # not tolerable raise UnknownParameter, format_error(symb, parameter, "Unknown parameter") else # feeling relaxed, so lets store it anyway. self[symb] = parameter end end |
Class Method Details
.check_config(config_file, report_file = nil) ⇒ Boolean
a class method to check a given config file one item at a time
This evaluates the given config file and reports if there are any errors to the report_file, which defaults to Stdout. Can only do the checking one error at a time.
To use this method, it is necessary to write a script that calls it for the particular subclass.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/jeckyl.rb', line 138 def self.check_config(config_file, report_file=nil) # create myself to generate defaults, but nothing else me = self.new success = true = "No errors found in: #{config_file}" begin # evaluate the config file me.instance_eval(File.read(config_file), config_file) rescue Errno::ENOENT = "No such config file: #{config_file}" success = false rescue JeckylError => err = err. success = false rescue SyntaxError => err = err. success = false end begin if report_file.nil? then puts else File.open(report_file, "w") do |rfile| rfile.puts end end return success rescue Errno::ENOENT raise ReportFileError, "Error with file: #{report_file}" end end |
.descendants ⇒ Array
return a list of descendant classes in the current context. This is provided to help find classes for the jeckyl utility, e.g. to generate a default config file
239 240 241 242 243 244 |
# File 'lib/jeckyl.rb', line 239 def self.descendants descs = Array.new ObjectSpace.each_object {|obj| descs << obj if obj.kind_of?(Class) && obj < self} descs.sort! {|a,b| a < b ? -1 : 1} return descs end |
.generate_config(local = false) ⇒ Object
a class method to generate a config file from the class definition
This calls each of the parameter methods, and creates a commented template with the comments and default lines
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/jeckyl.rb', line 184 def self.generate_config(local=false) me = self.new(nil, :local => local) # everything should now exist me._order.each do |key| if me._descriptions.has_key?(key) then puts "# #{me._descriptions[key]}" puts "#" end if me._comments.has_key?(key) then me._comments[key].each do |comment| puts "# #{comment}" end end # output an option description if needed if me..has_key?(key) then puts "#" puts "# Optparse options for this parameter:" puts "# #{me._options[key].join(", ")}" puts "#" end def_value = me._defaults[key] default = def_value.nil? ? '' : def_value.inspect puts "##{key.to_s} #{default}" puts "" end end |
.get_config_opt(args, c_file) ⇒ Object
get a config file option from the given command line args
This is needed with the optparse methods for obvious reasons - the options can only be parsed once and you may want to parse them with a config file specified on the command line. This does it the old-fashioned way and strips the option from the command line arguments.
Note that the optparse method also includes this option but just for the benefit of –help
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/jeckyl.rb', line 259 def self.get_config_opt(args, c_file) #c_file = nil if arg_index = args.index('-c') then # got a -c option so expect a file next c_file = args[arg_index + 1] # check the file exists if c_file && FileTest.readable?(c_file) then # it does so strip the args out args.slice!(arg_index, 2) end end return [args, c_file] end |
.intersection(full_config) ⇒ Hash
this returns a plain hash and not an instance of Jeckyl::Config
extract only those parameters in a hash that are from the given class
222 223 224 225 226 227 228 229 230 231 |
# File 'lib/jeckyl.rb', line 222 def self.intersection(full_config) me = self.new # create the defaults for this class my_hash = {} me._order.each do |my_key| if full_config.has_key?(my_key) then my_hash[my_key] = full_config[my_key] end end return my_hash end |
Instance Method Details
#_comments ⇒ Object
gives access to a hash containing an entry for each parameter and the comments defined by the class definitions - used internally by class methods
102 103 104 |
# File 'lib/jeckyl.rb', line 102 def _comments @_comments end |
#_defaults ⇒ Object
this contains a hash of the defaults for each parameter - used internally by class methods
112 113 114 |
# File 'lib/jeckyl.rb', line 112 def _defaults @_defaults end |
#_descriptions ⇒ Object
return has of descriptions
122 123 124 |
# File 'lib/jeckyl.rb', line 122 def _descriptions @_descriptions end |
#_options ⇒ Object
return hash of options - used internally to generate files etc
117 118 119 |
# File 'lib/jeckyl.rb', line 117 def end |
#_order ⇒ Object
This contains an array of the parameter names - used internally by class methods
107 108 109 |
# File 'lib/jeckyl.rb', line 107 def _order @_order end |
#complement(conf_to_remove) ⇒ Object
Delete those parameters that are in the given hash from this instance of Jeckyl::Config. Useful for tailoring parameter sets to specific uses (e.g. removing logging parameters)
295 296 297 |
# File 'lib/jeckyl.rb', line 295 def complement(conf_to_remove) self.delete_if {|key, value| conf_to_remove.has_key?(key)} end |
#merge(conf_file) ⇒ Object
Read, check and merge another parameter file into this one, being of the same config class.
If the file does not exist then silently ignore the merge
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/jeckyl.rb', line 305 def merge(conf_file) if conf_file.kind_of?(Hash) then self.merge!(conf_file) else return unless FileTest.exists?(conf_file) self[:config_files] << conf_file # get the values from the config file itself self.instance_eval(File.read(conf_file), conf_file) end rescue SyntaxError => err raise ConfigSyntaxError, err. rescue Errno::ENOENT # duff file path so tell the caller raise ConfigFileMissing, "#{conf_file}" end |
#optparse(args = ARGV) { ... } ⇒ Object
parse the given command line using the defined options
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/jeckyl.rb', line 330 def optparse(args=ARGV) # ensure calls to parameter methods do not trample on things @_last_symbol = nil opts = OptionParser.new # get the prefix for parameter methods (once) prefix = self.prefix opts.on('-c', '--config-file [FILENAME]', String, 'specify an alternative config file') # need to define usage etc # loop through each of the options saved .each_pair do |param, | << @_descriptions[param] if @_descriptions.has_key?(param) # get the method itself to call with the given arg pref_method = self.method("#{prefix}_#{param}".to_sym) # now process the option opts.on(*) do |val| # and save the results having passed it through the parameter method self[param] = pref_method.call(val) end end # allow non-jeckyl options to be added (without the checks!) if block_given? then # pass out self to allow parameters to be saved and the opts object yield(self, opts) end # add in a little bit of help opts.on_tail('-h', '--help', 'you are looking at it') do puts opts return false end opts.parse!(args) return true end |
#prefix ⇒ Object
set the prefix to the parameter names that should be used for corresponding parameter methods defined for a subclass. Parameter names in config files are mapped onto parameter method by prefixing the methods with the results of this function. So, for a parameter named ‘greeting’, the parameter method used to check the parameter will be, by default, ‘configure_greeting’.
For example, to define parameter methods prefix with ‘set’ redefine this method to return ‘set’. The greeting parameter method should then be called ‘set_greeting’
286 287 288 |
# File 'lib/jeckyl.rb', line 286 def prefix 'configure' end |
#to_s(opts = {}) ⇒ Object
output the hash as a formatted set
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/jeckyl.rb', line 378 def to_s(opts={}) keys = self.keys.collect {|k| k.to_s} cols = 0 strs = Array.new keys.each {|k| cols = k.length if k.length > cols} keys.sort.each do |key_s| str = ' ' str << key_s.ljust(cols) key = key_s.to_sym desc = @_descriptions[key] value = self[key].inspect str << ": #{value}" str << " (#{desc})" unless desc.nil? strs << str end return strs.join("\n") end |