Forum: Ruby a DSL + scope problem

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Srijayanth S. (Guest)
on 2009-05-05 11:24
(Received via mailing list)
Hello,

Wrt:

http://groups.google.com/group/comp.lang.ruby/brow...

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
Brian C. (Guest)
on 2009-05-05 14:32
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@(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.
Srijayanth S. (Guest)
on 2009-05-06 08:49
(Received via mailing list)
Thanks Brian,

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

Jayanth
Robert D. (Guest)
on 2009-05-06 11:13
(Received via mailing list)
On Wed, May 6, 2009 at 6:49 AM, Srijayanth S.
<removed_email_address@domain.invalid> 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 S. (Guest)
on 2009-05-06 14:54
(Received via mailing list)
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
This topic is locked and can not be replied to.