[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Ruby as a configuration language

jma

2/8/2007 3:51:00 PM

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...{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!

--
Tapio
8 Answers

Gavin Kistner

2/8/2007 4:33:00 PM

0

Tapio Kelloniemi wrote:
> 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...{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, :originalname, :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

Simon Strandgaard

2/8/2007 4:35:00 PM

0

On 2/8/07, Tapio Kelloniemi <no@such.thing> wrote:
> 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.ruby...


--
Simon Strandgaard
http://opc...

Gavin Kistner

2/8/2007 4:40:00 PM

0

On Feb 8, 9:32 am, "Phrogz" <g...@refinery.com> wrote:
> Tapio Kelloniemi wrote:
> > archive {
> > localname = "#{name}-#{version}.tar.bz2"
> > originalname = "#{name}-#{version}.tar.gz"
> > baseurl "ftp://ftp.gnu.org...{version}/"
> > baseurl "ftp.mirror.site/gnu/gcc/#{version}/"
> > convert = "gz-bz2"
> > }
> class Archive
> attr_accessor :localname, :originalname, :baseurl, :convert
> end

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

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

Suraj Kurapati

2/8/2007 5:31:00 PM

0

Simon Strandgaard wrote:
> On 2/8/07, Tapio Kelloniemi <no@such.thing> wrote:
>> 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.ruby...

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-....

Peter Booth

2/8/2007 5:56:00 PM

0

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.

-----Original Message-----
From: Suraj Kurapati [mailto:snk@gna.org]
Sent: Thursday, February 08, 2007 12:31 PM
To: ruby-talk@ruby-lang.org
Subject: Re: Ruby as a configuration language

Simon Strandgaard wrote:
> On 2/8/07, Tapio Kelloniemi <no@such.thing> wrote:
>> 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.ruby...

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-....

------------------------------------------------------------------------
-----------------------------------------------------------.
.The 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 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.



Brian Candler

2/8/2007 8:22:00 PM

0

On Fri, Feb 09, 2007 at 01:00:09AM +0900, Tapio Kelloniemi wrote:
> # 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...{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.ruby... (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.

jma

2/8/2007 9:54:00 PM

0

>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)!

--
Tapio

Joel VanderWerf

2/8/2007 10:31:00 PM

0

Tapio Kelloniemi wrote:
>> 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)!

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.n...

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...{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.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407