SuperMap is a two-way, multi-purpose ordered hash with some additional
capabilities (additional attributes, translations). It is meant to be used with
Rails, but it doesn't depend on them, so someone might find it useful in other

Ever had an enumerable field in a model that would map to a select box in a
form? Wanted some nice way to operate it as symbol in the code, integer in
database and label in views? That's where SuperMap comes into play.


Let's say there is a Payment model with two enumerable fields:
- payment_type: Cash In, Cash Out, Bonus, Commission
- payment_method: Paypal, Bank Transfer, Manual

We define 2 SuperMaps:

	class Payment

		PAYMENT_TYPES = SuperMap.new(
				[:cash_in, 1, { :label => "Cash In", :tax => 0.01 }],
				[:cash_out, 2, { :label => "Cash Out", :tax => 0.02 }],
				[:bonus, 123, { :label => "Bonus Payment", :tax => 0.03 }],
				[:commission, 384728, { :tax => 0.01 }]

		PAYMENT_METHODS = SuperMap.new(
				[:paypal, 1, { :label => "Paid via Paypal", :favorite => true }],
				[:bank_transfer, 2],
				[:manual, 3],
				:translation_scope => "activerecord.models.payment.payment_methods"


PAYMENT_TYPES defines options for payment_type field. First parameter is a key
that should be used to access this element instead of using value, which comes
second as integer (and is possibly stored in database). Note that value might be
totally random, it just needs be unique across elements. Some labels are set
explicitly, for other options key.titleize will be used implicitly. We also
defined a custom attribute :tax, which can be accessed using SuperMap#attribute

PAYMENT_METHODS define translation_scope, which means labels will be present in
translations file (I18n - note that it's totally optional). :paypal will have
custom label, which overrides translations.

We can than use those SuperMaps to handle attributes for Payment instances:
	payment = Payment.new( :payment_method => 1 )
	payment.payment_type = PAYMENT_TYPES[:cash_out]			# Set to 2
	label = PAYMENT_TYPES.label( payment.payment_type ) # "Cash Out"
	label = PAYMENT_TYPES.label( :bonus )								# "Bonus Payment"
	value = PAYMENT_METHODS[payment.payment_method]			# 1
	tax = PAYMENT_TYPES.attribute( payment.payment_type, :tax ) # 0.02
	tax = PAYMENT_TYPES.attribute( :bonus, :tax ) # 0.03

We can also use


to get the form directly suitable to pass options to f.select helper method.

To make things even simpler, we can use super_mapped_attr:

	class Payment
		... # SuperMaps declarations

		super_mapped_attr :payment_type, PAYMENT_TYPES
		super_mapped_attr :payment_method, PAYMENT_METHODS


Now a whole lot of new methods comes into play:

	p = Payment.new( :payment_method => 1 )
	p.payment_method_label                      # "Paid via Paypal"
	p.payment_method_key												# :paypal
	p.payment_method_attr( :favorite )					# true
	p.payment_method_key = :manual
	p.payment_method														# 3


Many thanks go to Stefan Nothegger and Sharewise project
(http://www.sharewise.com), where the original idea and large parts of the code
originate from.