Class: UCL

Inherits:
Object
  • Object
show all
Defined in:
ext/ucl.c,
ext/ucl.c

Overview

Parser for configuration files written in the Universal Configuration Language (UCL), a JSON-superset format handled by the libucl library.

Parsed configurations are returned as plain Ruby objects (Hash, Array, String, Integer, Float, true/false, nil).

Objects nested more than 1000 levels deep are rejected with Error; see UCL.parse. Input that is both that deeply nested and malformed is the one case this cannot cover: libucl releases its half-built tree recursively, out of reach here, and a SystemStackError comes out instead.

Examples:

Parse a string

UCL.parse('name = value')        #=> { "name" => "value" }

Load a file with symbol keys

UCL.load_file('foo.conf', UCL::KEY_SYMBOL)

See Also:

Defined Under Namespace

Classes: Error

Constant Summary collapse

KEY_LOWERCASE =

convert all object keys to lower case.

Flag
NO_TIME =

do not parse time values; keep them as strings.

Flag
DISABLE_MACRO =

disable processing of macros (e.g. .include).

Flag
NO_FILEVARS =

do not predefine the file variables ($FILENAME, $CURDIR). This affects parse; load_file still derives those variables from the file being loaded.

Flag
KEY_SYMBOL =

return object keys as Symbol instead of String.

Flag

Class Method Summary collapse

Class Method Details

.flagsInteger

Default flags applied by parse and load_file when none are given explicitly.

Returns:

  • the current default flags (0 by default)



363
364
365
366
367
368
369
370
371
372
# File 'ext/ucl.c', line 363

static VALUE
ucl_s_get_flags(VALUE klass)
{
    /* @flags is a plain instance variable and so is not inherited: a
     * subclass that never set its own falls back to UCL's, which is the
     * value its parse/load_file would have used anyway. */
    VALUE flags = rb_attr_get(klass, rb_intern("@flags"));
    if (NIL_P(flags)) flags = rb_attr_get(mUCL, rb_intern("@flags"));
    return flags;
}

.flags=(val) ⇒ Integer

Set the default flags applied by parse and load_file when none are given explicitly.

Parameters:

  • flags, combined with a bitwise OR

Returns:

  • the flags that were set



386
387
388
389
390
391
392
# File 'ext/ucl.c', line 386

static VALUE
ucl_s_set_flags(VALUE klass, VALUE val)
{
    rb_check_type(val, T_FIXNUM);
    rb_iv_set(klass, "@flags", val);
    return val;
}

.load_file(file, flags = UCL.flags) ⇒ Hash, ...

Load and parse a UCL configuration from a file.

Unlike parse, this defines the file variables ($FILENAME, $CURDIR) from the loaded file, so they can be referenced from within the configuration.

Macros are processed, and the nesting limit of parse applies here too.

Examples:

UCL.load_file('foo.conf', UCL::KEY_SYMBOL)

Parameters:

  • path to the configuration file

  • (defaults to: UCL.flags)

    parsing flags combined with a bitwise OR; defaults to flags when omitted

Returns:

  • the configuration as Ruby objects

Raises:

  • if the file cannot be read, is malformed, or is nested too deeply



504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'ext/ucl.c', line 504

static VALUE
ucl_s_load_file(int argc, VALUE *argv, VALUE klass)
{
    VALUE file, flags;
    rb_scan_args(argc, argv, "11", &file, &flags);
    if (NIL_P(flags)) flags = ucl_s_get_flags(klass);

    rb_check_type(file,  T_STRING);
    rb_check_type(flags, T_FIXNUM);

    int   r_flags = FIX2INT(flags);
    int   c_flags = r_flags & ucl_allowed_c_flags;
    char *c_file  = StringValueCStr(file);

    struct ucl_parser *parser =
	ucl_parser_new(c_flags | UCL_PARSER_NO_IMPLICIT_ARRAYS);
    if (parser == NULL)
	rb_raise(eUCLError, "failed to allocate UCL parser");

    /* Before the file is read, not after: the variables are substituted
     * while parsing, so setting them afterwards would have no effect at
     * all. (libucl sets them from the file as well.) */
    ucl_parser_set_filevars(parser, c_file, false);
    ucl_parser_add_file(parser, c_file);

    return ucl_parser_result(parser, r_flags);
}

.parse(data, flags = UCL.flags) ⇒ Hash, ...

Parse a UCL configuration from a string.

Macros are processed, so a configuration is able to pull in other files through .include. Use safe_parse (or the DISABLE_MACRO flag) for input that is not trusted.

Objects nested more than 1000 levels deep are refused: both this conversion and libucl's own tree handling recurse per level, so a deeper tree would exhaust the C stack.

Examples:

UCL.parse('name = value')            #=> { "name" => "value" }
UCL.parse('name = value', UCL::KEY_SYMBOL)  #=> { :name => "value" }

Parameters:

  • the UCL configuration to parse

  • (defaults to: UCL.flags)

    parsing flags combined with a bitwise OR; defaults to flags when omitted

Returns:

  • the configuration as Ruby objects

Raises:

  • if the configuration is malformed, or nested too deeply



447
448
449
450
451
# File 'ext/ucl.c', line 447

static VALUE
ucl_s_parse(int argc, VALUE *argv, VALUE klass)
{
    return ucl_parse_string(argc, argv, klass, 0);
}

.safe_parse(data, flags = UCL.flags) ⇒ Hash, ...

Parse a UCL configuration from a string with macros disabled.

Identical to parse but always adds DISABLE_MACRO, so the configuration cannot reach outside itself through .include. This is the entry point to use for input from an untrusted source.

Examples:

UCL.safe_parse('.include "/etc/passwd"')  #=> raises UCL::Error

Parameters:

  • the UCL configuration to parse

  • (defaults to: UCL.flags)

    parsing flags combined with a bitwise OR; defaults to flags when omitted; DISABLE_MACRO is added to whatever is given

Returns:

  • the configuration as Ruby objects

Raises:

  • if the configuration is malformed, or nested too deeply



474
475
476
477
478
# File 'ext/ucl.c', line 474

static VALUE
ucl_s_safe_parse(int argc, VALUE *argv, VALUE klass)
{
    return ucl_parse_string(argc, argv, klass, UCL_PARSER_DISABLE_MACRO);
}