README.rdoc

Path: README.rdoc
Last Update: Wed Apr 17 08:03:40 +0000 2013

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:

  • gem install delano-caesars —source gems.github.com
  • git clone git://github.com/delano/caesar.git

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

  • OrderedHash implementation by jan molic
  • Delano Mandelbaum (delano@solutious.com)

Thanks

  • Clams, Tomatoes, Grey Goose, and the rest of the crew.
  • Caleb Buxton (cpb.ca) for early feedback.
  • Solutious Inc (solutious.com)

Related Projects

License

See: LICENSE.txt

[Validate]