Class: Class

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

Overview

:nodoc:#

Instance Method Summary collapse

Instance Method Details

#constructor(*attrs, &block) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/constructor.rb', line 4

def constructor(*attrs, &block)
  call_block = ''
  if block_given?
    @constructor_block = block
    call_block = 'self.instance_eval(&self.class.constructor_block)'
  end
  # Look for embedded options in the listing:
  opts = attrs.find { |a| a.kind_of?(Hash) and attrs.delete(a) } 
  do_acc = opts.nil? ? false : opts[:accessors] == true
  do_reader = opts.nil? ? false : opts[:readers] == true
  require_args = opts.nil? ? true : opts[:strict] != false
  super_args = opts.nil? ? nil : opts[:super]

  # Incorporate superclass's constructor keys, if our superclass
  if superclass.constructor_keys
    similar_keys = superclass.constructor_keys & attrs
    raise "Base class already has keys #{similar_keys.inspect}" unless similar_keys.empty?
    attrs = [attrs,superclass.constructor_keys].flatten
  end
  # Generate ivar assigner code lines
  assigns = ''
  attrs.each do |k|
    assigns += "@#{k.to_s} = args[:#{k.to_s}]\n"
  end 

  # If accessors option is on, declare accessors for the attributes:
  if do_acc
    add_accessors = "attr_accessor " + attrs.reject {|x| superclass.constructor_keys.include?(x.to_sym)}.map {|x| ":#{x.to_s}"}.join(',')
    #add_accessors = "attr_accessor " + attrs.map {|x| ":#{x.to_s}"}.join(',')
    self.class_eval add_accessors
  end

  # If readers option is on, declare readers for the attributes:
  if do_reader
    self.class_eval "attr_reader " + attrs.reject {|x| superclass.constructor_keys.include?(x.to_sym)}.map {|x| ":#{x.to_s}"}.join(',')
  end
  
  # If user supplied super-constructor hints:
  super_call = ''
  if super_args
    list = super_args.map do |a|
      case a
      when String
        %|"#{a}"|
      when Symbol
        %|:#{a}|
      end
    end
    super_call  = %|super(#{list.join(',')})|
  end

  # If strict is on, define the constructor argument validator method,
  # and setup the initializer to invoke the validator method.
  # Otherwise, insert lax code into the initializer.
  validation_code = "return if args.nil?"
  if require_args
    self.class_eval do 
      def _validate_constructor_args(args)
        # First, make sure we've got args of some kind
        unless args and args.keys and args.keys.size > 0 
          raise ConstructorArgumentError.new(self.class.constructor_keys)
        end
        # Scan for missing keys in the argument hash
        a_keys = args.keys
        missing = []
        self.class.constructor_keys.each do |ck|
          unless a_keys.member?(ck)
            missing << ck
          end
          a_keys.delete(ck) # Delete inbound keys as we address them
        end
        if missing.size > 0 || a_keys.size > 0
          raise ConstructorArgumentError.new(missing,a_keys)
        end
      end
    end
    # Setup the code to insert into the initializer:
    validation_code = "_validate_constructor_args args "
  end

  # Generate the initializer code
  self.class_eval %{
    def initialize(args=nil)
      #{super_call}
      #{validation_code}
      #{assigns}
      setup if respond_to?(:setup)
      #{call_block}
    end
  }

  # Remember our constructor keys
  @_ctor_keys = attrs
end

#constructor_blockObject

:nodoc:#



102
103
104
# File 'lib/constructor.rb', line 102

def constructor_block #:nodoc:#
  @constructor_block
end

#constructor_keysObject

Access the constructor keys for this class



100
# File 'lib/constructor.rb', line 100

def constructor_keys; @_ctor_keys ||=[]; end