Class: Engineering::Builder::Model

Inherits:
Object
  • Object
show all
Includes:
Model::DSL
Defined in:
lib/builder/model.rb

Overview

Build a Model subclass

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Model::DSL

#attr_accessor, #attr_reader, #attr_writer

Constructor Details

#initializeModel

Returns a new instance of Model.



16
17
18
# File 'lib/builder/model.rb', line 16

def initialize
    @attribute_defaults = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

The second half of the instance_eval delegation trick mentioned at

http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation


55
56
57
58
59
60
61
# File 'lib/builder/model.rb', line 55

def method_missing(method, *args, &block)
    if @klass.respond_to? method
 @klass.send method, *args, &block
    else
 @self_before_instance_eval.send method, *args, &block
    end
end

Class Method Details

.build(&block) ⇒ Object

Convenience method for creating a new builder and evaluating a block



12
13
14
# File 'lib/builder/model.rb', line 12

def self.build(&block)
    self.new.build(&block)
end

Instance Method Details

#build(super_class = ::Model, &block) ⇒ Object

Evaluate a block and return a new Engineering::Builder::Model subclass

Use the trick found here http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation
to allow the DSL block to call methods in the enclosing *lexical* scope


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/builder/model.rb', line 23

def build(super_class=::Model, &block)
    @klass = Class.new(super_class)
    if block_given?
 @self_before_instance_eval = block.binding.eval('self')
 self.instance_eval(&block)

 # Instance variable values for read-only attributes need special handling
 options = @attribute_defaults.select {|k,v| @klass.respond_to? k.to_s + '=' } # Find the ones that can be set normally
 instance_variable_defaults = @attribute_defaults.reject {|k,v| @klass.respond_to? k.to_s + '=' } # These must be set directly

 @klass.send :define_method, :initialize do |*args, &block|
      # Directly set the read-only instance variables
      instance_variable_defaults.each {|k,v| instance_variable_set('@' + k.to_s, v) }

      # Handle the others normally, while evaluating any blocks
      super(*(options.map {|k,v| { k => (v.respond_to?(:call) ? v.call : v) } }), *args, &block)

      # Push the default geometry
      self.class.instance_variable_get(:@elements).each do |a|
  if a.is_a? Array
        push a.first.new(*a.last)
  else
        push a
  end
      end
 end
    end
    @klass
end