Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 DSLs
Index -> Programming, Ruby -> Ruby Tutorials
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Thu Dec 01, 2005 4:52 am   Post subject: DSLs

Time for a quick look at the power of Ruby to make your life easier.

The term of the day is "Domain Specific Language." Within a language's rules, we create a sub-language geared specifically toward solving one problem, as easily as possible.

The example problem is one programmers face on a regular basis in the course of learning. At some point you'll want to create a menu with various options. We could write the code out each time, but that gets tedious.

Ruby:
class Question
   def self.option(option_text, &response)
      self.class_eval do
         if c = instance_variable_get("@count")
            instance_variable_set "@count", c + 1
         else
            c = 0
            instance_variable_set "@count", c + 1
         end           
     
         if q = instance_variable_get("@options")
            q ||= []
            q <<  option_text   
            instance_variable_set "@options", q
         else
            instance_variable_set "@options", [option_text]
         end
         
         if response
            if r = instance_variable_get("@responses")
               r ||= {}
               r[c + 1] = response
               instance_variable_set "@responses", r
            else
               instance_variable_set "@responses", {c + 1 => response}
            end
         end
      end
   end
   
   def self.default_option(option_text, &response)
      self.option(option_text, &response)
     
      self.class_eval do
         instance_variable_set("@default", instance_variable_get("@count"))
      end
   end
   
   def self.question(question_text)
      self.class_eval do
         instance_variable_set "@question", question_text
      end
   end
   
   def self.error_message(err_text)
      self.class_eval do
         instance_variable_set "@err", err_text
      end
   end
   
   def self.on_select(&action)
      self.class_eval do
         instance_variable_set("@on_select", action)
      end
   end
   
   def options
      self.class.instance_variable_get("@options")
   end
   
   def question
      self.class.instance_variable_get("@question")
   end
   
   def error_msg
      self.class.instance_variable_get("@err")
   end
   
   def default_option
      self.class.instance_variable_get("@default")
   end
   
   def initialize(limit=nil)
      @limit = limit
   end
   
   def ask(indent = 0)
      counter = 0
      options_width = options.length.to_s.length
      loop do
         counter += 1
         puts "#{' ' * indent}#{question}"
         puts
         options.each_with_index do |option, index|
            puts "#{' ' * indent}#{" " * (options_width - index.to_s.length)}#{index + 1}. #{option}"
         end
         
         print "#{" " * indent}#{"[#{default_option}] " if default_option}"
         answer_string = gets
         
         answer = answer_string =~ /^\s*$/ ? default_option : answer_string.to_i
         
         if (1..options.length).include? answer
            responses = self.class.instance_variable_get("@responses")
            responses[answer].call(answer, options[answer - 1]) if responses and responses.has_key? answer
           
            on_select = self.class.instance_variable_get("@on_select")
            on_select.call(answer, options[answer - 1]) if on_select
           
            break answer
         elsif error_msg and not (@limit and counter >= @limit)
            puts
            puts "#{' ' * indent}#{error_msg}"
            puts
         elsif @limit and counter >= @limit
            break
         end
      end
   end
end


Ok, that didn't look too much better. Fortunately it's a one time pain, and now when we want to create a menu...

Ruby:
class Q < Question
   question "Foo?"
   
   default_option "foo"
   option "bar"
   option "baz"
   
   on_select { |i, o| puts o }
   
   error_message "Pick another"
end

Q.new.ask


And we end up with:

code:
Foo?

1. foo
2. bar
3. baz
[1] 2
bar


Any questions? Smile
Sponsor
Sponsor
Sponsor
sponsor
Display posts from previous:   
   Index -> Programming, Ruby -> Ruby Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 1 Posts ]
Jump to:   


Style:  
Search: