From: "s.ross" Date: 2008-02-20T16:06:26+09:00 Subject: Re: ruby and DSL On Feb 19, 2008, at 9:30 PM, P Rajmohan Banavi-A17190 wrote: > Are there any ruby book(s) that explains more in detail about > DSL(Domain > Specific Language) implementation in ruby? Any pointers to online > tutorials will also be of help. I don't know if there are any books that directly address this, but a good way to learn about DSLs is to pick some apart and figure out what about the language work for you and how the authors implemented it. rSpec is a great example because it uses the flexibility of Ruby to create an expressive language that models its problem domain. So, for example, you can write: result.should eql(3) This reads like English, but it is actually a clever bit of programming. There is a method called "should" that is mixed into Object by rSpec. Because everything inherits from Object, all descendent objects gain the "should" method. Simplifying a bit, the "should" method calls a matcher called "eql" with the argument 3. If "eql" returns true, then the spec passes, otherwise the spec fails. Again, this oversimplifies what's going on, but you can see that by placing method calls carefully, a very readable language for expressing specifications has been created. Another example from the rSpec bag of tricks has to do with expectations on mock objects: @cash_machine.should_receive(:withdraw).twice.and_return(true) This kind of method chaining is very nice in DSLs, but it relies on you to create a structure in which the expected return value of each method is an object on which any of the chained methods can be invoked. So, should_receive must return an object that responds to twice. twice must return an object that responds to and_return. As it turns out, you can write: @cash_machine.should_receive(:withdraw).and_return(false) @cash_machine.should_receive(:deposit).once.and_return(true) @cash_machine .should_receive(:balance).once.with_any_args.and_return(150) So you can see that rSpec expectations are crafted such that you can really chain an expressive set of constraints on an object that is being mocked. Jamis Buck writes in an older blog post (http://weblog.jamisbuck.org/2006/3/9/integration-testing-in-rails-1-1 ) about integration testing in Rails. In the process of the post, Jamis extracts a DSL out of the testing scenario so that it becomes quite natural to use. Of course, Rails is a huge example of DSLs. I don't consider Rails one DSL, but several. Obviously, ActiveRecord is an implementation of a pattern, but where the DSL part comes into play is in how relationships and validations and such are handled: class CashMachine < ActiveRecord::Base has_many :customers belongs_to :bank validates_presence_of :security_camera # ... end Well, you can see I'm not in the banking business, but no matter. The point is that even the casual reader could see that any given cash machine has many (zero or more) customers and that that machine belongs uniquely to a bank. Further, a valid cash machine has to have a security camera. It's totally readable (unlike my typical cryptic one-liners with a couple of regex'es thrown in). The trick is to evolve a language that is possible to speak. Creating a DSL has to do with having a problem domain and factoring out common operations within that domain. While it's possible to write about a very real DSL such as rSpec, or an almost-real one like Jamis' integration testing scenario, it's not possible to give you a manual and say "here's how to write your very own DSL." I hope this is useful info.