Changeset 8003
- Timestamp:
- 10/23/07 17:39:35 (2 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/aggregations.rb (modified) (3 diffs)
- trunk/activerecord/test/fixtures/customer.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r8002 r8003 1 1 *SVN* 2 3 * Assigning an instance of a foreign class to a composed_of aggregate calls an optional conversion block. Refactor and simplify composed_of implementation. #6322 [brandon, Chris Cruft] 2 4 3 5 * Assigning nil to a composed_of aggregate also sets its immediate value to nil. #9843 [Chris Cruft] trunk/activerecord/lib/active_record/aggregations.rb
r8002 r8003 123 123 # This defaults to +false+. 124 124 # 125 # An optional block can be passed to convert the argument that is passed to the writer method into an instance of 126 # <tt>:class_name</tt>. The block will only be called if the arguement is not already an instance of <tt>:class_name</tt>. 127 # 125 128 # Option examples: 126 129 # composed_of :temperature, :mapping => %w(reading celsius) 127 # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)130 # composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) {|balance| balance.to_money } 128 131 # composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ] 129 132 # composed_of :gps_location 130 133 # composed_of :gps_location, :allow_nil => true 131 134 # 132 def composed_of(part_id, options = {} )135 def composed_of(part_id, options = {}, &block) 133 136 options.assert_valid_keys(:class_name, :mapping, :allow_nil) 134 137 … … 136 139 class_name = options[:class_name] || name.camelize 137 140 mapping = options[:mapping] || [ name, name ] 141 mapping = [ mapping ] unless mapping.first.is_a?(Array) 138 142 allow_nil = options[:allow_nil] || false 139 143 140 144 reader_method(name, class_name, mapping, allow_nil) 141 writer_method(name, class_name, mapping, allow_nil )145 writer_method(name, class_name, mapping, allow_nil, block) 142 146 143 147 create_reflection(:composed_of, part_id, options, self) … … 146 150 private 147 151 def reader_method(name, class_name, mapping, allow_nil) 148 mapping = (Array === mapping.first ? mapping : [ mapping ]) 149 150 allow_nil_condition = if allow_nil 151 mapping.collect { |pair| "!read_attribute(\"#{pair.first}\").nil?"}.join(" || ") 152 else 153 "true" 152 module_eval do 153 define_method(name) do |*args| 154 force_reload = args.first || false 155 if (instance_variable_get("@#{name}").nil? || force_reload) && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? }) 156 instance_variable_set("@#{name}", class_name.constantize.new(*mapping.collect {|pair| read_attribute(pair.first)})) 157 end 158 return instance_variable_get("@#{name}") 159 end 154 160 end 155 161 156 module_eval <<-end_eval, __FILE__, __LINE__157 def #{name}(force_reload = false)158 if (@#{name}.nil? || force_reload) && #{allow_nil_condition}159 @#{name} = #{class_name}.new(#{mapping.collect { |pair| "read_attribute(\"#{pair.first}\")"}.join(", ")})160 end161 return @#{name}162 end163 end_eval164 162 end 165 163 166 def writer_method(name, class_name, mapping, allow_nil) 167 mapping = (Array === mapping.first ? mapping : [ mapping ]) 168 169 if allow_nil 170 module_eval <<-end_eval, __FILE__, __LINE__ 171 def #{name}=(part) 172 @#{name} = part.freeze 173 if part.nil? 174 #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = nil" }.join("\n")} 175 else 176 #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")} 177 end 164 def writer_method(name, class_name, mapping, allow_nil, conversion) 165 module_eval do 166 define_method("#{name}=") do |part| 167 if part.nil? && allow_nil 168 mapping.each { |pair| @attributes[pair.first] = nil } 169 instance_variable_set("@#{name}", nil) 170 else 171 part = conversion.call(part) unless part.is_a?(class_name.constantize) || conversion.nil? 172 mapping.each { |pair| @attributes[pair.first] = part.send(pair.last) } 173 instance_variable_set("@#{name}", part.freeze) 178 174 end 179 end_eval 180 else 181 module_eval <<-end_eval, __FILE__, __LINE__ 182 def #{name}=(part) 183 @#{name} = part.freeze 184 #{mapping.collect{ |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")} 185 end 186 end_eval 175 end 187 176 end 188 177 end trunk/activerecord/test/fixtures/customer.rb
r4353 r8003 1 1 class Customer < ActiveRecord::Base 2 2 composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true 3 composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)3 composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money } 4 4 composed_of :gps_location, :allow_nil => true 5 5 end