if the '$5-$10 Limit' list is more than 12 then notify the floor to open

if the '$1-$2 No Limit' list is more than 15 then notify the floor to open

if the '$5-$10 Limit' list is more than 8 then notify the brush to announce

if the '$1-$2 No Limit' list is more than 10 then notify the brush to announce

class ContextOne < DslContext



bubble :than, :is, :list, :the, :to



def more(value)

'> ' + value.to_s

end



def method_missing(sym, *args)

@stakes = sym

eval "List.size_for(sym) #{args.first}"

end



def floor(value)

__position(value, :floor)

end



def brush(value)

__position(value, :brush)

end



def open

__action(:open)

end



def announce

__action(:announce)

end



def __action(to)

{ :action => to }

end



def __position(value, title)

value[:position] = title

value

end



def notify(value)

[@stakes, value]

end



end

class ContextTwo < DslContext



bubble :than, :is, :list, :the, :to, :more, :notify, :floor, :open, :brush



def announce

@stakes

end



alias open announce



def method_missing(sym, *args)

@stakes = sym

end



end

class ContextThree < DslContext



bubble :than, :is, :list, :the, :to, :more, :notify, :announce, :open, :open



def announce; end

def open; end



def brush(value)

:brush

end



def floor(value)

:floor

end



def method_missing(sym, *args)

true

end



end

Creating an internal DSL (or embedded DSL) is challenging, but it does provide many advantages. One advantage to expressing your business rules in an internal DSL is the ability to execute them in various contexts. By executing the DSL in various contexts you can generate multiple behaviors from the same business rule. When the rule changes over time, all parts of the system that reference the rule will also be changed.For example assume you work for a casino and you have been tasked with designing a system that will notify the poker room employees when a new table needs to be opened or when you are looking to open a new table. The rules for opening a table vary based on the stakes of the table and the length of the waiting list. For example, you need more people waiting for a no limit game because people go broke more quickly and you don't want the table to be short-handed shortly after you open it. The rules would be expressed in your DSL like this:The first context in which I will execute the DSL is the context that notifies the employees.ContextOne uses the DSL to check the List for the size per stakes and sends notifications when necessary. This is of course sample code and my List object is just a stub to verify that everything works correctly. I'll add a link to the sample code at the end of the post.Based on this same script you could execute a second context that returns a list of the different games that are currently being spread.As you can see, adding additional contexts is very easy. Another could be added to display all positions that are set up to receive notices.Executing a DSL script in multiple contexts begins to blur the line between code and data. The script 'code' can also be executed to do things such as generate reports (i.e. A report of which employees are contacted by the system). The script could also be executed in a context that will show how long before a table will be opened (i.e. the rule states that 15 are needed, the system knows 10 are on the list so it displays the message '5 more people needed before the game can start').A note on implementation: In my experience it is much easier to create a class per context and execute in the scope of that object. An alternative is to execute the script in the scope of one object that creates a generic object graph. The problem with this approach is finding an object graph that is generic enough to be useful in several situations. Clearly, I prefer the first approach.Sample Code: http://www.jayfields.com/src/dslcontext.txt