Permalink
Browse files

Merge remote branch 'recruitmilitary/master'. Seriously, this time.

Conflicts:
	test/attribute_mapper_test.rb
  • Loading branch information...
2 parents 6b5807e + 149fc6b commit 4d57c3978fd73c4f2d3a332604b8a438aff1f41e @therealadam committed Sep 12, 2010
Showing with 63 additions and 3 deletions.
  1. +32 −3 lib/attribute_mapper.rb
  2. +31 −0 test/attribute_mapper_test.rb
View
@@ -25,6 +25,7 @@ module ClassMethods # @private
# Each attribute you map generates an options method, suitable for
# use in form helpers. If you define an attribute +status+,
# instances of your model will have a +status_options+ method
+ # (on the class and any instances)
# that returns a sorted array of arrays containing
# humanized-option-name/value pairs. By default this array is
# sorted by the option name (closed/open/etc.) If you'd rather
@@ -42,15 +43,31 @@ module ClassMethods # @private
# @option options :predicate_methods Generate methods for checking
# whether an object has a certain attribute set
def map_attribute(attribute, options)
- mapping = options[:to]
+ mapping = build_mapping(options)
verify_existence_of attribute
add_accessor_for attribute, mapping
add_predicates_for attribute, mapping.keys if options.fetch(:predicate_methods) { true }
override attribute
add_options_helper_for attribute, mapping
+ add_options_helper_to_class attribute, self
end
private
+ def build_mapping(options)
+ case options[:to]
+ when Hash
+ options[:to]
+ when Array
+ build_mapping_from_array(options[:to])
+ end
+ end
+
+ # Transforms an array into a hash for the mapping.
+ # [:open, :closed] # => { :open => 1, :closed => 2 }
+ #
+ def build_mapping_from_array(array)
+ array.enum_for(:each_with_index).inject({}) { |h, (o, i)| h[o] = i+1; h }
+ end
def add_accessor_for(attribute, mapping)
class_eval(<<-EVAL, __FILE__, __LINE__)
@@ -78,9 +95,21 @@ def #{attribute}_options(sort_by_keys=true)
options = self.class.#{attribute.to_s.pluralize}.sort { |l, r|
sort_by_keys ? l.first.to_s <=> r.first.to_s : l.last <=> r.last
}.map { |f|
- [f[0].to_s.humanize, f[0]]
+ [f[0].to_s.capitalize, f[0]]
+ }
+ self.#{attribute}.present? ? [options, {:selected => self.#{attribute}}] : [options]
+ end
+ EVAL
+ end
+
+ def add_options_helper_to_class(attribute, klass)
+ klass.instance_eval(<<-EVAL, __FILE__, __LINE__)
+ def #{attribute}_options(sort_by_keys=true)
+ options = #{attribute.to_s.pluralize}.sort { |l, r|
+ sort_by_keys ? l.first.to_s <=> r.first.to_s : l.last <=> r.last
+ }.map { |f|
+ [f[0].to_s.capitalize, f[0]]
}
- self.#{attribute}.present? ? [options, {:selected => self.#{attribute}}] : [options]
end
EVAL
end
@@ -96,6 +96,11 @@ class AttributeMapperTest < Test::Unit::TestCase
assert_equal [[["Open", :open], ["Closed", :closed]], {:selected => :open}], ticket.status_options(false)
end
+ should "provide a class level helper for forms" do
+ assert_equal [["Closed", :closed], ["Open", :open]], Ticket.status_options
+ assert_equal [["Open", :open], ["Closed", :closed]], Ticket.status_options(false)
+ end
+
should "not raise an error when setting to a blank value" do
assert_nothing_raised {
ticket.update_attributes(:status => "")
@@ -149,6 +154,32 @@ class AttributeMapperTest < Test::Unit::TestCase
end
+ should 'auto-expand arrays to a hash with the raw value being the index + 1' do
+ array_ticket = Class.new(ActiveRecord::Base) do
+ set_table_name "tickets"
+
+ include AttributeMapper
+ map_attribute :status, :to => [:open, :closed]
+ end
+
+ ticket = array_ticket.new
+
+ assert_nil ticket.status
+ assert_nothing_raised do
+ ticket.status = :open
+ end
+ assert_equal :open, ticket.status
+ assert_equal mapping[:open], ticket[:status]
+
+ assert_nothing_raised do
+ ticket.status = :closed
+ end
+
+ assert_equal :closed, ticket.status
+ assert_equal mapping[:closed], ticket[:status]
+
+ end
+
end
#######

0 comments on commit 4d57c39

Please sign in to comment.