@@ -20,18 +20,51 @@ def initialize(model=nil, options={})
2020 options = model . dup if options . empty? && model . is_a? ( Hash )
2121 required_hooks ( options )
2222 optional_hooks ( options )
23+ set_values ( options )
2324 super
2425 end
2526 end
2627
2728 module ClassMethods
29+
30+ def inherited ( subclass )
31+ super
32+ subclass . property_keys *self . all_property_keys
33+ end
34+
35+ # contains all property keys, or property hashes regardless of wheter they are optional or required
36+ # used in order to initialize values of properties correctly for subclasses and make properties inheritable
37+ def all_property_keys
38+ @all_properties . flatten! &.uniq! if defined? @all_properties
39+ @all_properties ||= [ ]
40+ end
41+
42+ def created_properties
43+ @created_properties ||= [ ]
44+ end
45+
46+ # add property keys to array containing all property keys
47+ def property_keys ( *attributes )
48+ attributes . each do |attribute |
49+ if attribute . is_a? ( Hash )
50+ attribute . each do |temp |
51+ all_property_keys . push ( { "#{ temp . first } " : temp . last } )
52+ end
53+ else
54+ all_property_keys . push ( attribute )
55+ end
56+ end
57+ end
58+
2859 # define optinoal properties for custom components with `optional :foo, :bar`
2960 def optional ( *properties )
61+ property_keys *properties
3062 add_properties_to_list ( optional_properties , properties )
3163 end
3264
3365 # define required properties for custom components with `requires :title, :foo, :bar`
3466 def requires ( *properties )
67+ property_keys *properties
3568 add_properties_to_list ( requires_properties , properties )
3669 end
3770
@@ -47,7 +80,7 @@ def add_properties_to_list(list, properties)
4780
4881 # array of properties created from the component
4982 def optional_properties
50- @component_properties ||= [ ]
83+ @optional_properties ||= [ ]
5184 end
5285
5386 # array of required properties from the component
@@ -58,30 +91,50 @@ def requires_properties
5891
5992 def optional_hooks ( options )
6093 self . class . optional_properties . compact . each do |prop |
61- if prop . is_a? Array
62- hash = prop . flatten
63- options [ hash . last [ :as ] ] = options [ hash . first ]
64- prop = hash . last [ :as ]
65- end
66- raise PropertyOverwritingExistingMethodException , "Optional property #{ prop } would overwrite already defined instance method for #{ self . class } " if self . respond_to? prop
67- send ( :define_singleton_method , prop ) do
68- options [ prop ]
69- end
94+ prop = extract_property_key ( options , prop )
95+ if self . respond_to? ( prop ) && !self . class . created_properties . include? ( prop )
96+ raise PropertyOverwritingExistingMethodException , "Optional property \" #{ prop } \" would overwrite already defined instance method for #{ self . class } " if self . respond_to? prop
97+ end
98+ define_getter_and_setter_for_property ( prop )
7099 end
71100 end
72101
73102 def required_hooks ( options )
74103 self . class . requires_properties . compact . each do |prop |
75- if prop . is_a? Array
76- hash = prop . flatten
77- options [ hash . last [ :as ] ] = options [ hash . first ]
78- prop = hash . last [ :as ]
79- end
104+ prop = extract_property_key ( options , prop )
80105 raise PropertyMissingException , "Required property #{ prop } is missing for #{ self . class } " if options [ prop ] . nil?
81- raise PropertyOverwritingExistingMethodException , "Required property #{ prop } would overwrite already defined instance method for #{ self . class } " if self . respond_to? prop
82- send ( :define_singleton_method , prop ) do
83- options [ prop ]
106+ if self . respond_to? ( prop ) && !self . class . created_properties . include? ( prop )
107+ raise PropertyOverwritingExistingMethodException , "Required property \" #{ prop } \" would overwrite already defined instance method for #{ self . class } " if self . respond_to? prop
84108 end
109+ define_getter_and_setter_for_property ( prop )
110+ end
111+ end
112+
113+ def set_values ( options )
114+ self . class . all_property_keys . compact . each do |prop |
115+ value_key = prop
116+ prop = extract_property_key ( options , prop )
117+ send ( :"#{ prop } =" , options [ prop ] )
118+ end
119+ end
120+
121+ # returns property key and sets alias if hash with as option is given
122+ def extract_property_key ( options , prop )
123+ if prop . is_a? ( Array ) || prop . is_a? ( Hash )
124+ hash = prop . flatten
125+ options [ hash . last [ :as ] ] = options [ hash . first ]
126+ prop = hash . last [ :as ]
127+ end
128+ prop
129+ end
130+
131+ def define_getter_and_setter_for_property ( prop )
132+ self . class . created_properties . push ( prop )
133+ self . class . send ( :define_method , prop ) do
134+ self . instance_variable_get ( :"@#{ prop } " )
135+ end
136+ self . class . send ( :define_method , :"#{ prop } =" ) do |value |
137+ self . instance_variable_set ( :"@#{ prop } " , value )
85138 end
86139 end
87140
0 commit comments