aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/aggregations.rb
diff options
context:
space:
mode:
authorJeremy Kemper <jeremy@bitsweat.net>2007-10-23 17:39:35 +0000
committerJeremy Kemper <jeremy@bitsweat.net>2007-10-23 17:39:35 +0000
commit7b42a1d0ac2aa1c7ba544949bd14c2f166293b00 (patch)
tree313ee38b221b8548b5e2cb4b08d26e26150faa5c /activerecord/lib/active_record/aggregations.rb
parentc220e558be33e30a7946d3604d45ba671b2e7c31 (diff)
downloadrails-7b42a1d0ac2aa1c7ba544949bd14c2f166293b00.tar.gz
rails-7b42a1d0ac2aa1c7ba544949bd14c2f166293b00.tar.bz2
rails-7b42a1d0ac2aa1c7ba544949bd14c2f166293b00.zip
Assigning an instance of a foreign class to a composed_of aggregate calls an optional conversion block. Refactor and simplify composed_of implementation. Closes #6322.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8003 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib/active_record/aggregations.rb')
-rw-r--r--activerecord/lib/active_record/aggregations.rb63
1 files changed, 26 insertions, 37 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 8ee9d8368d..c227893765 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -122,68 +122,57 @@ module ActiveRecord
# attributes are +nil+. Setting the aggregate class to +nil+ has the effect of writing +nil+ to all mapped attributes.
# This defaults to +false+.
#
+ # An optional block can be passed to convert the argument that is passed to the writer method into an instance of
+ # <tt>:class_name</tt>. The block will only be called if the arguement is not already an instance of <tt>:class_name</tt>.
+ #
# Option examples:
# composed_of :temperature, :mapping => %w(reading celsius)
- # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
+ # composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) {|balance| balance.to_money }
# composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
# composed_of :gps_location
# composed_of :gps_location, :allow_nil => true
#
- def composed_of(part_id, options = {})
+ def composed_of(part_id, options = {}, &block)
options.assert_valid_keys(:class_name, :mapping, :allow_nil)
name = part_id.id2name
class_name = options[:class_name] || name.camelize
mapping = options[:mapping] || [ name, name ]
+ mapping = [ mapping ] unless mapping.first.is_a?(Array)
allow_nil = options[:allow_nil] || false
reader_method(name, class_name, mapping, allow_nil)
- writer_method(name, class_name, mapping, allow_nil)
+ writer_method(name, class_name, mapping, allow_nil, block)
create_reflection(:composed_of, part_id, options, self)
end
private
def reader_method(name, class_name, mapping, allow_nil)
- mapping = (Array === mapping.first ? mapping : [ mapping ])
-
- allow_nil_condition = if allow_nil
- mapping.collect { |pair| "!read_attribute(\"#{pair.first}\").nil?"}.join(" || ")
- else
- "true"
- end
-
- module_eval <<-end_eval, __FILE__, __LINE__
- def #{name}(force_reload = false)
- if (@#{name}.nil? || force_reload) && #{allow_nil_condition}
- @#{name} = #{class_name}.new(#{mapping.collect { |pair| "read_attribute(\"#{pair.first}\")"}.join(", ")})
+ module_eval do
+ define_method(name) do |*args|
+ force_reload = args.first || false
+ if (instance_variable_get("@#{name}").nil? || force_reload) && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? })
+ instance_variable_set("@#{name}", class_name.constantize.new(*mapping.collect {|pair| read_attribute(pair.first)}))
end
- return @#{name}
+ return instance_variable_get("@#{name}")
end
- end_eval
- end
+ end
- def writer_method(name, class_name, mapping, allow_nil)
- mapping = (Array === mapping.first ? mapping : [ mapping ])
+ end
- if allow_nil
- module_eval <<-end_eval, __FILE__, __LINE__
- def #{name}=(part)
- @#{name} = part.freeze
- if part.nil?
- #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = nil" }.join("\n")}
- else
- #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")}
- end
+ def writer_method(name, class_name, mapping, allow_nil, conversion)
+ module_eval do
+ define_method("#{name}=") do |part|
+ if part.nil? && allow_nil
+ mapping.each { |pair| @attributes[pair.first] = nil }
+ instance_variable_set("@#{name}", nil)
+ else
+ part = conversion.call(part) unless part.is_a?(class_name.constantize) || conversion.nil?
+ mapping.each { |pair| @attributes[pair.first] = part.send(pair.last) }
+ instance_variable_set("@#{name}", part.freeze)
end
- end_eval
- else
- module_eval <<-end_eval, __FILE__, __LINE__
- def #{name}=(part)
- @#{name} = part.freeze
- #{mapping.collect{ |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")}
- end
- end_eval
+ end
end
end
end