Class: Cosmos::ConfigParser
- Defined in:
- lib/cosmos/config/config_parser.rb,
ext/cosmos/ext/config_parser/config_parser.c
Overview
Reads COSMOS style configuration data which consists of keywords followed by 0 or more comma delimited parameters. Parameters with spaces must be enclosed in quotes. Quotes should also be used to indicate a parameter is a string. Keywords are case-insensitive and will be returned in uppercase.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- PARSING_REGEX =
Regular expression used to break up an individual line into a keyword and comma delimited parameters. Handles parameters in single or double quotes.
%r{ (?:"(?:[^\\"]|\\.)*") | (?:'(?:[^\\']|\\.)*') | \S+ }x
- @@message_callback =
nil
- @@progress_callback =
nil
- @@splash =
Holds the current splash screen
nil
Instance Attribute Summary collapse
-
#filename ⇒ String
The name of the configuration file being parsed.
-
#keyword ⇒ String
The current keyword being parsed.
-
#line ⇒ String
The current line being parsed.
-
#line_number ⇒ Integer
The current line number being parsed.
-
#parameters ⇒ Array<String>
The parameters found after the keyword.
-
#url ⇒ String
The default URL to use in errors.
Class Method Summary collapse
-
.handle_defined_constants(value) ⇒ Numeric
Converts a string representing a defined constant into its value.
-
.handle_nil(value) ⇒ nil|Object
Converts a String containing ”, ‘NIL’ or ‘NULL’ to nil Ruby primitive.
-
.handle_true_false(value) ⇒ true|false|Object
Converts a String containing ‘TRUE’ or ‘FALSE’ to true or false Ruby primitive.
-
.handle_true_false_nil(value) ⇒ true|false|nil|Object
Converts a String containing ”, ‘NIL’, ‘NULL’, ‘TRUE’ or ‘FALSE’ to nil, true or false Ruby primitives.
- .message_callback=(message_callback) ⇒ Object
- .progress_callback=(progress_callback) ⇒ Object
-
.splash ⇒ Object
Returns the current splash screen if present.
- .splash=(splash) ⇒ Object
Instance Method Summary collapse
-
#error(message, usage = "", url = @url) ⇒ Error
Creates an Error.
-
#initialize(url = "https://github.com/BallAerospace/COSMOS/wiki/Configuration-Guide") ⇒ ConfigParser
constructor
A new instance of ConfigParser.
-
#parse_file(filename, yield_non_keyword_lines = false, remove_quotes = true, &block) {|keyword, parameters| ... } ⇒ Object
Processes a file and yields |config| to the given block.
-
#parse_loop(io, yield_non_keyword_lines, remove_quotes, size, rx) ⇒ Object
Iterates over each line of the io object and yields the keyword and parameters.
-
#render(template_name, options = {}) ⇒ Object
Called by the ERB template to render a partial.
-
#verify_num_parameters(min_num_params, max_num_params, usage = "") ⇒ Object
Verifies the parameters in the config parameter have the specified number of parameter and raises an Error if not.
Constructor Details
#initialize(url = "https://github.com/BallAerospace/COSMOS/wiki/Configuration-Guide") ⇒ ConfigParser
Returns a new instance of ConfigParser.
134 135 136 |
# File 'lib/cosmos/config/config_parser.rb', line 134 def initialize(url = "https://github.com/BallAerospace/COSMOS/wiki/Configuration-Guide") @url = url end |
Instance Attribute Details
#filename ⇒ String
Returns The name of the configuration file being parsed. This will be an empty string if the parse_string class method is used.
30 31 32 |
# File 'lib/cosmos/config/config_parser.rb', line 30 def filename @filename end |
#keyword ⇒ String
Returns The current keyword being parsed.
23 24 25 |
# File 'lib/cosmos/config/config_parser.rb', line 23 def keyword @keyword end |
#line ⇒ String
Returns The current line being parsed. This is the raw string which is useful when printing errors.
34 35 36 |
# File 'lib/cosmos/config/config_parser.rb', line 34 def line @line end |
#line_number ⇒ Integer
Returns The current line number being parsed. This will still be populated when using parse_string because lines still must be delimited by newline characters.
39 40 41 |
# File 'lib/cosmos/config/config_parser.rb', line 39 def line_number @line_number end |
#parameters ⇒ Array<String>
Returns The parameters found after the keyword.
26 27 28 |
# File 'lib/cosmos/config/config_parser.rb', line 26 def parameters @parameters end |
#url ⇒ String
Returns The default URL to use in errors. The URL can still be overridden by directly passing it to the error method.
43 44 45 |
# File 'lib/cosmos/config/config_parser.rb', line 43 def url @url end |
Class Method Details
.handle_defined_constants(value) ⇒ Numeric
Converts a string representing a defined constant into its value. The defined constants are the minimum and maximum values for all the allowable data types. [MIN/MAX]_[U]INT and [MIN/MAX]_FLOAT. Thus MIN_UINT8, MAX_INT32, and MIN_FLOAT64 are all allowable values. Any other strings raise ArgumentError but all other types are simply returned.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/cosmos/config/config_parser.rb', line 290 def self.handle_defined_constants(value) if value.class == String case value.upcase when 'MIN_INT8' return -128 when 'MAX_INT8' return 127 when 'MIN_INT16' return -32768 when 'MAX_INT16' return 32767 when 'MIN_INT32' return -2147483648 when 'MAX_INT32' return 2147483647 when 'MIN_INT64' return -9223372036854775808 when 'MAX_INT64' return 9223372036854775807 when 'MIN_UINT8', 'MIN_UINT16', 'MIN_UINT32', 'MIN_UINT64' return 0 when 'MAX_UINT8' return 255 when 'MAX_UINT16' return 65535 when 'MAX_UINT32' return 4294967295 when 'MAX_UINT64' return 18446744073709551615 when 'MIN_FLOAT64' return -Float::MAX when 'MAX_FLOAT64' return Float::MAX when 'MIN_FLOAT32' return -3.402823e38 when 'MAX_FLOAT32' return 3.402823e38 when 'POS_INFINITY' return Float::INFINITY when 'NEG_INFINITY' return -Float::INFINITY else raise ArgumentError, "Could not convert constant: #{value}" end end return value end |
.handle_nil(value) ⇒ nil|Object
Converts a String containing ”, ‘NIL’ or ‘NULL’ to nil Ruby primitive. All other arguments are simply returned.
235 236 237 238 239 240 241 242 243 |
# File 'lib/cosmos/config/config_parser.rb', line 235 def self.handle_nil(value) if String === value case value.upcase when '', 'NIL', 'NULL' return nil end end return value end |
.handle_true_false(value) ⇒ true|false|Object
Converts a String containing ‘TRUE’ or ‘FALSE’ to true or false Ruby primitive. All other values are simply returned.
250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/cosmos/config/config_parser.rb', line 250 def self.handle_true_false(value) if String === value case value.upcase when 'TRUE' return true when 'FALSE' return false end end return value end |
.handle_true_false_nil(value) ⇒ true|false|nil|Object
Converts a String containing ”, ‘NIL’, ‘NULL’, ‘TRUE’ or ‘FALSE’ to nil, true or false Ruby primitives. All other values are simply returned.
267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/cosmos/config/config_parser.rb', line 267 def self.handle_true_false_nil(value) if String === value case value.upcase when 'TRUE' return true when 'FALSE' return false when '', 'NIL', 'NULL' return nil end end return value end |
.message_callback=(message_callback) ⇒ Object
50 51 52 |
# File 'lib/cosmos/config/config_parser.rb', line 50 def self.() @@message_callback = end |
.progress_callback=(progress_callback) ⇒ Object
60 61 62 |
# File 'lib/cosmos/config/config_parser.rb', line 60 def self.progress_callback=(progress_callback) @@progress_callback = progress_callback end |
.splash ⇒ Object
Returns the current splash screen if present
82 83 84 |
# File 'lib/cosmos/config/config_parser.rb', line 82 def self.splash @@splash end |
.splash=(splash) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/cosmos/config/config_parser.rb', line 69 def self.splash=(splash) if splash @@splash = splash @@progress_callback = splash.progress_callback @@message_callback = splash. else @@splash = nil @@progress_callback = nil @@message_callback = nil end end |
Instance Method Details
#error(message, usage = "", url = @url) ⇒ Error
Creates an Error
144 145 146 |
# File 'lib/cosmos/config/config_parser.rb', line 144 def error(, usage = "", url = @url) return Error.new(self, , usage, url) end |
#parse_file(filename, yield_non_keyword_lines = false, remove_quotes = true, &block) {|keyword, parameters| ... } ⇒ Object
Processes a file and yields |config| to the given block
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/cosmos/config/config_parser.rb', line 170 def parse_file(filename, yield_non_keyword_lines = false, remove_quotes = true, &block) @filename = filename file = nil unparsed_data = nil begin # Create a temp file where we can write the ERB parsed output file = Tempfile.new("parsed_#{File.basename(filename)}") unparsed_data = File.read(@filename) file.write(ERB.new(unparsed_data).result(binding)) file.rewind size = file.stat.size.to_f # Callbacks for beginning of parsing @@message_callback.call("Parsing #{size} bytes of #{filename}") if @@message_callback @@progress_callback.call(0.0) if @@progress_callback # Loop through each line of the data parse_loop(file, yield_non_keyword_lines, remove_quotes, size, PARSING_REGEX, &block) rescue Exception => e debug_file = create_debug_output_file(filename, file, unparsed_data, e) if debug_file raise e, "#{e}\nDebug output in #{debug_file}", e.backtrace else raise e end ensure file.close unless file.closed? end end |
#parse_loop(io, yield_non_keyword_lines, remove_quotes, size, rx) ⇒ Object
Iterates over each line of the io object and yields the keyword and parameters
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 99 100 101 102 103 104 105 106 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 135 136 137 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 175 176 177 178 179 180 181 182 183 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 'ext/cosmos/ext/config_parser/config_parser.c', line 72
static VALUE parse_loop(VALUE self, VALUE io, VALUE yield_non_keyword_lines, VALUE remove_quotes, VALUE size, VALUE rx) {
int line_number = 0;
int result = 0;
long length = 0;
int index = 0;
double float_pos = 0.0;
double float_size = NUM2DBL(size);
volatile VALUE progress_callback = rb_cvar_get(cConfigParser, id_cvar_progress_callback);
volatile VALUE line = Qnil;
volatile VALUE data = Qnil;
volatile VALUE line_continuation = Qfalse;
volatile VALUE string = Qnil;
volatile VALUE array = rb_ary_new();
volatile VALUE first_item = Qnil;
volatile VALUE ivar_keyword = Qnil;
volatile VALUE ivar_parameters = rb_ary_new();
volatile VALUE ivar_line =Qnil;
rb_ivar_set(self, id_ivar_line_number, INT2FIX(0));
rb_ivar_set(self, id_ivar_keyword, ivar_keyword);
rb_ivar_set(self, id_ivar_parameters, ivar_parameters);
rb_ivar_set(self, id_ivar_line, ivar_line);
while (1) {
line_number += 1;
rb_ivar_set(self, id_ivar_line_number, INT2FIX(line_number));
if (RTEST(progress_callback) && ((line_number % 10) == 0)) {
if (float_size > 0.0) {
float_pos = NUM2DBL(rb_funcall(io, id_method_pos, 0));
rb_funcall(progress_callback, id_method_call, 1, rb_float_new(float_pos / float_size));
}
}
line = rb_protect(config_parser_readline, io, &result);
if (result) {
rb_set_errinfo(Qnil);
break;
}
line = rb_funcall(line, id_method_strip, 0);
data = rb_funcall(line, id_method_scan, 1, rx);
first_item = rb_funcall(rb_ary_entry(data, 0), id_method_to_s, 0);
if (RTEST(line_continuation)) {
rb_str_concat(ivar_line, line);
/* Carry over keyword and parameters */
} else {
ivar_line = line;
rb_ivar_set(self, id_ivar_line, ivar_line);
if ((RSTRING_LEN(first_item) == 0) || (RSTRING_PTR(first_item)[0] == '#')) {
ivar_keyword = Qnil;
} else {
ivar_keyword = rb_funcall(first_item, id_method_upcase, 0);
}
rb_ivar_set(self, id_ivar_keyword, ivar_keyword);
ivar_parameters = rb_ary_new();
rb_ivar_set(self, id_ivar_parameters, ivar_parameters);
}
/* Ignore comments and blank lines */
if (ivar_keyword == Qnil) {
if ((RTEST(yield_non_keyword_lines)) && (!(RTEST(line_continuation)))) {
rb_ary_clear(array);
rb_ary_push(array, ivar_keyword);
rb_ary_push(array, ivar_parameters);
rb_yield(array);
}
continue;
}
if (RTEST(line_continuation)) {
if (RTEST(remove_quotes)) {
rb_ary_push(ivar_parameters, string_remove_quotes(first_item));
} else {
rb_ary_push(ivar_parameters, first_item);
}
line_continuation = Qfalse;
}
length = RARRAY_LEN(data);
if (length > 1) {
for (index = 1; index < length; index++) {
string = rb_ary_entry(data, index);
/*
* Don't process trailing comments such as:
* KEYWORD PARAM #This is a comment
* But still process Ruby string interpolations such as:
* KEYWORD PARAM #{var}
*/
if ((RSTRING_LEN(string) > 0) && (RSTRING_PTR(string)[0] == '#')) {
if (!((RSTRING_LEN(string) > 1) && (RSTRING_PTR(string)[1] == '{'))) {
break;
}
}
/*
* If the string is simply '&' and its the last string then its a line continuation so break the loop
*/
if ((RSTRING_LEN(string) == 1) && (RSTRING_PTR(string)[0] == '&') && (index == (length - 1))) {
line_continuation = Qtrue;
continue;
}
line_continuation = Qfalse;
if (RTEST(remove_quotes)) {
rb_ary_push(ivar_parameters, string_remove_quotes(string));
} else {
rb_ary_push(ivar_parameters, string);
}
}
}
/*
* If we detected a line continuation while going through all the
* strings on the line then we strip off the continuation character and
* return to the top of the loop to continue processing the line.
*/
if (RTEST(line_continuation)) {
/* Strip the continuation character */
if (RSTRING_LEN(ivar_line) >= 1) {
ivar_line = rb_str_new(RSTRING_PTR(ivar_line), RSTRING_LEN(ivar_line) - 1);
} else {
ivar_line = rb_str_new2("");
}
rb_ivar_set(self, id_ivar_line, ivar_line);
continue;
}
rb_ary_clear(array);
rb_ary_push(array, ivar_keyword);
rb_ary_push(array, ivar_parameters);
rb_yield(array);
}
if (RTEST(progress_callback)) {
rb_funcall(progress_callback, id_method_call, 1, rb_float_new(1.0));
}
return Qnil;
}
|
#render(template_name, options = {}) ⇒ Object
Called by the ERB template to render a partial
149 150 151 152 153 154 155 156 157 158 |
# File 'lib/cosmos/config/config_parser.rb', line 149 def render(template_name, = {}) b = binding if [:locals] [:locals].each do |key, value| eval("#{key} = #{value}", b) end end # Assume the file is there. If not we raise a pretty obvious error ERB.new(File.read(File.join(File.dirname(@filename), template_name))).result(b) end |
#verify_num_parameters(min_num_params, max_num_params, usage = "") ⇒ Object
Verifies the parameters in the config parameter have the specified number of parameter and raises an Error if not.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/cosmos/config/config_parser.rb', line 215 def verify_num_parameters(min_num_params, max_num_params, usage = "") # This syntax works with 0 because each doesn't return any values # for a backwards range (1..min_num_params).each do |index| # If the parameter is nil (0 based) then we have a problem if @parameters[index-1].nil? raise Error.new(self, "Not enough parameters for #{@keyword}.", usage, @url) end end # If they pass nil for max_params we don't check for a maximum number if max_num_params && !@parameters[max_num_params].nil? raise Error.new(self, "Too many parameters for #{@keyword}.", usage, @url) end end |