A DSL + scope problem

Hello,

Wrt:

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/689cbe271d680979/5ba5a52ba929b142?lnk=raot&fwc=2&pli=1

Basically I have a log file where different lines need to be mapped to
different statements, for instance:

“Look a shiny red Ferrari!” → “Italian metal”

However, it is not a simple mapping alone, there also needs to be some
intelligence and a state needs to be kept in order to determine some
other
fancy stuff. Anyway, the point is, I had an ugly design involving
abstract
classes and so on, I’ve gone on to making a DSL where a person can do
the
following:

rule name is fairly pointless, just used to trigger the method_missing

call :slight_smile:
rule_name /regEx/ do |line|

process the line, apply logic

Return a mapped new string

end

Basically what the DSL lets them do is define rules and associated
blocks on
certain regexes which all gets put into a table. This has simplified
things
a lot, and all they do is create rules. Its all working fine, but now I
want
to add another feature. I want to define some common methods in the DSL
class(like formatting strings a certain way etc), but I want this to be
available to the people who define the rules and the blocks and use the
DSL.
Ideally this is easily accomplished by passing self into the blocks. But
I
don’t want to burden these chaps with what self is and so on, and
generally
speaking passing self seems a little ugly. Is there any other method you
guys can suggest?

The DSL is being instance_eval-ed…

Thank you,

Jayanth

Srijayanth S. wrote:

Basically what the DSL lets them do is define rules and associated
blocks on
certain regexes which all gets put into a table. This has simplified
things
a lot, and all they do is create rules. Its all working fine, but now I
want
to add another feature. I want to define some common methods in the DSL
class(like formatting strings a certain way etc), but I want this to be
available to the people who define the rules and the blocks and use the
DSL.
Ideally this is easily accomplished by passing self into the blocks. But
I
don’t want to burden these chaps with what self is and so on, and
generally
speaking passing self seems a little ugly. Is there any other method you
guys can suggest?

The DSL is being instance_eval-ed…

If you are doing obj.instance_eval { … } then ‘self’ is already obj.

If these helper methods are pre-defined ones, then just define them
within obj’s class. The user should be able to call them. If not,
provide a cut-down example which demonstrates the problem.

If you want the user to be able to define their own helper methods
within the DSL, this is also possible. You may find “define_method”
helpful, which can define a method within a class, given a block.

irb(main):002:0> def helper(name, &blk)
irb(main):003:1> (class << self; self; end).class_eval {
define_method(name,&blk) }
irb(main):004:1> end
=> nil
irb(main):005:0> helper(:test) { puts “hello!” }
=> #Proc:0xb7ccbed0@:5(irb)
irb(main):006:0> test()
hello!
=> nil

Also, note that class_eval also sets the context for a regular “def”. So
if the object you are instance_eval’ing within is actually a module or a
class, and you use class_eval instead, users can just stick ‘def’
statements in the DSL to define methods within that class.

irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo.class_eval %{def test; puts “hi”; end}
=> nil
irb(main):003:0> Foo.new.test
hi
=> nil

But if you are instance_eval’ing within an instance of Foo, then you
want to define methods within the singleton class of that instance,
which I think is best done using define_method as shown first.

Thanks Brian,

All of these help. Eventually I would like those using the DSL to define
their own helper methods.

Jayanth

I was thinking something of this sort:

class MyDsl
def load_helper_methods filename
MyDsl.class_eval(File.read(filename))
end
end

and the DSL itself would contain two parts really, one file where the
helper
methods are defined, and another for the actual DSL.

Basically:

$ cat foo.dsl
load_helper_methods “my_helpers”

the rest of the DSL

follows

etc

Now, for some annoying reason my head swims with yet other possibilities
such as making the helper methods a Module and have it be included in
the
class etc. Kid in a candy store and all that. Too many options.

Jayanth

On Wed, May 6, 2009 at 6:49 AM, Srijayanth S.
[email protected] wrote:

Thanks Brian,

All of these help. Eventually I would like those using the DSL to define
their own helper methods.

… which have scope of?
Robert