# Playing with DSLs, a question or two

**URL:** <https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828>\
**Category:** Ruby\
**Created:** [February 11, 2013, 4:19pm UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828 "2013-02-11T16:19:22Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![tekhne](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/90ced4/32.png) [@tekhne](https://www.ruby-forum.com/u/tekhne)\
**Post date:** [February 11, 2013, 4:19pm UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828/1 "2013-02-11T16:19:22Z")

</div>

I am playing around with writing some DSLs to help me get more familier  
with how they work and I have a couple of questions. First here’s an  
example of one I am playing with (based on the classic dungeon adventure  
problem)

class Adventure  
def initialize  
@rooms = Hash.new  
@current\_room = nil  
end

def room(reference, &block)  
if @rooms.has\_key?(reference)  
puts “Error: Room #{reference} has already been defined”  
else  
@rooms[reference] = {:short =\> ‘’, :long =\> ‘’, :exits =\>  
Hash.new}  
end

```
@current_room = reference

yield block

```

end

def short(text)  
@rooms[@current\_room][:short] = text  
end

def long(text)  
@rooms[@current\_room][:long] = text  
end

def door(direction, destination, &block)  
if @rooms[@current\_room][:exits].has\_key?(direction)  
puts “Error: Room #{@current\_room} already has an exit defined in  
#{direction}”  
else  
@rooms[@current\_room][:exits][direction] = {:where =\> destination,  
:condition =\> block\_given? ? block : true}  
end  
end  
end

class Object  
def adventure(&block)  
a = Adventure.new

```
a.instance_eval(&block)

```

end  
end

adventure do  
room :cave do  
short “You are in a large cave”  
long “You are in a very large cave”  
door :west, :another\_cave  
door :east, :exit do  
if player.has\_item(:key)  
true  
else  
false  
end  
end  
end

room :another\_cave do  
short “A cave”  
long “Oh great … another cave”  
door :east, :cave  
end

room :exit do  
short “Freedom”  
long “Freeeeeeeeeeedom!!!”  
door :west, :cave  
end

require ‘pp’  
pp @rooms  
end

Now this works just fine but a couple of things just don’t seem right.  
Notice the @current\_room variable that is set in the room method and  
referenced in short, long and door. This seems clunky - it is basically  
a  
global variable to help tie things together. Is there some better way of  
doing this? Perhaps by passing it as a parameter somehow.

Also is the yield at the bottom of the room method the right way to go  
or  
should I be calling instance\_eval or similar?

Also how do I stop, for example, the door method being called outside of  
the room method? I have a solution where I set @current\_room to nil  
after  
the yield and then each method checks to see if it is set and if not it  
errors. But again this seems to be quite a pain.

---

<div class="post-metadata">

**Author:** ![tekhne](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/90ced4/32.png) [@tekhne](https://www.ruby-forum.com/u/tekhne)\
**Post date:** [February 11, 2013, 6:21pm UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828/2 "2013-02-11T18:21:00Z")

</div>

Hey Peter,

How does this look? [DSLs · GitHub](https://gist.github.com/cookrn/4755773)

By making the Room a separate object, the scoping might be more as you  
had  
hoped e.g. the door method

Regarding the yield vs. instance\_eval – this is a matter of opinion. If  
you wanted to be very explicit, you could yield the adventure and room  
objects to the blocks given to those methods. This makes your DSL seem a  
bit less magic, but maybe that’s ok.

I gave a talk on DSLs at Boulder Ruby a while back that you might find  
interesting: [DSLs As Teaching Tools - Speaker Deck](https://speakerdeck.com/cookrn/dsls-as-teaching-tools)

Ryan

On Mon, Feb 11, 2013 at 8:18 AM, Peter H. \<

---

<div class="post-metadata">

**Author:** ![tekhne](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/90ced4/32.png) [@tekhne](https://www.ruby-forum.com/u/tekhne)\
**Post date:** [February 11, 2013, 9:42pm UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828/3 "2013-02-11T21:42:41Z")

</div>

Thanks Ryan.

That was just the sort of thing I was looking for.

Thanks for that.

---

<div class="post-metadata">

**Author:** ![tekhne](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/90ced4/32.png) [@tekhne](https://www.ruby-forum.com/u/tekhne)\
**Post date:** [February 12, 2013, 12:08pm UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828/4 "2013-02-12T12:08:31Z")

</div>

Gulys

Thanks for that. It woud seem that picking an adventure game was the  
best  
choice for learning DSLs. At least I understand the domain 🙂

Peter

---

<div class="post-metadata">

**Author:** ![tekhne](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/90ced4/32.png) [@tekhne](https://www.ruby-forum.com/u/tekhne)\
**Post date:** [February 12, 2013, 11:53am UTC](https://www.ruby-forum.com/t/playing-with-dsls-a-question-or-two/229828/5 "2013-02-12T11:53:20Z")

</div>

Hi,

Dwemthy’s Array by Why can also be helpful  
[http://mislav.uniqpath.com/poignant-guide/dwemthy/](http://mislav.uniqpath.com/poignant-guide/dwemthy/)

ati
