Class: Caesar

Inherits:
Object
  • Object
show all
Defined in:
lib/caesar.rb

Overview

Caesar – A simple class for rapid DSL prototyping.

Subclass Caesar, then tell it which attributes have children using Caesar.bloody and which have blocks that you want to execute later using Caesar.virgin. That’s it! Just start drinking! I mean, start writing your domain specific language!

See README.rdoc for a usage example.

Defined Under Namespace

Classes: Hash

Constant Summary collapse

VERSION =
"0.3.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = nil) ⇒ Caesar

Creates an instance of Caesar. name is .



27
28
29
30
31
# File 'lib/caesar.rb', line 27

def initialize(name=nil)
  @caesar_name = name if name
  @caesar_properties = Caesar::Hash.new
  @caesar_pointer = @caesar_properties
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &b) ⇒ Object

This method handles all of the attributes that do not contain blocks.



33
34
35
36
37
38
39
40
41
# File 'lib/caesar.rb', line 33

def method_missing(name, *args, &b)
  return @caesar_properties[name] if @caesar_properties.has_key?(name) && args.empty? && b.nil?
  if @caesar_pointer[name]
    @caesar_pointer[name] = [@caesar_pointer[name]] unless @caesar_pointer[name].is_a?(Array)
    @caesar_pointer[name] += args
  elsif !args.empty?
    @caesar_pointer[name] = args.size == 1 ? args.first : args
  end
end

Instance Attribute Details

#caesar_propertiesObject

An instance of Caesar::Hash which contains the data specified by your DSL



24
25
26
# File 'lib/caesar.rb', line 24

def caesar_properties
  @caesar_properties
end

Class Method Details

.bloody(meth, execute = true) ⇒ Object

see bin/example for usage.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/caesar.rb', line 47

def self.bloody(meth, execute=true)
  define_method(meth) do |*names,&b|  # |*names,&b| syntax does not parse in Ruby 1.8
    all = instance_variable_get("@" << meth.to_s) || []
    
    names.each do |name|
      instance_variable_set("@" << meth.to_s, all << name)
      
      if execute
        prev = @caesar_pointer
        @caesar_pointer[name] ||= Caesar::Hash.new
        @caesar_pointer = @caesar_pointer[name]
        b.call if b
        @caesar_pointer = prev
      else
        @caesar_pointer[name] = b
      end
      
    end
    nil
  end
  define_method("#{meth}_values") do ||
    instance_variable_get("@" << meth.to_s) || []
  end
end

.inherited(modname) ⇒ Object

Executes automatically when Caesar is subclassed. This creates the YourClass::DSL module which contains a single method: method_missing. This is used to catch the top level DSL method. That’s why you can used any method name you like.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/caesar.rb', line 75

def self.inherited(modname)
  meth = (modname.to_s.split(/::/))[-1].downcase  # Some::ClassName => classname
  module_eval %Q{
    module #{modname}::DSL
      def #{meth}(*args, &b)
        name = !args.empty? ? args.first.to_s : nil
        varname = "@#{meth.to_s}"
        varname << "_\#{name}" if name
        i = instance_variable_set(varname, #{modname.to_s}.new(name))
        i.instance_eval(&b) if b
        i
      end
    end
  }, __FILE__, __LINE__
end

.virgin(meth) ⇒ Object

see bin/example for usage.



43
44
45
# File 'lib/caesar.rb', line 43

def self.virgin(meth)
  self.bloody(meth, false)
end