super_map 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README ADDED
@@ -0,0 +1,91 @@
1
+ Introduction
2
+ ============
3
+
4
+ SuperMap is a two-way, multi-purpose ordered hash with some additional
5
+ capabilities (additional attributes, translations). It is meant to be used with
6
+ Rails, but it doesn't depend on them, so someone might find it useful in other
7
+ environments.
8
+
9
+ Ever had an enumerable field in a model that would map to a select box in a
10
+ form? Wanted some nice way to operate it as symbol in the code, integer in
11
+ database and label in views? That's where SuperMap comes into play.
12
+
13
+ Example
14
+ =======
15
+
16
+ Let's say there is a Payment model with two enumerable fields:
17
+ - payment_type: Cash In, Cash Out, Bonus, Commission
18
+ - payment_method: Paypal, Bank Transfer, Manual
19
+
20
+ We define 2 SuperMaps:
21
+
22
+ class Payment
23
+
24
+ PAYMENT_TYPES = SuperMap.new(
25
+ [:cash_in, 1, { :label => "Cash In", :tax => 0.01 }],
26
+ [:cash_out, 2, { :label => "Cash Out", :tax => 0.02 }],
27
+ [:bonus, 123, { :label => "Bonus Payment", :tax => 0.03 }],
28
+ [:commission, 384728, { :tax => 0.01 }]
29
+ )
30
+
31
+ PAYMENT_METHODS = SuperMap.new(
32
+ [:paypal, 1, { :label => "Paid via Paypal", :favorite => true }],
33
+ [:bank_transfer, 2],
34
+ [:manual, 3],
35
+ :translation_scope => "activerecord.models.payment.payment_methods"
36
+ )
37
+
38
+ end
39
+
40
+ PAYMENT_TYPES defines options for payment_type field. Some labels are set
41
+ explicitly, for other options key.titleize will be used implicitly. We also
42
+ defined a custom attribute :tax, which can be accessed using SuperMap#attribute
43
+ method.
44
+
45
+ PAYMENT_METHODS define translation_scope, which means labels will be present in
46
+ translations file (I18n). :paypal will have custom label, which overrides
47
+ translations.
48
+
49
+ We can than use those SuperMaps to handle attributes for Payment instances:
50
+
51
+ payment = Payment.new( :payment_method => 1 )
52
+ payment.payment_type = PAYMENT_TYPES[:cash_out] # Set to 2
53
+ label = PAYMENT_TYPES.label( payment.payment_type ) # "Cash Out"
54
+ label = PAYMENT_TYPES.label( :bonus ) # "Bonus Payment"
55
+ value = PAYMENT_METHODS[payment.payment_method] # 1
56
+ tax = PAYMENT_TYPES.attribute( payment.payment_type, :tax ) # 0.02
57
+ tax = PAYMENT_TYPES.attribute( :bonus, :tax ) # 0.03
58
+
59
+ We can also use
60
+
61
+ PAYMENT_TYPES.labeled_values
62
+
63
+ to get the form directly suitable to pass options to f.select helper method.
64
+
65
+
66
+
67
+ To make things even simpler, we can use super_mapped_attr:
68
+
69
+ class Payment
70
+ ... # SuperMaps declarations
71
+
72
+ super_mapped_attr :payment_type, PAYMENT_TYPES
73
+ super_mapped_attr :payment_method, PAYMENT_METHODS
74
+
75
+ end
76
+
77
+ Now a whole lot of new methods comes into play:
78
+
79
+ p = Payment.new( :payment_method => 1 )
80
+ p.payment_method_label # "Paid via Paypal"
81
+ p.payment_method_key # :paypal
82
+ p.payment_method_attr( :favorite ) # true
83
+ p.payment_method_key = :manual
84
+ p.payment_method # 3
85
+
86
+ Thanks
87
+ ======
88
+
89
+ Many thanks go to Stefan Nothegger and Sharewise project
90
+ (http://www.sharewise.com), where the original idea and large parts of the code
91
+ originate from.
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ PKG_FILES = FileList[
7
+ '[a-zA-Z]*',
8
+ 'generators/**/*',
9
+ 'lib/**/*',
10
+ 'rails/**/*',
11
+ 'tasks/**/*',
12
+ 'test/**/*'
13
+ ]
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = "super_map"
17
+ s.version = "1.0.0"
18
+ s.author = "Marek Janukowicz"
19
+ s.email = "marek@janukowicz.net"
20
+ s.homepage = ""
21
+ s.platform = Gem::Platform::RUBY
22
+ s.summary = "Swiss army knife of enum-based attributes"
23
+ s.files = PKG_FILES.to_a
24
+ s.require_path = "lib"
25
+ s.has_rdoc = false
26
+ s.extra_rdoc_files = ["README"]
27
+ s.add_dependency "i18n", ">= 0.4.0"
28
+ end
29
+
30
+ desc 'Create gem'
31
+ Rake::GemPackageTask.new(spec) do |pkg|
32
+ pkg.gem_spec = spec
33
+ end
34
+
35
+ desc 'Run tests'
36
+ Rake::TestTask.new(:test) do |t|
37
+ t.libs << 'lib'
38
+ t.libs << 'test'
39
+ t.pattern = 'test/**/*_test.rb'
40
+ t.verbose = true
41
+ end
42
+
43
+ desc 'Generate RDoc documentation'
44
+ Rake::RDocTask.new(:rdoc) do |rdoc|
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = 'SuperMap'
47
+ rdoc.options << '--line-numbers' << '--inline-source'
48
+ rdoc.rdoc_files.include('README')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
51
+
@@ -0,0 +1,18 @@
1
+ class String
2
+
3
+ # Some poor man's implementations of Rails String extensions in case we can't
4
+ # use those
5
+
6
+ unless method_defined?( :pluralize )
7
+ def pluralize
8
+ [-1,1] == "s" ? self : self + "s"
9
+ end
10
+ end
11
+
12
+ unless method_defined?( :titleize )
13
+ def titleize
14
+ gsub( "_", " " ).capitalize
15
+ end
16
+ end
17
+
18
+ end
data/lib/super_map.rb ADDED
@@ -0,0 +1,240 @@
1
+ begin
2
+ require 'i18n'
3
+ rescue LoadError
4
+ nil # We don't really need I18n, but if it's not present, :translation_scope can't be used
5
+ end
6
+ require 'string_extensions'
7
+ require 'super_mapped_attr'
8
+
9
+ # Two-way hash with additional custom data, autogenerated labels and human
10
+ # readable strings - swiss army knife of collections :) Especially suited for
11
+ # emulating enumerable fields in database.
12
+ #
13
+ # Immutable objects - most element accessing methods are cached, there is no
14
+ # designed way to get "raw" elements. If you need another (similar) SuperMap,
15
+ # use +/- methods to get a new one. The methods accessing Element objects
16
+ # directly (each, first, last) should be used with awareness of aforementioned
17
+ # limitations. Usually (when not enumerating over all elements) you would use
18
+ # key/value/attribute etc. accessing methods, eg. map.key( value ), map.value(
19
+ # key ), map.attribute( key, attr_name ).
20
+ class SuperMap
21
+
22
+ include Enumerable
23
+
24
+ class Error < ::StandardError; end
25
+ class UnknownKey < Error; end
26
+ class UnknownValue < Error; end
27
+
28
+ attr_reader :options
29
+
30
+ # Map element. Rarely used directly, usually the map object itself is queried
31
+ # for element properties.
32
+ class Element
33
+
34
+ # Key (symbol) - used for getting element by symbolic name
35
+ attr_reader :key
36
+ # Value - corresponds to key, usually an integer or string to be stored in
37
+ # database
38
+ attr_reader :value
39
+ # Additional information about element, eg. time frame, additional
40
+ # attributes. Also contains the label if not default or provided by I18n.
41
+ # Takes the form of a Hash.
42
+ attr_reader :attributes
43
+
44
+ # Creates new list element.
45
+ def initialize( list, key, value, attributes = {} )
46
+ raise "Key must be a Symbol" unless key.is_a? Symbol
47
+ raise "Value must NOT be a Symbol" if value.is_a? Symbol
48
+ @list, @key, @value, @attributes = list, key, value, attributes
49
+ end
50
+
51
+ def label
52
+ translated_attribute( :label )
53
+ end
54
+
55
+ def description
56
+ translated_attribute( :description )
57
+ end
58
+
59
+ def method_missing( name, *args )
60
+ return @attributes[name] || super( name, *args )
61
+ end
62
+
63
+ # Returns all initializing arguments as passed to SuperMap constructor - this
64
+ # method is used for cloning to another SuperMap.
65
+ def to_a
66
+ [key, value, attributes]
67
+ end
68
+
69
+ protected
70
+ def translated_attribute( attr )
71
+ return @attributes[attr.to_sym] if @attributes[attr.to_sym]
72
+ if @list.options[:translation_scope]
73
+ return I18n.t( @key, :scope => [@list.options[:translation_scope], attr.to_s.pluralize], :default => @key.to_s.titleize )
74
+ else
75
+ return @key.to_s.titleize
76
+ end
77
+ end
78
+ end
79
+
80
+ # Creates new list.
81
+ # Elements - arrays with arguments for Element.new (key, value, attributes)
82
+ # Options (optional last argument):
83
+ # :translation_scope - where to find translated labels/descriptions
84
+ # :unknown_value_fatal - whether to raise an exception when accessing
85
+ # objects via unknown value (unknown key is always fatal)
86
+ #
87
+ # Example:
88
+ #
89
+ # class User
90
+ # KINDS = SuperMap.new(
91
+ # [:member, 1, "Casual member", { :min_age => 18.years, :welcome_string => "Welcome member!" }],
92
+ # [:admin, 2, "Administrator", { :min_age => nil, :welcome_string => "Hello admin!" }],
93
+ # :translation_scope => "user.kinds"
94
+ # )
95
+ # end
96
+ # TODO: enforce key/value uniqueness
97
+ def initialize( *elements )
98
+ if elements.last.is_a?( Hash )
99
+ @options = elements.pop
100
+ else
101
+ @options = {}
102
+ end
103
+ # TODO: handle old syntax here (elements passed in an Array and not as
104
+ # separate arguments)
105
+ @elements = elements.collect { |elem| Element.new( *([self] + elem) ) }
106
+ # We store elements in 2 Hashes, because we need to be able to lookup both
107
+ # on key (when in need of value) and on value (when in need of a key/label
108
+ # corresponding to the value fetched from database)
109
+ @elements_by_key = @elements.inject( {} ) { |hash, elem| hash[elem.key] = elem; hash }
110
+ @elements_by_value = @elements.inject( {} ) { |hash, elem| hash[elem.value] = elem; hash }
111
+ end
112
+
113
+ # Elements in the form of array (original form as passed as argument)
114
+ def element_array
115
+ @element_array ||= @elements.collect { |elem| elem.to_a }
116
+ end
117
+
118
+ # Iterates over the list return Element objects - required for Enumerable
119
+ # methods to work.
120
+ def each
121
+ @elements.each { |elem| yield elem }
122
+ end
123
+
124
+ def first
125
+ @elements.first
126
+ end
127
+
128
+ def last
129
+ @elements.last
130
+ end
131
+
132
+ # Removes element(s) corresponding to key(s) (returns new map)
133
+ # TODO: this should also handle another map as argument
134
+ def - (*keys)
135
+ keys = keys.flatten
136
+ new_elements = select { |el| !keys.include?( el.key ) }.collect { |elem| elem.to_a }
137
+ return self.class.new( *(new_elements + [@options]) )
138
+ end
139
+
140
+ # Adds elements from another map or array (returns new map)
141
+ def + (map_or_array)
142
+ if map_or_array.is_a?( self.class ) # Map
143
+ return self.class.new( *(element_array + map_or_array.element_array + [@options]) )
144
+ else # Array
145
+ return self.class.new( *(element_array + map_or_array + [@options]) )
146
+ end
147
+ end
148
+
149
+ # Returns array of label/value pairs, useful for SELECT tags - eg.
150
+ # f.select( :kind, User::KINDS.labeled_values )
151
+ def labeled_values
152
+ @labeled_values ||= @elements.collect { |elem| [elem.label, elem.value] }
153
+ end
154
+
155
+ # Array of values
156
+ def values
157
+ @values ||= @elements.collect { |elem| elem.value }
158
+ end
159
+
160
+ # Array of keys
161
+ def keys
162
+ @keys ||= @elements.collect { |elem| elem.key }
163
+ end
164
+
165
+ # Number of elements
166
+ def size
167
+ @size ||= @elements.size
168
+ end
169
+
170
+ # Key for given value - raises exception on unknown value depending on
171
+ # :unknown_value_fatal setting
172
+ def key(value)
173
+ elem = element_by_value_or_key( value )
174
+ # Exception handling in element_by_value_or_key
175
+ return elem ? elem.key : nil
176
+ end
177
+
178
+ # Value for given key - raises exception when key does not exist (to avoid bogus
179
+ # error messages when called with non-existant key)
180
+ def value(key)
181
+ # Exception handling in element_by_value_or_key
182
+ element_by_value_or_key( key ).value
183
+ end
184
+
185
+ # Label for given value or key (it is determined basing on argument type -
186
+ # keys must be Symbols while values can not)
187
+ def label( value_or_key )
188
+ elem = element_by_value_or_key( value_or_key )
189
+ return elem ? elem.label : nil
190
+ end
191
+
192
+ # Attribute field for given value or key
193
+ def attribute(value_or_key, attr_key)
194
+ elem = element_by_value_or_key( value_or_key )
195
+ if elem
196
+ return elem.attributes[attr_key]
197
+ else
198
+ return nil
199
+ end
200
+ end
201
+
202
+ # Returns true if given key exists
203
+ def has_key?( key )
204
+ @elements_by_key.has_key?( key )
205
+ end
206
+
207
+ # Returns true if given value exists
208
+ def has_value?( value )
209
+ @elements_by_value.has_key?( value )
210
+ end
211
+
212
+ # Returns true if given key (Symbol) or value (non-Symbol) exists
213
+ def include?( value_or_key )
214
+ return has_key?( value_or_key ) || has_value?( value_or_key )
215
+ end
216
+
217
+ alias_method '[]', :value
218
+
219
+ def element_by_value_or_key( value_or_key )
220
+
221
+ if value_or_key.is_a?( Symbol ) # Key
222
+ elem = @elements_by_key[value_or_key]
223
+ if elem
224
+ return elem
225
+ else
226
+ raise UnknownKey, "Unknown key #{value_or_key}"
227
+ end
228
+ else
229
+ elem = @elements_by_value[value_or_key]
230
+ return elem if elem
231
+ if @options[:unknown_value_fatal]
232
+ raise UnknownValue, "Unknown value #{value_or_key}"
233
+ else
234
+ return nil
235
+ end
236
+ end
237
+
238
+ end
239
+
240
+ end
@@ -0,0 +1,65 @@
1
+ module SuperMappedAttr
2
+
3
+ def self.included( klass )
4
+ klass.extend( ClassMethods )
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ # Makes the attribute mapped by a SuperMap, eg.
10
+ # class User
11
+ #
12
+ # super_mapped_attr :kind, SuperMap.new(
13
+ # [:member, 1, "Casual member", { :min_age => 18.years, :welcome_string => "Welcome member!" }],
14
+ # [:admin, 2, "Administrator", { :min_age => nil, :welcome_string => "Hello admin!" }]
15
+ # )
16
+ #
17
+ # end
18
+ #
19
+ # u = User.new( :kind => 1 )
20
+ #
21
+ # u.kind_label # "Casual member"
22
+ #
23
+ # u.kind_key # :member
24
+ #
25
+ # u.kind_attr( :member, :min_age ) # 18.years
26
+ #
27
+ # u.kind_key = :admin
28
+ #
29
+ # u.kind # 2
30
+ #
31
+ # User.kinds # #SuperMap:0x....
32
+ def super_mapped_attr( attr, map, options = {} )
33
+
34
+ if respond_to?( :validates_inclusion_of )
35
+ validates_inclusion_of attr, { :in => map.values }.merge( options )
36
+ end
37
+
38
+ define_method( "#{attr}_key" ) do
39
+ map.key(send(attr))
40
+ end
41
+
42
+ define_method( "#{attr}_key=" ) do |key|
43
+ send( "#{attr}=", map.value( key ))
44
+ end
45
+
46
+ define_method( "#{attr}_label" ) do
47
+ map.label(send(attr))
48
+ end
49
+
50
+ define_method( "#{attr}_attr" ) do |key|
51
+ map.attribute(send(attr), key)
52
+ end
53
+
54
+ (class << self; self; end).instance_eval do
55
+ define_method attr.to_s.pluralize, lambda { map }
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+
62
+ # Include in ActiveRecord models by default
63
+ if defined?( ActiveRecord::Base )
64
+ ActiveRecord::Base.send( :include, SuperMappedAttr )
65
+ end
data/test/en.yml ADDED
@@ -0,0 +1,9 @@
1
+ en:
2
+ enum:
3
+ map:
4
+ labels:
5
+ one: NEVER DISPLAY
6
+ two: Two label
7
+ descriptions:
8
+ one: NEVER DISPLAY
9
+ two: Two description
@@ -0,0 +1,144 @@
1
+ require 'test/unit'
2
+ require 'super_map'
3
+ I18n.load_path << File.join( File.dirname( __FILE__ ), "en.yml" )
4
+
5
+ class SuperMapTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @color_map = SuperMap.new(
9
+ [:red, 5, { :rgb => "AA0000", :priority => 3 }],
10
+ [:green, 2, { :rgb => "00AA00", :priority => 12 }],
11
+ [:blue, 123, { :rgb => "0000AA", :preference => 8823 }],
12
+ :translation_scope => "color.map"
13
+ )
14
+ end
15
+
16
+ def test_element_label_and_description
17
+ enum_map = SuperMap.new(
18
+ [:one, 1, { :label => "One label", :description => "One description" }],
19
+ [:two, 2],
20
+ :translation_scope => "enum.map"
21
+ )
22
+ assert_equal 'One label', enum_map.first.label
23
+ assert_equal 'One description', enum_map.first.description
24
+ assert_equal 'Two label', enum_map.last.label
25
+ assert_equal 'Two description', enum_map.last.description
26
+ end
27
+
28
+ def test_element_attributes
29
+ red = @color_map.first
30
+ assert_equal "AA0000", red.rgb
31
+ assert_equal 3, red.priority
32
+ blue = @color_map.last
33
+ assert_equal "0000AA", blue.rgb
34
+ assert_equal 8823, blue.preference
35
+ end
36
+
37
+ def test_enumeration
38
+ keys = []
39
+ @color_map.each do |elem|
40
+ keys << elem.key
41
+ end
42
+ assert_equal [:red, :green, :blue], keys
43
+ elems = @color_map.select { |elem| elem.value < 10 }.collect { |elem| elem.key }
44
+ assert_equal [:red, :green], elems
45
+ elems = @color_map.sort_by { |elem| elem.value }.collect { |elem| elem.key }
46
+ assert_equal [:green, :red, :blue], elems
47
+ assert_equal :red, @color_map.first.key
48
+ assert_equal :blue, @color_map.last.key
49
+ end
50
+
51
+ def test_subtraction
52
+ # Existing key
53
+ map = @color_map - :red
54
+ assert_equal [:green, :blue], map.keys
55
+ # Non-existant key
56
+ map = @color_map - :yellow
57
+ assert_equal [:red, :green, :blue], map.keys
58
+ # multiple keys
59
+ map = @color_map - [:green, :blue]
60
+ assert_equal [:red], map.keys
61
+ assert_equal @color_map.options[:translation_scope], map.options[:translation_scope]
62
+ end
63
+
64
+ def test_addition
65
+ # Single element
66
+ map = @color_map + [[:yellow, 3]]
67
+ assert_equal [:red, :green, :blue, :yellow], map.keys
68
+ # Multiple elements
69
+ map = @color_map + [[:yellow, 3], [:brown, 4]]
70
+ assert_equal [:red, :green, :blue, :yellow, :brown], map.keys
71
+ # Add another SuperMap
72
+ second_map = SuperMap.new( [:yellow, 3], [:brown, 4, {:label => "Blah"}], :translation_scope => "another.scope" )
73
+ map = @color_map + second_map
74
+ assert_equal [:red, :green, :blue, :yellow, :brown], map.keys
75
+ assert_equal @color_map.options[:translation_scope], map.options[:translation_scope]
76
+ # Original array is untouched
77
+ assert_equal [:red, :green, :blue], @color_map.keys
78
+ end
79
+
80
+ def test_labeled_values
81
+ assert_equal [["Red", 5], ["Green", 2], ["Blue", 123]], @color_map.labeled_values
82
+ end
83
+
84
+ def test_values
85
+ assert_equal [5,2,123], @color_map.values
86
+ end
87
+
88
+ def test_keys
89
+ assert_equal [:red, :green, :blue], @color_map.keys
90
+ end
91
+
92
+ def test_size
93
+ assert_equal 3, @color_map.size
94
+ end
95
+
96
+ def test_key
97
+ assert_equal :red, @color_map.key( 5 )
98
+ assert_equal :green, @color_map.key( 2 )
99
+ assert_nil @color_map.key( 3 )
100
+ @color_map.options[:unknown_value_fatal] = true
101
+ assert_raise( SuperMap::UnknownValue ) { @color_map.key( 3 ) }
102
+ end
103
+
104
+ def test_value
105
+ assert_equal 5, @color_map.value( :red )
106
+ assert_equal 123, @color_map.value( :blue )
107
+ assert_raise( SuperMap::UnknownKey ) { @color_map.value( :yellow ) }
108
+ end
109
+
110
+ def test_label
111
+ assert_equal "Blue", @color_map.label( :blue )
112
+ assert_equal "Red", @color_map.label( 5 )
113
+ end
114
+
115
+ def test_attribute
116
+ assert_equal 8823, @color_map.attribute( :blue, :preference )
117
+ assert_equal nil, @color_map.attribute( :blue, :priority ) # This attribute doesn't exist for this element
118
+ assert_equal 3, @color_map.attribute( :red, :priority )
119
+ end
120
+
121
+ def test_has_key
122
+ assert @color_map.has_key?( :green )
123
+ assert !@color_map.has_key?( :yellow )
124
+ end
125
+
126
+ def test_has_value
127
+ assert @color_map.has_value?( 2 )
128
+ assert !@color_map.has_value?( 55 )
129
+ end
130
+
131
+ def test_include
132
+ assert @color_map.include?( :blue )
133
+ assert !@color_map.include?( :yellow )
134
+ assert @color_map.include?( 123 )
135
+ assert !@color_map.include?( 122 )
136
+ end
137
+
138
+ # [] is an alias to #value
139
+ def test_brackets
140
+ assert_equal 5, @color_map[ :red ]
141
+ assert_equal 123, @color_map[ :blue ]
142
+ assert_raise( SuperMap::UnknownKey ) { @color_map[ :yellow ] }
143
+ end
144
+ end
@@ -0,0 +1,52 @@
1
+ require 'test/unit'
2
+ require 'super_map'
3
+ I18n.load_path << File.join( File.dirname( __FILE__ ), "en.yml" )
4
+
5
+ class SuperMappedAttrTest < Test::Unit::TestCase
6
+
7
+ class User
8
+
9
+ include SuperMappedAttr
10
+
11
+ attr_accessor :color
12
+ super_mapped_attr :color, SuperMap.new(
13
+ [:red, 5, { :rgb => "AA0000", :priority => 3 }],
14
+ [:green, 2, { :rgb => "00AA00", :priority => 12 }],
15
+ [:blue, 123, { :rgb => "0000AA", :preference => 8823 }],
16
+ :translation_scope => "color.map"
17
+ )
18
+
19
+ end
20
+
21
+ def setup
22
+ @user = User.new
23
+ end
24
+
25
+ def test_label
26
+ @user.color_key = :red
27
+ assert_equal "Red", @user.color_label
28
+ assert_raise( SuperMap::UnknownKey ) do
29
+ @user.color_key = :asdjfkajf
30
+ end
31
+ end
32
+
33
+ def test_key
34
+ # This test DOES make sense - color_key getter and setter both pass through
35
+ # underlying SuperMap
36
+ @user.color_key = :red
37
+ assert_equal :red, @user.color_key
38
+ end
39
+
40
+ def test_attr
41
+ @user.color_key = :blue
42
+ assert_nil @user.color_attr( :priority )
43
+ assert_equal "0000AA", @user.color_attr( :rgb )
44
+ end
45
+
46
+ def test_map_accessor
47
+ assert_equal "Green", User.colors.label( :green )
48
+ assert_equal 123, User.colors[ :blue ]
49
+ assert_equal 12, User.colors.attribute( :green, :priority )
50
+ end
51
+
52
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: super_map
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Marek Janukowicz
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-08 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: i18n
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 0
32
+ - 4
33
+ - 0
34
+ version: 0.4.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description:
38
+ email: marek@janukowicz.net
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README
45
+ files:
46
+ - Rakefile
47
+ - README
48
+ - lib/super_map.rb
49
+ - lib/super_mapped_attr.rb
50
+ - lib/string_extensions.rb
51
+ - test/super_mapped_attr_test.rb
52
+ - test/en.yml
53
+ - test/super_map_test.rb
54
+ has_rdoc: true
55
+ homepage: ""
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Swiss army knife of enum-based attributes
88
+ test_files: []
89
+