Datafiles as Ruby source musings

Hi,

I would like to have a Ruby program read some data- or descriptionfiles which
are just Ruby code. ( ofcourse I’ll look at security, etc. ), but I found
some caveats:

snippet of datafile e.g.:


VAR=true
OTHERVAR=false
YETANOTHER=true

  • ---------etc.------------

module Data
load "datafile"
end

However, the constants loaded are not defined in the scope of the module, but
in the global space. I must use:
module Data
eval File.new (“datafile”).read
end

or put the module definition line in the datafile as well. Which, both are not
very elegant.

Other files which my app will need, must contain Makefile-like structures.
I would rather just “load” the file, and having the Ruby interpreter take care
of the parsing (example:)

ALSA && (
depend “audio/alsa-driver” { |p| p.version >= 0.9 }
configure << “–enable-alsa”
)

where ‘depend’ and ‘configure’ are just methods in the current instance, and
’ALSA’ a constant defined in a module that got included. But again using
’obj.instance_eval File.new(“file”).read’ is the only thing I can think of.

Does anybody have a nice hint or better trick to create data- or config files
readable with Ruby without having to write parsers in ruby?

thanks,
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

Does anybody have a nice hint or better trick to create data- or config files
readable with Ruby without having to write parsers in ruby?

thanks,
Wilbert

A not-uncommon approach is to define a class with your global vars

···

#----------------------------------------

file config.rb

class Config
VAR=true
OTHERVAR=false
YETANOTHER=true

Use some conditional logic to define a config constant …

winroot = “”
/mswin/ =~ RUBY_PLATFORM ? winroot = “C:/” : winroot = “”
BASE_PATH = “#{winroot}/home/foobar”
end
#----------------------------------------

and then just require this file elsewhere

#----------------------------------------

File my_test.rb

require ‘config’

my_var = Config::VAR
my_other_var = Config::OTHERVAR
my_dev_path = Config::BASE_PATH

#----------------------------------------

James

XML
YAML

tho it seems like

module M
eval IO.readline ‘config’
end

is elegant enough, you could even

module M
eval IO.readline “#{self}.config”
end

-a

···

On Sun, 26 Jan 2003, Wilbert Berendsen wrote:

Does anybody have a nice hint or better trick to create data- or config files
readable with Ruby without having to write parsers in ruby?

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

Hi,

module Data
load “datafile”
end

Kernel#load code in the file into toplevel context if (omitted)
second argument is false, or an anonymous module.

If it were return that anonymous module, you can write as:

module Data
include load(“datafile”, true)
end

or even

Data = load(“datafile”, true)

Other files which my app will need, must contain Makefile-like structures.
I would rather just “load” the file, and having the Ruby interpreter take care
of the parsing (example:)

ALSA && (
depend “audio/alsa-driver” { |p| p.version >= 0.9 }
configure << “–enable-alsa”
)

where ‘depend’ and ‘configure’ are just methods in the current instance, and
‘ALSA’ a constant defined in a module that got included. But again using
‘obj.instance_eval File.new(“file”).read’ is the only thing I can think of.

To do it, Kernel#load would need to accept a Module as second
argument, like as:

load(“depend”, Data)

Although I don’t guess this modification rarely breaks existing
code, but not sure it’s a good thing.

Index: eval.c

···

At Sun, 26 Jan 2003 06:18:09 +0900, Wilbert Berendsen wrote:

RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.389
diff -u -2 -p -r1.389 eval.c
— eval.c 23 Jan 2003 08:27:05 -0000 1.389
+++ eval.c 26 Jan 2003 12:44:42 -0000
@@ -5398,8 +5398,7 @@ rb_mod_module_eval(argc, argv, mod)
VALUE rb_load_path;

-void
+VALUE
rb_load(fname, wrap)

  • VALUE fname;
  • int wrap;
  • VALUE fname, wrap;
    {
    VALUE tmp;
    @@ -5411,5 +5410,5 @@ rb_load(fname, wrap)
    TMP_PROTECT;
  • if (wrap && ruby_safe_level >= 4) {
  • if (RTEST(wrap) && ruby_safe_level >= 4) {
    StringValue(fname);
    }
    @@ -5428,5 +5427,6 @@ rb_load(fname, wrap)
    wrapper = ruby_wrapper;
    ruby_cref = top_cref;
  • if (!wrap) {
  • if (!RTEST(wrap)) {
  • wrap = Qnil;
    rb_secure(4); /* should alter global state */
    ruby_class = rb_cObject;
    @@ -5434,6 +5434,9 @@ rb_load(fname, wrap)
    }
    else {
  • /* load in anonymous module as toplevel */
  • ruby_class = ruby_wrapper = rb_module_new();
  • if (TYPE(wrap) != T_MODULE) {
  •   /* load in anonymous module as toplevel */
    
  •   wrap = rb_module_new();
    
  • }
  • ruby_class = ruby_wrapper = wrap;
    self = rb_obj_clone(ruby_top_self);
    rb_extend_object(self, ruby_class);
    @@ -5485,10 +5488,11 @@ rb_load(fname, wrap)
    if (!NIL_P(ruby_errinfo)) /* exception during load */
    rb_exc_raise(ruby_errinfo);
  • return wrap;
    }

-void
+VALUE
rb_load_protect(fname, wrap, state)
VALUE fname;

  • int wrap;
  • VALUE wrap;
    int *state;
    {
    @@ -5497,8 +5501,9 @@ rb_load_protect(fname, wrap, state)
    PUSH_TAG(PROT_NONE);
    if ((status = EXEC_TAG()) == 0) {
  • rb_load(fname, wrap);
  • wrap = rb_load(fname, wrap);
    }
    POP_TAG();
    if (state) *state = status;
  • return wrap;
    }

@@ -5511,6 +5516,5 @@ rb_f_load(argc, argv)

 rb_scan_args(argc, argv, "11", &fname, &wrap);
  • rb_load(fname, RTEST(wrap));
  • return Qtrue;
  • return rb_load(fname, wrap);
    }

Index: intern.h

RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.109
diff -u -2 -p -r1.109 intern.h
— intern.h 16 Jan 2003 07:34:01 -0000 1.109
+++ intern.h 26 Jan 2003 12:39:37 -0000
@@ -168,6 +168,6 @@ ID rb_frame_last_func _((void));
VALUE rb_obj_instance_eval _((int, VALUE*, VALUE));
VALUE rb_mod_module_eval _((int, VALUE*, VALUE));
-void rb_load _((VALUE, int));
-void rb_load_protect _((VALUE, int, int*));
+VALUE rb_load _((VALUE, VALUE));
+VALUE rb_load_protect _((VALUE, VALUE, int*));
NORETURN(void rb_jump_tag _((int)));
int rb_provided _((const char*));


Nobu Nakada

For simple config files, you could write it in Ruby itself:

=============== config.rb =============
module Conf

VALUE = 7

Array = [1,2,3] # You must use constants so they
# are visible in your file.
end

============== your_program.rb ==========
require ‘config.rb’

Can use C::VALUE and C::Array

···

On Sun, Jan 26, 2003 at 12:12:31PM +0900, ahoward wrote:

Does anybody have a nice hint or better trick to create data- or config files
readable with Ruby without having to write parsers in ruby?


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

let me repeat: YAML

···

On Saturday 25 January 2003 08:12 pm, ahoward wrote:

On Sun, 26 Jan 2003, Wilbert Berendsen wrote:

Does anybody have a nice hint or better trick to create data- or config
files readable with Ruby without having to write parsers in ruby?
YAML


tom sawyer, aka transami
transami@transami.net

Hi,

module Data
load “datafile”
end

Kernel#load code in the file into toplevel context if (omitted)
second argument is false, or an anonymous module.

If it were return that anonymous module, you can write as:

module Data
include load(“datafile”, true)
end

or even

Data = load(“datafile”, true)

Wow!! I did not know the load method would return the anonymous module. This
is nice!

Other files which my app will need, must contain Makefile-like
structures. I would rather just “load” the file, and having the Ruby
interpreter take care of the parsing (example:)

ALSA && (
depend “audio/alsa-driver” { |p| p.version >= 0.9 }
configure << “–enable-alsa”
)

where ‘depend’ and ‘configure’ are just methods in the current instance,
and ‘ALSA’ a constant defined in a module that got included. But again
using ‘obj.instance_eval File.new(“file”).read’ is the only thing I can
think of.

To do it, Kernel#load would need to accept a Module as second
argument, like as:

load(“depend”, Data)

Although I don’t guess this modification rarely breaks existing
code, but not sure it’s a good thing.

I think I’ll have to stick to eval. Of cource eval is dangerous, but my
process runs a an unprivileged user (like ‘nobody’) and the scripts are
trusted.

Thanks for your ideas (also the others :slight_smile:
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

···

On Sunday 26 January 2003 13:57, nobu.nokada@softhome.net wrote:

At Sun, 26 Jan 2003 06:18:09 +0900, > > Wilbert Berendsen wrote:

Hi,

module Data
load “datafile”
end

Kernel#load code in the file into toplevel context if (omitted)
second argument is false, or an anonymous module.

If it were return that anonymous module, you can write as:

Wrong. What you want is can be done as

class Module
def module_load(file)
module_eval(IO.read(file))
end
end
class Class
alias class_load module_load
end

Data = Module.new
Data.module_load(“datafile”)

where ‘depend’ and ‘configure’ are just methods in the current instance, and
‘ALSA’ a constant defined in a module that got included. But again using
‘obj.instance_eval File.new(“file”).read’ is the only thing I can think of.

Is instance_eval really necessary? If you want to load into
same module again, just module_load for that module too.

···

At Sun, 26 Jan 2003 21:57:18 +0900, nobu.nokada@softhome.net wrote:


Nobu Nakada

Does anybody have a nice hint or better trick to create data- or
config files
readable with Ruby without having to write parsers in ruby?

I recently helped someone write code to do
something similar… it basically did a split
on the = sign, used the lefthand side as a
hash key; then we used the hash keys to make
a Struct and stored the values in the struct.

If your righthand side is other than a simple
string, you might want to eval. Unless you
consider eval evil. :slight_smile:

Hal

···

----- Original Message -----
From: “Daniel Carrera” dcarrera@math.umd.edu
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Saturday, January 25, 2003 9:37 PM
Subject: Re: datafiles as Ruby source musings

On Sun, Jan 26, 2003 at 12:12:31PM +0900, ahoward wrote:

let me repeat: YAML

Keep in mind that the YAML spec is still a working draft, albeit in “Last Call.”

James