Class: SuperMap
Overview
Two-way hash with additional custom data, autogenerated labels and human readable strings - swiss army knife of collections :) Especially suited for emulating enumerable fields in database.
Immutable objects - most element accessing methods are cached, there is no designed way to get “raw” elements. If you need another (similar) SuperMap, use +/- methods to get a new one. The methods accessing Element objects directly (each, first, last) should be used with awareness of aforementioned limitations. Usually (when not enumerating over all elements) you would use key/value/attribute etc. accessing methods, eg. map.key( value ), map.value( key ), map.attribute( key, attr_name ).
Defined Under Namespace
Classes: Element, Error, UnknownKey, UnknownValue
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
-
#+(map_or_array) ⇒ Object
Adds elements from another map or array (returns new map).
-
#-(*keys) ⇒ Object
Removes element(s) corresponding to key(s) (returns new map) TODO: this should also handle another map as argument.
-
#attribute(value_or_key, attr_key) ⇒ Object
Attribute field for given value or key.
-
#each ⇒ Object
Iterates over the list return Element objects - required for Enumerable methods to work.
-
#element_array ⇒ Object
Elements in the form of array (original form as passed as argument).
- #element_by_value_or_key(value_or_key) ⇒ Object
- #first ⇒ Object
-
#has_key?(key) ⇒ Boolean
Returns true if given key exists.
-
#has_value?(value) ⇒ Boolean
Returns true if given value exists.
-
#include?(value_or_key) ⇒ Boolean
Returns true if given key (Symbol) or value (non-Symbol) exists.
-
#initialize(*elements) ⇒ SuperMap
constructor
Creates new list.
-
#key(value) ⇒ Object
Key for given value - raises exception on unknown value depending on :unknown_value_fatal setting.
-
#keys ⇒ Object
Array of keys.
-
#label(value_or_key) ⇒ Object
Label for given value or key (it is determined basing on argument type - keys must be Symbols while values can not).
-
#labeled_values ⇒ Object
Returns array of label/value pairs, useful for SELECT tags - eg.
- #last ⇒ Object
-
#size ⇒ Object
Number of elements.
-
#value(key) ⇒ Object
(also: #[])
Value for given key - raises exception when key does not exist (to avoid bogus error messages when called with non-existant key).
-
#values ⇒ Object
Array of values.
Constructor Details
#initialize(*elements) ⇒ SuperMap
Creates new list. Elements - arrays with arguments for Element.new (key, value, attributes) Options (optional last argument):
:translation_scope - where to find translated labels/descriptions
:unknown_value_fatal - whether to raise an exception when accessing
objects via unknown value (unknown key is always fatal)
Example:
class User
KINDS = SuperMap.new(
[:member, 1, "Casual member", { :min_age => 18.years, :welcome_string => "Welcome member!" }],
[:admin, 2, "Administrator", { :min_age => nil, :welcome_string => "Hello admin!" }],
:translation_scope => "user.kinds"
)
end TODO: enforce key/value uniqueness
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/super_map.rb', line 97 def initialize( *elements ) if elements.last.is_a?( Hash ) @options = elements.pop else @options = {} end # TODO: handle old syntax here (elements passed in an Array and not as # separate arguments) @elements = elements.collect { |elem| Element.new( *([self] + elem) ) } # We store elements in 2 Hashes, because we need to be able to lookup both # on key (when in need of value) and on value (when in need of a key/label # corresponding to the value fetched from database) @elements_by_key = @elements.inject( {} ) { |hash, elem| hash[elem.key] = elem; hash } @elements_by_value = @elements.inject( {} ) { |hash, elem| hash[elem.value] = elem; hash } end |
Instance Attribute Details
#options ⇒ Object (readonly)
Returns the value of attribute options.
28 29 30 |
# File 'lib/super_map.rb', line 28 def @options end |
Instance Method Details
#+(map_or_array) ⇒ Object
Adds elements from another map or array (returns new map)
141 142 143 144 145 146 147 |
# File 'lib/super_map.rb', line 141 def + (map_or_array) if map_or_array.is_a?( self.class ) # Map return self.class.new( *(element_array + map_or_array.element_array + [@options]) ) else # Array return self.class.new( *(element_array + map_or_array + [@options]) ) end end |
#-(*keys) ⇒ Object
Removes element(s) corresponding to key(s) (returns new map) TODO: this should also handle another map as argument
134 135 136 137 138 |
# File 'lib/super_map.rb', line 134 def - (*keys) keys = keys.flatten new_elements = select { |el| !keys.include?( el.key ) }.collect { |elem| elem.to_a } return self.class.new( *(new_elements + [@options]) ) end |
#attribute(value_or_key, attr_key) ⇒ Object
Attribute field for given value or key
193 194 195 196 197 198 199 200 |
# File 'lib/super_map.rb', line 193 def attribute(value_or_key, attr_key) elem = element_by_value_or_key( value_or_key ) if elem return elem.attributes[attr_key] else return nil end end |
#each ⇒ Object
Iterates over the list return Element objects - required for Enumerable methods to work.
120 121 122 |
# File 'lib/super_map.rb', line 120 def each @elements.each { |elem| yield elem } end |
#element_array ⇒ Object
Elements in the form of array (original form as passed as argument)
114 115 116 |
# File 'lib/super_map.rb', line 114 def element_array @element_array ||= @elements.collect { |elem| elem.to_a } end |
#element_by_value_or_key(value_or_key) ⇒ Object
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/super_map.rb', line 219 def element_by_value_or_key( value_or_key ) if value_or_key.is_a?( Symbol ) # Key elem = @elements_by_key[value_or_key] if elem return elem else raise UnknownKey, "Unknown key #{value_or_key}" end else elem = @elements_by_value[value_or_key] return elem if elem if @options[:unknown_value_fatal] raise UnknownValue, "Unknown value #{value_or_key}" else return nil end end end |
#first ⇒ Object
124 125 126 |
# File 'lib/super_map.rb', line 124 def first @elements.first end |
#has_key?(key) ⇒ Boolean
Returns true if given key exists
203 204 205 |
# File 'lib/super_map.rb', line 203 def has_key?( key ) @elements_by_key.has_key?( key ) end |
#has_value?(value) ⇒ Boolean
Returns true if given value exists
208 209 210 |
# File 'lib/super_map.rb', line 208 def has_value?( value ) @elements_by_value.has_key?( value ) end |
#include?(value_or_key) ⇒ Boolean
Returns true if given key (Symbol) or value (non-Symbol) exists
213 214 215 |
# File 'lib/super_map.rb', line 213 def include?( value_or_key ) return has_key?( value_or_key ) || has_value?( value_or_key ) end |
#key(value) ⇒ Object
Key for given value - raises exception on unknown value depending on :unknown_value_fatal setting
172 173 174 175 176 |
# File 'lib/super_map.rb', line 172 def key(value) elem = element_by_value_or_key( value ) # Exception handling in element_by_value_or_key return elem ? elem.key : nil end |
#keys ⇒ Object
Array of keys
161 162 163 |
# File 'lib/super_map.rb', line 161 def keys @keys ||= @elements.collect { |elem| elem.key } end |
#label(value_or_key) ⇒ Object
Label for given value or key (it is determined basing on argument type - keys must be Symbols while values can not)
187 188 189 190 |
# File 'lib/super_map.rb', line 187 def label( value_or_key ) elem = element_by_value_or_key( value_or_key ) return elem ? elem.label : nil end |
#labeled_values ⇒ Object
Returns array of label/value pairs, useful for SELECT tags - eg. f.select( :kind, User::KINDS.labeled_values )
151 152 153 |
# File 'lib/super_map.rb', line 151 def labeled_values @labeled_values ||= @elements.collect { |elem| [elem.label, elem.value] } end |
#last ⇒ Object
128 129 130 |
# File 'lib/super_map.rb', line 128 def last @elements.last end |
#size ⇒ Object
Number of elements
166 167 168 |
# File 'lib/super_map.rb', line 166 def size @size ||= @elements.size end |
#value(key) ⇒ Object Also known as: []
Value for given key - raises exception when key does not exist (to avoid bogus error messages when called with non-existant key)
180 181 182 183 |
# File 'lib/super_map.rb', line 180 def value(key) # Exception handling in element_by_value_or_key element_by_value_or_key( key ).value end |
#values ⇒ Object
Array of values
156 157 158 |
# File 'lib/super_map.rb', line 156 def values @values ||= @elements.collect { |elem| elem.value } end |