symbolize 4.5.0 → 4.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5fa03980e8f95cd5a9f9517d246364128972c3fd
4
- data.tar.gz: 934d6ff3ef97dd046ed3d3d7f5241ee0bebf3bff
3
+ metadata.gz: d8c8248c8a57a1c3e3248a339ec6214fd6fe93ef
4
+ data.tar.gz: 5a2a2faba8acc56b88545a583507a714ea03f495
5
5
  SHA512:
6
- metadata.gz: a1b4cc6c15e0bfb030401926817481f578f4e37d9292066996b3bc42346f6023dfe32ca3a6fb0ebfa7ec9ed8b3d8c41d7e44bf0f9d189b027cb14f3d12e923ec
7
- data.tar.gz: ad06350b50ecd3bcd63abbda8baa36ab34a2fecea34a10c8af86ce50e8421fe135ceda22fb693ac096beca821adf7fffb8b257e4cd678e57281fda95694dd708
6
+ metadata.gz: a6cbd772314ae69fc054ea373487d515f3f3fb6a7eea1144ceda2382c463c0797114a5df969ee7e7e79c48f3f050003b651c5f5a453c7aa096b0dddbb12508c7
7
+ data.tar.gz: 7dea8dbec2121d3357c269bcfad8926db2b3309a5d40a670911a9bdb972fd86ad9e9bad1bc862dede94acffc156c4a62a04fc263eb285e60d87c5d12847c6e3e
data/README.md CHANGED
@@ -56,7 +56,7 @@ Mongoid:
56
56
 
57
57
  Other examples:
58
58
 
59
- symbolize :so, :in => {
59
+ symbolize :os, :in => {
60
60
  :linux => "Linux",
61
61
  :mac => "Mac OS X"
62
62
  }, :scopes => true
data/Rakefile CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'bundler/gem_tasks'
2
2
 
3
3
  require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
4
5
 
5
6
  RSpec::Core::RakeTask.new
7
+ RuboCop::RakeTask.new
6
8
 
7
- task :default => [:spec]
9
+ task :default => [:spec, :rubocop]
@@ -1,4 +1,3 @@
1
- # Todo: is this the best way for AR?
2
1
  module Symbolize
3
2
  autoload :ActiveRecord, 'symbolize/active_record'
4
3
  end
@@ -1,211 +1,219 @@
1
1
  require 'active_support/concern'
2
+ require 'active_support/core_ext/hash/keys'
2
3
 
3
4
  module Symbolize
4
- end
5
-
6
- module Symbolize::ActiveRecord
7
- extend ActiveSupport::Concern
5
+ module ActiveRecord
6
+ extend ActiveSupport::Concern
8
7
 
9
- included do
10
- # Returns an array of all the attributes that have been specified for symbolization
11
- class_attribute :symbolized_attributes, :instance_reader => false
12
- self.symbolized_attributes = []
13
- end
8
+ included do
9
+ # Returns an array of all the attributes that have been specified for symbolization
10
+ class_attribute :symbolized_attributes, :instance_reader => false
11
+ self.symbolized_attributes = []
12
+ end
14
13
 
15
- # Symbolize ActiveRecord attributes. Add
16
- # symbolize :attr_name
17
- # to your model class, to make an attribute return symbols instead of
18
- # string values. Setting such an attribute will accept symbols as well
19
- # as strings. In the database, the symbolized attribute should have
20
- # the column-type :string.
21
- #
22
- # Example:
23
- # class User < ActiveRecord::Base
24
- # symbolize :gender, :in => [:female, :male]
25
- # symbolize :so, :in => {
26
- # :linux => "Linux",
27
- # :mac => "Mac OS X"
28
- # }
29
- # symbolize :gui, , :in => [:gnome, :kde, :xfce], :allow_blank => true
30
- # symbolize :browser, :in => [:firefox, :opera], :i18n => false
31
- # end
32
- #
33
- # It will automattically lookup for i18n:
34
- #
35
- # activerecord:
36
- # symbolizes:
37
- # user:
38
- # gender:
39
- # female: Girl
40
- # male: Boy
41
- #
42
- # You can skip i18n lookup with :i18n => false
43
- # symbolize :gender, :in => [:female, :male], :i18n => false
44
- #
45
- # Its possible to use boolean fields also.
46
- # symbolize :switch, :in => [true, false]
47
- #
48
- # ...
49
- # switch:
50
- # "true": On
51
- # "false": Off
52
- # "nil": Unknown
53
- #
54
- module ClassMethods
55
- # Specifies that values of the given attributes should be returned
56
- # as symbols. The table column should be created of type string.
57
-
58
- def symbolize *attr_names
59
- configuration = {}
60
- configuration.update(attr_names.extract_options!)
61
-
62
- enum = configuration[:in] || configuration[:within]
63
- i18n = configuration.delete(:i18n) || (!enum.instance_of?(Hash) && enum)
64
- scopes = configuration.delete :scopes
65
- methods = configuration.delete :methods
66
- capitalize = configuration.delete :capitalize
67
- validation = configuration.delete(:validate) != false
68
- default_option = configuration.delete :default
69
-
70
- unless enum.nil?
14
+ # Symbolize ActiveRecord attributes. Add
15
+ # symbolize :attr_name
16
+ # to your model class, to make an attribute return symbols instead of
17
+ # string values. Setting such an attribute will accept symbols as well
18
+ # as strings. In the database, the symbolized attribute should have
19
+ # the column-type :string.
20
+ #
21
+ # Example:
22
+ # class User < ActiveRecord::Base
23
+ # symbolize :gender, :in => [:female, :male]
24
+ # symbolize :so, :in => {
25
+ # :linux => "Linux",
26
+ # :mac => "Mac OS X"
27
+ # }
28
+ # symbolize :gui, , :in => [:gnome, :kde, :xfce], :allow_blank => true
29
+ # symbolize :browser, :in => [:firefox, :opera], :i18n => false
30
+ # end
31
+ #
32
+ # It will automattically lookup for i18n:
33
+ #
34
+ # activerecord:
35
+ # symbolizes:
36
+ # user:
37
+ # gender:
38
+ # female: Girl
39
+ # male: Boy
40
+ #
41
+ # You can skip i18n lookup with :i18n => false
42
+ # symbolize :gender, :in => [:female, :male], :i18n => false
43
+ #
44
+ # Its possible to use boolean fields also.
45
+ # symbolize :switch, :in => [true, false]
46
+ #
47
+ # ...
48
+ # switch:
49
+ # "true": On
50
+ # "false": Off
51
+ # "nil": Unknown
52
+ #
53
+ module ClassMethods
54
+ # Specifies that values of the given attributes should be returned
55
+ # as symbols. The table column should be created of type string.
56
+
57
+ def symbolize(*attr_names)
58
+ configuration = attr_names.extract_options!
59
+ configuration.assert_valid_keys(:in, :within, :i18n, :scopes, :methods, :capitalize, :validate, :default, :allow_blank, :allow_nil)
60
+
61
+ enum = configuration[:in] || configuration[:within]
62
+ i18n = configuration[:i18n]
63
+ i18n = enum && !enum.is_a?(Hash) if i18n.nil?
64
+ scopes = configuration[:scopes]
65
+ methods = configuration[:methods]
66
+ capitalize = configuration[:capitalize]
67
+ validation = configuration[:validate] != false
68
+ default_option = configuration[:default]
71
69
 
72
70
  attr_names.each do |attr_name|
73
- attr_name = attr_name.to_s
74
- const = "#{attr_name}_values"
75
- if enum.is_a?(Hash)
76
- values = enum
77
- else
78
- values = ActiveSupport::OrderedHash.new
79
- enum.map do |val|
80
- key = val.respond_to?(:to_sym) ? val.to_sym : val
81
- values[key] = capitalize ? val.to_s.capitalize : val.to_s
71
+ attr_name_str = attr_name.to_s
72
+
73
+ if enum
74
+ enum_hash = \
75
+ if enum.is_a?(Hash)
76
+ enum
77
+ else
78
+ enum.map do |val|
79
+ [
80
+ val.respond_to?(:to_sym) ? val.to_sym : val,
81
+ capitalize ? val.to_s.capitalize : val.to_s,
82
+ ]
83
+ end.to_h
82
84
  end
83
- end
84
85
 
85
- # Get the values of :in
86
- const_set const.upcase, values unless const_defined? const.upcase
87
- ev = if i18n
88
- # This one is a dropdown helper
89
- code = "#{const.upcase}.map { |k,v| [I18n.translate(\"activerecord.symbolizes.\#{ActiveSupport::Inflector.underscore(self.model_name)}.#{attr_name}.\#{k}\"), k] }" #.to_sym rescue nila
90
- "def self.get_#{const}; #{code}; end;"
91
- else
92
- "def self.get_#{const}; #{const.upcase}.map(&:reverse); end"
93
- end
94
- class_eval(ev)
95
- class_eval "def self.#{attr_name}_enum; self.get_#{const}; end"
86
+ values_name = attr_name_str + '_values'
87
+ values_const_name = values_name.upcase
88
+
89
+ # Get the values of :in
90
+ const_set values_const_name, enum_hash unless const_defined? values_const_name
91
+
92
+ [
93
+ 'get_' + values_name,
94
+ attr_name_str + '_enum',
95
+ ].each do |enum_method_name|
96
96
 
97
- if methods
98
- values.each do |value|
99
- key = value[0]
97
+ define_singleton_method(enum_method_name) do
98
+ if i18n
99
+ enum_hash.each_key.map do |symbol|
100
+ [i18n_translation_for(attr_name_str, symbol), symbol]
101
+ end
102
+ else
103
+ enum_hash.map(&:reverse)
104
+ end
105
+ end
106
+ end
100
107
 
101
- # It's a good idea to test for name collisions here and raise exceptions.
102
- # However, the existing software with this kind of errors will start crashing,
103
- # so I'd postpone this improvement until the next major version
104
- # this way it will not affect those people who use ~> in their Gemfiles
108
+ if methods
109
+ enum_hash.each_key do |key|
110
+ # It's a good idea to test for name collisions here and raise exceptions.
111
+ # However, the existing software with this kind of errors will start crashing,
112
+ # so I'd postpone this improvement until the next major version
113
+ # this way it will not affect those people who use ~> in their Gemfiles
105
114
 
106
- # raise ArgumentError, "re-defined #{key}? method of #{self.name} class due to 'symbolize'" if method_defined?("#{key}?")
115
+ # raise ArgumentError, "re-defined #{key}? method of #{self.name} class due to 'symbolize'" if method_defined?("#{key}?")
107
116
 
108
- define_method("#{key}?") do
109
- self.send(attr_name) == key.to_sym
117
+ define_method("#{key}?") do
118
+ send(attr_name_str) == key.to_sym
119
+ end
110
120
  end
111
121
  end
112
- end
113
122
 
114
- if scopes
115
- if scopes == :shallow
116
- values.each do |value|
117
- name = value[0]
118
- if name.respond_to?(:to_sym)
119
- scope name.to_sym, -> { where(attr_name => name.to_s) }
123
+ if scopes
124
+ if scopes == :shallow
125
+ enum_hash.each_key do |name|
126
+ next unless name.respond_to?(:to_sym)
127
+
128
+ scope name, -> { where(attr_name_str => name) }
120
129
  # Figure out if this as another option, or default...
121
- # scope_comm.call "not_#{attr_name}".to_sym, :conditions => { attr_name != name }
130
+ # scope "not_#{name}", -> { where.not(attr_name_str => name)
122
131
  end
132
+ else
133
+ scope attr_name_str, ->(val) { where(attr_name_str => val) }
123
134
  end
124
- else
125
- scope attr_name, ->(enum) { where(attr_name => enum) }
126
135
  end
136
+
137
+ if validation
138
+ validates(*attr_names, configuration.slice(:allow_nil, :allow_blank).merge(:inclusion => { :in => enum_hash.keys }))
139
+ end
140
+ end
141
+
142
+ define_method(attr_name_str) { read_and_symbolize_attribute(attr_name_str) || default_option }
143
+ define_method(attr_name_str + '=') { |value| write_symbolized_attribute(attr_name_str, value) }
144
+
145
+ if default_option
146
+ before_save { self[attr_name_str] ||= default_option }
147
+ else
148
+ define_method(attr_name_str) { read_and_symbolize_attribute(attr_name_str) }
127
149
  end
128
150
 
129
- if validation
130
- validation = "validates :#{attr_names.join(', :')}"
131
- validation += ", :inclusion => { :in => #{values.keys.inspect} }"
132
- validation += ", :allow_nil => true" if configuration[:allow_nil]
133
- validation += ", :allow_blank => true" if configuration[:allow_blank]
134
- class_eval validation
151
+ define_method(attr_name_str + '_text') do
152
+ if i18n
153
+ read_i18n_attribute(attr_name_str)
154
+ else
155
+ attr_value = send(attr_name_str)
156
+ if enum
157
+ enum_hash[attr_value]
158
+ else
159
+ attr_value.to_s
160
+ end
161
+ end
135
162
  end
136
163
  end
137
- end
138
164
 
139
- attr_names.each do |attr_name|
165
+ # merge new symbolized attribute and create a new array to ensure that each class in inheritance hierarchy
166
+ # has its own array of symbolized attributes
167
+ self.symbolized_attributes += attr_names.map(&:to_s)
168
+ end
140
169
 
141
- if default_option
142
- class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}') || :#{default_option}; end")
143
- class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
144
- class_eval("def set_default_for_attr_#{attr_name}; self[:#{attr_name}] ||= :#{default_option}; end")
145
- class_eval("before_save :set_default_for_attr_#{attr_name}")
146
- else
147
- class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}'); end")
148
- class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
170
+ # Hook used by Rails to do extra stuff to attributes when they are initialized.
171
+ def initialize_attributes(*args)
172
+ super.tap do |attributes|
173
+ # Make sure any default values read from the database are symbolized
174
+ symbolized_attributes.each do |attr_name|
175
+ attributes[attr_name] = symbolize_attribute(attributes[attr_name])
176
+ end
149
177
  end
150
- if i18n
151
- class_eval("def #{attr_name}_text; read_i18n_attribute('#{attr_name}'); end")
152
- elsif enum
153
- class_eval("def #{attr_name}_text; #{attr_name.to_s.upcase}_VALUES[#{attr_name}]; end")
178
+ end
179
+
180
+ # String becomes symbol, booleans string and nil nil.
181
+ def symbolize_attribute(value)
182
+ case value
183
+ when String
184
+ value.presence.try(:to_sym)
185
+ when Symbol, TrueClass, FalseClass, Numeric
186
+ value
154
187
  else
155
- class_eval("def #{attr_name}_text; #{attr_name}.to_s; end")
188
+ nil
156
189
  end
157
190
  end
158
191
 
159
- # merge new symbolized attribute and create a new array to ensure that each class in inheritance hierarchy
160
- # has its own array of symbolized attributes
161
- self.symbolized_attributes += attr_names.map(&:to_s)
162
- end
163
-
164
- # Hook used by Rails to do extra stuff to attributes when they are initialized.
165
- def initialize_attributes *args
166
- super.tap do |attributes|
167
- # Make sure any default values read from the database are symbolized
168
- symbolized_attributes.each do |attr_name|
169
- attributes[attr_name] = symbolize_attribute(attributes[attr_name])
170
- end
192
+ def i18n_translation_for(attr_name, attr_value)
193
+ I18n.translate("activerecord.symbolizes.#{model_name.to_s.underscore}.#{attr_name}.#{attr_value}")
171
194
  end
172
195
  end
173
196
 
174
197
  # String becomes symbol, booleans string and nil nil.
175
- def symbolize_attribute value
176
- case value
177
- when String
178
- value.presence.try(:to_sym)
179
- when Symbol, TrueClass, FalseClass, Numeric
180
- value
181
- else
182
- nil
183
- end
198
+ def symbolize_attribute(value)
199
+ self.class.symbolize_attribute(value)
184
200
  end
185
- end
186
-
187
- # String becomes symbol, booleans string and nil nil.
188
- def symbolize_attribute value
189
- self.class.symbolize_attribute value
190
- end
191
-
192
- # Return an attribute's value as a symbol or nil
193
- def read_and_symbolize_attribute attr_name
194
- symbolize_attribute self[attr_name]
195
- end
196
201
 
197
- # Return an attribute's i18n
198
- def read_i18n_attribute attr_name
199
- attr = read_attribute(attr_name)
200
- t = I18n.translate("activerecord.symbolizes.#{self.class.model_name.to_s.underscore}.#{attr_name}.#{attr}") #.to_sym rescue nila
201
- t.is_a?(Hash) ? nil : t
202
- end
202
+ # Return an attribute's value as a symbol or nil
203
+ def read_and_symbolize_attribute(attr_name)
204
+ symbolize_attribute(read_attribute(attr_name))
205
+ end
203
206
 
204
- # Write a symbolized value. Watch out for booleans.
205
- def write_symbolized_attribute attr_name, value
206
- val = { "true" => true, "false" => false }[value]
207
- val = symbolize_attribute(value) if val.nil?
207
+ # Return an attribute's i18n
208
+ def read_i18n_attribute(attr_name)
209
+ unless (t = self.class.i18n_translation_for(attr_name, read_attribute(attr_name))).is_a?(Hash)
210
+ t
211
+ end
212
+ end
208
213
 
209
- self[attr_name] = val #.to_s
214
+ # Write a symbolized value. Watch out for booleans.
215
+ def write_symbolized_attribute(attr_name, value)
216
+ write_attribute(attr_name, symbolize_attribute(value))
217
+ end
210
218
  end
211
219
  end
@@ -1,4 +1,5 @@
1
1
  require 'active_support/concern'
2
+ require 'active_support/core_ext/hash/keys'
2
3
 
3
4
  module Mongoid
4
5
  module Symbolize
@@ -49,106 +50,117 @@ module Mongoid
49
50
  # Specifies that values of the given attributes should be returned
50
51
  # as symbols. The table column should be created of type string.
51
52
 
52
- def symbolize *attr_names
53
- configuration = {}
54
- configuration.update(attr_names.extract_options!)
53
+ def symbolize(*attr_names)
54
+ configuration = attr_names.extract_options!
55
+ configuration.assert_valid_keys(:in, :within, :i18n, :scopes, :methods, :capitalize, :validate, :default, :allow_blank, :allow_nil, :type)
55
56
 
56
- enum = configuration[:in] || configuration[:within]
57
- i18n = configuration.delete(:i18n)
58
- i18n = (!enum.instance_of?(Hash) && enum) if i18n.nil?
59
- scopes = configuration.delete :scopes
60
- methods = configuration.delete :methods
61
- capitalize = configuration.delete :capitalize
62
- validation = configuration.delete(:validate) != false
63
- field_type = configuration.delete :type
64
- default_opt = configuration.delete :default
65
- enum = [true, false] if [Boolean, ::Boolean].include?(field_type)
57
+ enum = configuration[:in] || configuration[:within]
58
+ i18n = configuration[:i18n]
59
+ i18n = enum && !enum.is_a?(Hash) if i18n.nil?
60
+ scopes = configuration[:scopes]
61
+ methods = configuration[:methods]
62
+ capitalize = configuration[:capitalize]
63
+ validation = configuration[:validate] != false
64
+ default_option = configuration[:default]
66
65
 
67
- unless enum.nil?
66
+ field_type = configuration[:type] || Symbol
67
+ enum = [true, false] if [Boolean, ::Boolean].include?(field_type)
68
68
 
69
- attr_names.each do |attr_name|
70
- # attr_name = attr_name.to_s
71
-
72
- #
73
- # Builds Mongoid 'field :name, type: type, :default'
74
- #
75
- const = "#{attr_name}_values"
76
- mongo_opts = ", :type => #{field_type || 'Symbol'}"
77
- mongo_opts += ", :default => :#{default_opt}" if default_opt
78
- class_eval("field :#{attr_name} #{mongo_opts}")
69
+ attr_names.each do |attr_name|
70
+ attr_name_str = attr_name.to_s
79
71
 
72
+ if enum
73
+ enum_hash = \
80
74
  if enum.is_a?(Hash)
81
- values = enum
75
+ enum
82
76
  else
83
- values = {}
84
- enum.map do |val|
85
- key = val.respond_to?(:to_sym) ? val.to_sym : val
86
- values[key] = capitalize ? val.to_s.capitalize : val.to_s
77
+ enum.each_with_object({}) do |val, hsh|
78
+ hsh.store(val.respond_to?(:to_sym) ? val.to_sym : val,
79
+ capitalize ? val.to_s.capitalize : val.to_s)
87
80
  end
88
81
  end
89
82
 
83
+ #
84
+ # Builds Mongoid 'field :name, type: type, :default'
85
+ #
86
+ { :type => field_type }.tap do |field_opts|
87
+ field_opts.merge!(:default => default_option) if default_option
88
+ field attr_name, field_opts
89
+ end
90
+
91
+ values_name = attr_name_str + '_values'
92
+ values_const_name = values_name.upcase
93
+
90
94
  # Get the values of :in
91
- const_set const.upcase, values unless const_defined? const.upcase
92
- ev = if i18n
93
- # This one is a dropdown helper
94
- code = "#{const.upcase}.map { |k,v| [I18n.t(\"mongoid.symbolizes.\#{ActiveSupport::Inflector.underscore(self.model_name)}.#{attr_name}.\#{k}\"), k] }" #.to_sym rescue nila
95
- "def self.get_#{const}; #{code}; end;"
96
- else
97
- "def self.get_#{const}; #{const.upcase}.map(&:reverse); end"
98
- end
99
- class_eval(ev)
100
- class_eval "def self.#{attr_name}_enum; self.get_#{const}; end"
95
+ const_set values_const_name, enum_hash unless const_defined? values_const_name
96
+
97
+ [
98
+ 'get_' + values_name, attr_name_str + '_enum'
99
+ ].each do |enum_method_name|
100
+
101
+ define_singleton_method(enum_method_name) do
102
+ if i18n
103
+ enum_hash.each_key.map do |symbol|
104
+ [i18n_translation_for(attr_name_str, symbol), symbol]
105
+ end
106
+ else
107
+ enum_hash.map(&:reverse)
108
+ end
109
+ end
110
+ end
101
111
 
102
112
  if methods
103
- values.each do |k, v|
104
- define_method("#{k}?") do
105
- self.send(attr_name) == k
113
+ enum_hash.each_key do |key|
114
+ define_method("#{key}?") do
115
+ send(attr_name_str) == key.to_sym
106
116
  end
107
117
  end
108
118
  end
109
119
 
110
120
  if scopes
111
121
  if scopes == :shallow
112
- values.each do |k, v|
113
- next unless k.respond_to?(:to_sym)
114
- scope k.to_sym, -> { where(attr_name => k) }
122
+ enum_hash.each_key do |name|
123
+ next unless name.respond_to?(:to_sym)
124
+ scope name, -> { where(attr_name_str => name) }
115
125
  end
116
126
  else # scoped scopes
117
- scope attr_name, ->(enum) { where(attr_name => enum) }
127
+ scope attr_name_str, ->(val) { where(attr_name_str => val) }
118
128
  end
119
129
  end
120
130
 
121
131
  if validation
122
- v = "validates :#{attr_names.join(', :')}" +
123
- ",:inclusion => { :in => #{values.keys.inspect} }"
124
- v += ',:allow_nil => true' if configuration[:allow_nil]
125
- v += ',:allow_blank => true' if configuration[:allow_blank]
126
- class_eval v
132
+ validates(*attr_names, configuration.slice(:allow_nil, :allow_blank).merge(:inclusion => { :in => enum_hash.keys }))
127
133
  end
128
-
129
134
  end
130
- end
131
135
 
132
- #
133
- # Creates <attribute>_text helper, human text for attribute.
134
- #
135
- attr_names.each do |attr_name|
136
- if i18n # memoize call to translate... good idea?
137
- define_method "#{attr_name}_text" do
138
- attr = read_attribute(attr_name)
139
- return nil if attr.nil?
140
- I18n.t("mongoid.symbolizes.#{self.class.model_name.to_s.underscore}.#{attr_name}.#{attr}")
136
+ #
137
+ # Creates <attribute>_text helper, human text for attribute.
138
+ #
139
+ define_method(attr_name_str + '_text') do
140
+ if i18n
141
+ read_i18n_attribute(attr_name_str)
142
+ else
143
+ attr_value = send(attr_name_str)
144
+ if enum
145
+ enum_hash[attr_value]
146
+ else
147
+ attr_value.to_s
148
+ end
141
149
  end
142
- elsif enum
143
- class_eval("def #{attr_name}_text; #{attr_name.to_s.upcase}_VALUES[#{attr_name}]; end")
144
- else
145
- class_eval("def #{attr_name}_text; #{attr_name}.to_s; end")
146
150
  end
147
- end
148
151
 
152
+ def i18n_translation_for(attr_name, attr_value)
153
+ I18n.translate("mongoid.symbolizes.#{model_name.to_s.underscore}.#{attr_name}.#{attr_value}")
154
+ end
155
+ end
149
156
  end
150
-
151
157
  end # ClassMethods
158
+
159
+ # Return an attribute's i18n
160
+ def read_i18n_attribute(attr_name)
161
+ t = self.class.i18n_translation_for(attr_name, read_attribute(attr_name))
162
+ t.is_a?(Hash) ? nil : t
163
+ end
152
164
  end # Symbolize
153
165
  end # Mongoid
154
166