Module: Metro::PropertyOwner::ClassMethods
- Defined in:
- lib/metro/models/properties/property_owner.rb
Instance Method Summary collapse
-
#_sub_property(name, options = {}, &block) ⇒ Object
Defines the sub-properties defined within the property.
-
#property(name, options = {}, &block) ⇒ Object
Define a property for the model.
Instance Method Details
#_sub_property(name, options = {}, &block) ⇒ Object
Defines the sub-properties defined within the property. This is to be used internally by the #property method.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/metro/models/properties/property_owner.rb', line 94 def _sub_property(name,={},&block) # Use the name as the property type if one has not been provided. property_type = [:type] || name property_class = Model::Property.property(property_type) parents = Array([:parents]) method_name = name if [:prefix] method_name = (parents + [name]).join("_") end # Define a getter for the sub-property that will traverse the # parent properties, finally returning the filtered value define_method method_name do raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) } property_class.new(self,).get raw_value end # Define a setter for the sub-property that will find the parent # value and set itself on that with the filtered value. The parent # is then set. # # @TODO: If getters return dups and not instances of the original object then a very # deep setter will not be valid. # define_method "#{method_name}=" do |value| parent_value = parents.inject(self) {|current,method| current.send(method) } prepared_value = property_class.new(self,,&block).set(value) parent_value.send("#{name}=",prepared_value) send("#{parents.last}=",parent_value) end end |
#property(name, options = {}, &block) ⇒ Object
Define a property for the model. A property has a name and then can optionally specify a property type which will receive additional options.
When the property name matches a property definition with that name they will be used. This is what happens for the ‘position’ and ‘image’ properties defined above. Both of those map to respective properties with matching names.
Properties by default are assumed to be numeric properties so the types does not have to be stated. This is the case for ‘angle’ and ‘turn_amount’ properties.
You may use any particular name for your properties as long as you specify the type. This is the case for the ‘motto’ property.
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 |
# File 'lib/metro/models/properties/property_owner.rb', line 47 def property(name,={},&block) # Use the name as the property type if one has not been provided. property_type = [:type] || name property_class = Model::Property.property(property_type) define_method name do raw_value = properties[name] unless parsed_value = instance_variable_get("@_property_parsed_#{name}") parsed_value = property_class.new(self,,&block).get(raw_value) instance_variable_set("@_property_parsed_#{name}",parsed_value) end parsed_value end define_method "#{name}=" do |value| instance_variable_set("@_property_parsed_#{name}",nil) prepared_value = property_class.new(self,).set(value) send("#{name}_changed",prepared_value) if respond_to? "#{name}_changed" properties[name] = prepared_value end # Define any sub-properties defined on this property # When the name does not match the property type then we want to force # the prefixing to be on for our sub-properties. This is to make sure # that when people define multiple fonts and colors that they do not # overlap. override_prefix = !(name == property_type) property_class.defined_properties.each do |subproperty| = { prefix: override_prefix }.merge(subproperty.) = .merge(parents: (Array([:parents]) + [name])) _sub_property subproperty.name, end end |