@@ -20,18 +20,51 @@ def initialize(model=nil, options={})
20
20
options = model . dup if options . empty? && model . is_a? ( Hash )
21
21
required_hooks ( options )
22
22
optional_hooks ( options )
23
+ set_values ( options )
23
24
super
24
25
end
25
26
end
26
27
27
28
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
+
28
59
# define optinoal properties for custom components with `optional :foo, :bar`
29
60
def optional ( *properties )
61
+ property_keys *properties
30
62
add_properties_to_list ( optional_properties , properties )
31
63
end
32
64
33
65
# define required properties for custom components with `requires :title, :foo, :bar`
34
66
def requires ( *properties )
67
+ property_keys *properties
35
68
add_properties_to_list ( requires_properties , properties )
36
69
end
37
70
@@ -47,7 +80,7 @@ def add_properties_to_list(list, properties)
47
80
48
81
# array of properties created from the component
49
82
def optional_properties
50
- @component_properties ||= [ ]
83
+ @optional_properties ||= [ ]
51
84
end
52
85
53
86
# array of required properties from the component
@@ -58,30 +91,50 @@ def requires_properties
58
91
59
92
def optional_hooks ( options )
60
93
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 )
70
99
end
71
100
end
72
101
73
102
def required_hooks ( options )
74
103
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 )
80
105
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
84
108
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 )
85
138
end
86
139
end
87
140
0 commit comments