Ruby as a configuration language

  • Thread starter Tapio Kelloniemi
  • Start date
T

Tapio Kelloniemi

Hi

I'm writing an automated software building framework in Ruby. The software
compiles software packages from source code using human-written profiles. The
profiles should be extremely easy to read and write by humans (and easy to
parse by a program). I wish I could write the profiles in Ruby to avoid
creating yet another advanced configuration language. But... it seems that I
might not be able to do that. What I want is something like this:

# An example package description file. The actual building commands are
# written in a bash script.
name = "gcc"
version = "4.1.1"
title = " "GNU Compiler Collection"
description = "..."

archive {
localname = "#{name}-#{version}.tar.bz2"
originalname = "#{name}-#{version}.tar.gz"
baseurl "ftp://ftp.gnu.org/gnu/gcc/#{version}/"
baseurl "ftp.mirror.site/gnu/gcc/#{version}/"
convert = "gz-bz2"
}

# Optional components
feature "gfortran" {
title = "Fortran compiler"
depend "gmp"
}

### END example

So my question is: is there a way to do this so that I would eval this package
description file and appropriate fields of internal objects would be filled
by the evaluated script?

Thanks in advance!
 
P

Phrogz

Tapio said:
I wish I could write the profiles in Ruby to avoid
creating yet another advanced configuration language.

Some people will suggest YAML. That's certainly a reasonable way to
go. Don't create your own config language when a simple markup exists
that translates painlessly into Ruby data structures.
# An example package description file. The actual building commands are
# written in a bash script.
name = "gcc"
version = "4.1.1"
title = " "GNU Compiler Collection"
description = "..."

archive {
localname = "#{name}-#{version}.tar.bz2"
originalname = "#{name}-#{version}.tar.gz"
baseurl "ftp://ftp.gnu.org/gnu/gcc/#{version}/"
baseurl "ftp.mirror.site/gnu/gcc/#{version}/"
convert = "gz-bz2"
}

# Optional components
feature "gfortran" {
title = "Fortran compiler"
depend "gmp"
}

### END example

If you want a true DSL, here's some untested code pointing you in the
right direction. I have no idea if you can have more than one archive,
or more than one feature, or more than one baseurl per Archive...but
you can do it.

class Archive
attr_accessor :localname, :eek:riginalname, :baseurl, :convert
end

class Feature
attr_accessor :title, :dependency
def depend( depends_on )
@dependency = depends_on
end
end

def archive( &block )
$archive = Archive.new
$archive.instance_eval( &block )
end

$features = []
def feature( &block )
f = Feature.new
$features << f
f.instance_eval( &block )
end
 
S

Simon Strandgaard

I'm writing an automated software building framework in Ruby. The software
compiles software packages from source code using human-written profiles. The
profiles should be extremely easy to read and write by humans (and easy to
[snip]

There is a Ruby replacement of make, that can give you some
inspiration on how to do it. Perhaps rake can do all what you want?
http://rake.rubyforge.org/
 
P

Phrogz

class Archive
attr_accessor :localname, :eek:riginalname, :baseurl, :convert
end

Oops, I missed that baseurl was a method call there. Then you might
want something like:

class Archive
attr_accessor :localname, :eek:riginalname, :convert
def initialize
@baseurls = []
end
def baseurl( url )
@baseurls << url
end
end
 
S

Suraj Kurapati

Simon said:
I'm writing an automated software building framework in Ruby. The software
compiles software packages from source code using human-written profiles. The
profiles should be extremely easy to read and write by humans (and easy to
[snip]

There is a Ruby replacement of make, that can give you some
inspiration on how to do it. Perhaps rake can do all what you want?
http://rake.rubyforge.org/

I agree. If you're going to build a DSL for your particular domain, I
suggest building it atop Rake. Stand on the shoulders of this jolly Red
giant.
 
P

Peter Booth

You should take a look at Capistrano - its pretty amazing what it does
out of the box, is base don Rake, and makes it easy to build, configure,
and deploy applications.=20

-----Original Message-----
From: Suraj Kurapati [mailto:[email protected]]=20
Sent: Thursday, February 08, 2007 12:31 PM
To: (e-mail address removed)
Subject: Re: Ruby as a configuration language

Simon said:
I'm writing an automated software building framework in Ruby. The=20
software compiles software packages from source code using=20
human-written profiles. The profiles should be extremely easy to read
and write by humans (and easy to
[snip]
=20
There is a Ruby replacement of make, that can give you some=20
inspiration on how to do it. Perhaps rake can do all what you want?
http://rake.rubyforge.org/

I agree. If you're going to build a DSL for your particular domain, I
suggest building it atop Rake. Stand on the shoulders of this jolly Red
giant.

--
Posted via http://www.ruby-forum.com/.

------------------------------------------------------------------------
-----------------------------------------------------------.
=2EThe information contained in and accompanying this communication is
strictly confidential and intended solely for the use of the intended
recipient(s).
If you have received it by mistake please let us know by reply and then
delete it from your system; you should not copy the message or disclose
its content to anyone.
MarketAxess reserves the right to monitor the content of emails sent to
or from its systems.
Any comments or statements made are not necessarily those of
MarketAxess. For more information, please visit www.marketaxess.com.
MarketAxess Europe Limited is regulated in the UK by the FSA, registered
in England no. 4017610, registered office at 71 Fenchurch Street,
London, EC3M 4BS. Telephone (020) 7709 3100.
MarketAxess Corporation is regulated in the USA by the SEC and the NASD,
incorporated in Delaware, executive offices at 140 Broadway, New York,
NY 10005. Telephone (1) 212 813 6000.
----------------------------------------------------------
The information contained in and accompanying this communication is stric=
tly confidential and intended solely for the use of the intended recipien=
t(s).

If you have received it by mistake please let us know by reply and then d=
elete it from your system; you should not copy the message or disclose it=
s content to anyone.

MarketAxess reserves the right to monitor the content of emails sent to o=
r from its systems.

Any comments or statements made are not necessarily those of MarketAxess.=
For more information, please visit www.marketaxess.com. MarketAxess Euro=
pe Limited is regulated in the UK by the FSA, registered in England no. 4=
017610, registered office at 71 Fenchurch Street, London, EC3M 4BS. Telep=
hone (020) 7709 3100.

MarketAxess Corporation is regulated in the USA by the SEC and the NASD, =
incorporated in Delaware, executive offices at 140 Broadway, New York, NY=
10005. Telephone (1) 212 813 6000.
 
B

Brian Candler

# An example package description file. The actual building commands are
# written in a bash script.
name = "gcc"
version = "4.1.1"
title = " "GNU Compiler Collection"
description = "..."

archive {
localname = "#{name}-#{version}.tar.bz2"
originalname = "#{name}-#{version}.tar.gz"
baseurl "ftp://ftp.gnu.org/gnu/gcc/#{version}/"
baseurl "ftp.mirror.site/gnu/gcc/#{version}/"
convert = "gz-bz2"
}

# Optional components
feature "gfortran" {
title = "Fortran compiler"
depend "gmp"
}

### END example

I did something a bit like this, using Rake, for building mail software. You
can download the source, which is basically just a bunch of package building
scripts, from http://linnet.rubyforge.org/ (take the linnet-src package, or
check out from cvs)

You might be able to steal some ideas. It's not as abstracted as the way
you've described above, but I found in practice that the software packages I
was building didn't all fit into identical moulds.
 
T

Tapio Kelloniemi

I'm writing an automated software building framework in Ruby. The software
compiles software packages from source code using human-written profiles. The
profiles should be extremely easy to read and write by humans (and easy to
parse by a program). I wish I could write the profiles in Ruby to avoid
creating yet another advanced configuration language.

Thanks to all of you who responded. I thought that instance_eval would be the
solution, but I somehow overlooked it. Now I have to simulate scoping so that
code in archive and feature blocks may refer to things declared in the
top-level of the profile (which will not be real top-level, since the profile
scripts get inctance_evaled, to avoid pollution of Object). Overriding
method_missing probably solves this nicely.

Ruby is a great thing (although it lacks multiple dispatching and
multiple inheritance)!
 
J

Joel VanderWerf

Tapio said:
Thanks to all of you who responded. I thought that instance_eval would be the
solution, but I somehow overlooked it. Now I have to simulate scoping so that
code in archive and feature blocks may refer to things declared in the
top-level of the profile (which will not be real top-level, since the profile
scripts get inctance_evaled, to avoid pollution of Object). Overriding
method_missing probably solves this nicely.

Ruby is a great thing (although it lacks multiple dispatching and
multiple inheritance)!

You could evaluate the whole config file inside of a scope (for example,
a module), and then pull objects out of this module as you need them.

There's one way to do this in:

http://redshift.sourceforge.net/script/

You can make methods like "archive" and "feature" available by
subclassing the Script module and defining them as module methods.

$ cat config-script.rb
name = "gcc"
version = "4.1.1"
title = "GNU Compiler Collection"
description = "..."

archive {
localname "#{name}-#{version}.tar.bz2"
#originalname "#{name}-#{version}.tar.gz"
#baseurl "ftp://ftp.gnu.org/gnu/gcc/#{version}/"
#baseurl "ftp.mirror.site/gnu/gcc/#{version}/"
#convert "gz-bz2"
}

# Optional components
feature("gfortran") {
title "Fortran compiler"
#depend "gmp"
}

$ cat parser.rb
require 'script'

class Archive
def localname n; @localname = n; end
# etc.
end

class Feature
def initialize arg; @arg = arg; end
def title t; @title = t; end
# etc.
end

class ConfigScript < Script
def archive(&bl)
@archive = Archive.new
@archive.instance_eval(&bl)
end

def feature(arg, &bl)
@feature = Feature.new(arg)
@feature.instance_eval(&bl)
end

def inspect
super + [@archive, @feature].inspect
end
end

config_script = ConfigScript.load("config-script.rb")

p config_script

$ ruby parser.rb
#<ConfigScript:/home/vjoel/tmp/scr/config-script.rb>[#<Archive:0xb7cb5ff4
@localname="gcc-4.1.1.tar.bz2">, #<Feature:0xb7cb5f7c @arg="gfortran",
@title="Fortran compiler">]

This doesn't really try to solve your parsing questions. It's just an
example of how to eval the script inside a scope and not let that leak
out into the global scope.

It might be less work if you can accept a config file of the form:

$ cat config-script2.rb
NAME = "gcc"
VERSION = "4.1.1"
TITLE = "GNU Compiler Collection"
DESCRIPTION = "..."

ARCHIVE = {
:localname => "#{NAME}-#{VERSION}.tar.bz2"
}

module Features
GFORTRAN = {
:title => "Fortran compiler"
}
end

Then the parser is just:

$ cat parser2.rb
require 'script'

config_script = Script.load("config-script2.rb")

p config_script

p config_script::NAME

p config_script::ARCHIVE

config_script::Features.constants.each do |c|
p(c=>config_script::Features.const_get(c))
end

$ ruby parser2.rb
#<Script:/home/vjoel/tmp/scr/config-script2.rb>
"gcc"
{:localname=>"gcc-4.1.1.tar.bz2"}
{"GFORTRAN"=>{:title=>"Fortran compiler"}}


Anyway, I hope this suggests some of the possibilities for scoping your
DSL. There are lots of possibilities for sweetening up the syntax.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top