[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

a DSL + scope problem

Srijayanth Sridhar

5/5/2009 7:24:00 AM

[Note: parts of this message were removed to make it a legal post.]

Hello,

Wrt:

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

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

4 Answers

Brian Candler

5/5/2009 10:32:00 AM

0

Srijayanth Sridhar 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@(irb):5>
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.
--
Posted via http://www.ruby-....

Srijayanth Sridhar

5/6/2009 4:49:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

Thanks Brian,

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

Jayanth

On Tue, May 5, 2009 at 4:02 PM, Brian Candler <b.candler@pobox.com> wrote:

> Srijayanth Sridhar 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@(irb):5>
> 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.
> --
> Posted via http://www.ruby-....
>
>

Robert Dober

5/6/2009 7:12:00 AM

0

On Wed, May 6, 2009 at 6:49 AM, Srijayanth Sridhar <srijayanth@gmail.com> 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

Srijayanth Sridhar

5/6/2009 10:54:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

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 12:42 PM, Robert Dober <robert.dober@gmail.com>wrote:

> On Wed, May 6, 2009 at 6:49 AM, Srijayanth Sridhar <srijayanth@gmail.com>
> 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
>
>