Caesars - v0.7

A simple class for rapid DSL prototyping in Ruby.

NOTE: Post-processing of Caesars::Config subclasses changed in 0.7. In 0.6 and earlier, the post-processing hook (Caesars::Config#postprocess) was called after every file was loaded. In 0.7 it's called after all files have been loaded. This could break some highly dependent code in your subclasses of Caesars::Config so I apologize but I believe this is the right thing to do. If you are not satisfied with that apology, prepare yourself a caesar or bloody mary or any other beverage and send email me with the details!

Installation

One of:

  • gem install caesars
  • copy lib/caesars.rb into your lib directory.

Or for GitHub fans:

EXAMPLE 1 -- A Simple DSL

 require 'caesars'

 class Flavour < Caesars  # Subclass Caesars. 
 end
 
 extend Flavour::DSL     # Bring the DSL into the current namespace. 
                         # This module is created dynamically based
                         # on the name of the subclass.
 
 flavour do              # Start drinking! I mean, start writing your
   spicy true            # domain specific language! 
   clamy true            # Use any attribute name you want.
   salty true
   vodka :very_true      # And any value you want. 
 end
 
 p @flavour              # => #<Flavour:0x3f56b0 ...>
 p @flavour.spicy        # => true

EXAMPLE 2 -- Storing Blocks as Procs

 require 'caesars'
 
 class Staff < Caesars
 
   chill :calculate      # Delay execution of the blocks for the calculate
                         # attribute. They will be stored as Procs.                      
 end
 
 extend Staff::DSL
 
 # The top level method is the lower case name of the class. For deeper
 # names like Class::SecondLevel it will use the final name 
 # (i.e. secondlevel). You can supply an optional modifier name which 
 # will be included in the instance variable (@staff_fte).
 staff :fte do
   desc 'Our hard-working, "full-time" staff'

   location :splashdown do
     town :tsawwassen

     person :steve, :sheila do
       role :manager
     end

     person :steve do
       role :cook
       anger :high
       hours 25
       catchphrase "Rah! [strokes goatee]"
     end

     person :sheila do
       catchphrase "This gravy tastes like food I ate in a Mexican prison."
       hours rand(20)
       rate "9.35/h"
       calculate :salary do |gumption|
         ("%.2f" % [gumption * self.splashdown.sheila.rate.to_f]).to_f
       end
     end

     person :delano do
       role :cook
       rate "8.35/h"
       hours 57
       satisfaction :low
       calculate :salary do 
         self.splashdown.delano.rate.to_f * self.splashdown.delano.hours
       end
     end

   end
 end
 
 p @staff_fte                    # => #<Staff: ...>
 p @staff_fte.desc               # => Our hard-working, "full-time" staff
 
 # Deeper attributes are also available via instance methods
 p @staff_fte.splashdown.delano  # => {:role=>:cook, :rate=>"$8.35/h", :satisfaction=>:low}
 p @staff_fte.splashdown.sheila  # => {:role=>:manager, :catchphrase=>"This gravy tastes like food I ate in a Mexican prison."}
 p @staff_fte.splashdown.steve   # => {:role=>[:manager, :cook], :anger=>:high, :catchphrase=>"Rah! [strokes goatee]"}
 p @staff_fte.splashdown.delano.satisfaction   # => :low
 
 # You can also access them using hash syntax
 p @staff_fte.splashdown[:steve][:role]  # => [:manager, :cook]
 
 # The "chilled" attributes store their blocks as Procs and are not executed automatically. 
 # You can call them manually and send arguments like you normally would. 
 p @staff_fte.splashdown.delano.salary.call             # => 475.95
 p @staff_fte.splashdown.sheila.salary.call(rand(100))  # => 549.77

EXAMPLE 3 -- External Config Files

 require 'caesars'
 
 class Food < Caesars
   chill :order
 end
 class Drink < Caesars
 end
 
 class PartyConfig < Caesars::Config
   dsl Food::DSL
   dsl Drink::DSL
 end
 
 conffile = File.join(File.dirname(__FILE__), 'party.conf')
 @config = PartyConfig.new(conffile)
 
 p @config.food.order.call   # => 10kg
 p @config[:drink][:wine]    # => 12L
 p @config                   # => <PartyConfig:0x3f780c ...>
 p @config.keys              # => [:food, :drink]
 
 # [... make changes to party.conf ...]
 
 @config.refresh

party.conf

 food do 
   oysters "10kg"
   order do
     self.oysters
   end
 end
 
 drink do
   wine "12L"
 end

More Info

Credits

Thanks

License

See: LICENSE.txt