simple_enum 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/simple_enum.rb CHANGED
@@ -8,11 +8,11 @@
8
8
  #
9
9
  # See the +as_enum+ documentation for more details.
10
10
 
11
- # because we depend on AR and i18n
11
+ # because we depend on i18n and activesupport
12
12
  require 'i18n'
13
+ require 'active_support'
13
14
 
14
15
  require 'simple_enum/enum_hash'
15
- require 'simple_enum/object_support'
16
16
  require 'simple_enum/validation'
17
17
 
18
18
  require 'active_support/deprecation'
@@ -174,7 +174,7 @@ module SimpleEnum
174
174
 
175
175
  # generate getter
176
176
  define_method("#{enum_cd}") do
177
- id = read_attribute options[:column]
177
+ id = respond_to?(:read_attribute) ? read_attribute(options[:column]) : send(options[:column])
178
178
  values_inverted[id]
179
179
  end
180
180
 
@@ -182,7 +182,15 @@ module SimpleEnum
182
182
  define_method("#{enum_cd}=") do |new_value|
183
183
  v = new_value.blank? ? nil : values[new_value.to_sym]
184
184
  raise(ArgumentError, "Invalid enumeration value: #{new_value}") if (options[:whiny] and v.nil? and !new_value.blank?)
185
- write_attribute options[:column], v
185
+ respond_to?(:write_attribute) ? write_attribute(options[:column], v) : send("#{options[:column]}=", v)
186
+ end
187
+
188
+ # generate checker
189
+ define_method("#{enum_cd}?") do |*args|
190
+ current = send(enum_cd)
191
+ return current == EnumHash.symbolize(args.first) if args.length > 0
192
+
193
+ !!current
186
194
  end
187
195
 
188
196
  # support dirty attributes by delegating to column, currently opt-in
@@ -200,6 +208,10 @@ module SimpleEnum
200
208
  attr_name = enum_cd.to_s.pluralize
201
209
  enum_attr = :"#{attr_name.downcase}_enum_hash"
202
210
 
211
+ define_method("human_#{enum_cd}") do
212
+ self.class.human_enum_name(attr_name, self.send(enum_cd))
213
+ end
214
+
203
215
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
204
216
  class_attribute #{enum_attr.inspect}, :instance_write => false, :instance_reader => false
205
217
 
@@ -226,13 +238,14 @@ module SimpleEnum
226
238
  prefix = options[:prefix] && "#{options[:prefix] == true ? enum_cd : options[:prefix]}_"
227
239
 
228
240
  values.each do |k,code|
229
- sym = k.to_enum_sym
241
+ sym = EnumHash.symbolize(k)
230
242
 
231
243
  define_method("#{prefix}#{sym}?") do
232
- code == read_attribute(options[:column])
244
+ current = respond_to?(:read_attribute) ? read_attribute(options[:column]) : send(options[:column])
245
+ code == current
233
246
  end
234
247
  define_method("#{prefix}#{sym}!") do
235
- write_attribute options[:column], code
248
+ respond_to?(:write_attribute) ? write_attribute(options[:column], code) : send("#{options[:column]}=", code)
236
249
  sym
237
250
  end
238
251
 
@@ -247,19 +260,25 @@ module SimpleEnum
247
260
  include Validation
248
261
 
249
262
  def human_enum_name(enum, key, options = {})
250
- klasses = self.respond_to?(:descendants) ? descendants : ancestors
251
- defaults = ([self] + klasses).map { |klass| :"#{klass.name.underscore}.#{enum}.#{key}" }
252
- defaults << :"#{enum}.#{key}"
263
+ defaults = lookup_ancestors.map do |klass|
264
+ :"#{self.i18n_scope}.enums.#{klass.model_name.i18n_key}.#{enum}.#{key}"
265
+ end
266
+
267
+ defaults << :"enums.#{self.model_name.i18n_key}.#{enum}.#{key}"
268
+ defaults << :"enums.#{enum}.#{key}"
253
269
  defaults << options.delete(:default) if options[:default]
254
- defaults << "#{key}".humanize
255
- options[:count] ||= 1
256
- I18n.translate(defaults.shift, options.merge(:default => defaults.flatten, :scope => [:activerecord, :enums]))
270
+ defaults << key.to_s.humanize
271
+
272
+ options.reverse_merge! :count => 1, :default => defaults
273
+ I18n.translate(defaults.shift, options)
257
274
  end
258
275
  end
259
276
  end
260
277
 
261
- # Tie stuff together and load translations if ActiveRecord is defined
262
- Object.send(:include, SimpleEnum::ObjectSupport)
278
+ # include in AR
279
+ ActiveSupport.on_load(:active_record) do
280
+ ActiveRecord::Base.send(:include, SimpleEnum)
281
+ end
263
282
 
264
- ActiveRecord::Base.send(:include, SimpleEnum) if defined?(ActiveRecord)
283
+ # setup i18n load path...
265
284
  I18n.load_path << File.join(File.dirname(__FILE__), '..', 'locales', 'en.yml')
@@ -1,46 +1,56 @@
1
1
  module SimpleEnum
2
-
2
+
3
3
  # Internal hash class, used to handle the enumerations et al.
4
4
  # Works like to original +Hash+ class, but with some added value,
5
- # like access to
5
+ # like access to
6
+ #
6
7
  #
7
- #
8
8
  class EnumHash < ::ActiveSupport::OrderedHash
9
+
10
+ # Converts an entity to a symbol, uses to_enum_sym, if possible.
11
+ def self.symbolize(sym)
12
+ return sym.to_enum_sym if sym.respond_to?(:to_enum_sym)
13
+ return sym.to_sym if sym.respond_to?(:to_sym)
14
+ return sym.name.to_s.parameterize('_').to_sym if sym.respond_to?(:name)
15
+ sym.to_param.to_sym unless sym.blank?
16
+ end
17
+
9
18
  def initialize(args = [])
10
19
  super()
11
-
20
+
12
21
  @reverse_sym_lookup = {}
13
22
  @sym_value_lookup = {}
14
23
 
15
24
  if args.is_a?(Hash)
16
25
  args.each { |k,v| set_value_for_reverse_lookup(k, v) }
17
26
  else
18
- ary = args.send(args.respond_to?(:enum_with_index) ? :enum_with_index : :each_with_index).to_a unless args.first.is_a?(ActiveRecord::Base) or args.first.is_a?(Array)
19
- ary = args.map { |e| [e, e.id] } if args.first.is_a?(ActiveRecord::Base)
27
+ ary = args.send(args.respond_to?(:enum_with_index) ? :enum_with_index : :each_with_index).to_a unless args.first.respond_to?(:map)
28
+ ary = args.map { |e| [e, e.id] } if args.first.respond_to?(:map) && !args.first.is_a?(Array)
20
29
  ary ||= args
21
30
  ary.each { |e| set_value_for_reverse_lookup(e[0], e[1]) }
22
31
  end
23
32
  end
24
-
33
+
25
34
  def default(k = nil)
26
- @sym_value_lookup[k.to_enum_sym] if k
35
+ @sym_value_lookup[EnumHash.symbolize(k)] if k
27
36
  end
28
-
37
+
29
38
  def method_missing(symbol, *args)
30
- if @sym_value_lookup.has_key?(symbol.to_enum_sym)
31
- return @reverse_sym_lookup[symbol.to_enum_sym] if args.first
39
+ sym = EnumHash.symbolize(symbol)
40
+ if @sym_value_lookup.has_key?(sym)
41
+ return @reverse_sym_lookup[sym] if args.first
32
42
  self[symbol]
33
43
  else
34
44
  super
35
45
  end
36
46
  end
37
-
47
+
38
48
  private
39
49
  def set_value_for_reverse_lookup(key, value)
40
- sym = key.to_enum_sym
50
+ sym = EnumHash.symbolize(key)
41
51
  self[key] = value
42
52
  @reverse_sym_lookup[sym] = key
43
53
  @sym_value_lookup[sym] = value
44
- end
54
+ end
45
55
  end
46
56
  end
@@ -0,0 +1,52 @@
1
+ require 'simple_enum'
2
+
3
+ module SimpleEnum
4
+
5
+ # Enables support for mongoid, also automatically creates the
6
+ # requested field.
7
+ #
8
+ # class Person
9
+ # include Mongoid::Document
10
+ # include SimpleEnum::Mongoid
11
+ #
12
+ # field :name
13
+ # as_enum :gender, [:female, :male]
14
+ # end
15
+ #
16
+ # When no field is requested:
17
+ #
18
+ # field :gender_cd, :type => Integer
19
+ # as_enum :gender, [:female, :male], :field => false
20
+ #
21
+ # or custom field options (like e.g. type want to be passed):
22
+ #
23
+ # as_enum :gender, [:female, :male], :field => { :type => Integer }
24
+ #
25
+ module Mongoid
26
+ extend ActiveSupport::Concern
27
+
28
+ included do
29
+ # create class level methods
30
+ class_attribute :enum_definitions, :instance_write => false, :instance_reader => false
31
+ enum_definitions = {}
32
+ end
33
+
34
+ module ClassMethods
35
+ include SimpleEnum::ClassMethods
36
+
37
+ # Wrap method chain to create mongoid field and additional
38
+ # column options
39
+ def as_enum_with_mongoid(enum_cd, values, options = {})
40
+ options = SimpleEnum.default_options.merge({ :column => "#{enum_cd}_cd" }).merge(options)
41
+
42
+ # forward custom field options
43
+ field_options = options.delete(:field)
44
+ field(options[:column], field_options.is_a?(Hash) ? field_options : {}) unless field_options === false
45
+
46
+ # call original as_enum method
47
+ as_enum_without_mongoid(enum_cd, values, options)
48
+ end
49
+ alias_method_chain :as_enum, :mongoid
50
+ end
51
+ end
52
+ end
@@ -29,7 +29,7 @@ module SimpleEnum
29
29
  enum_def = enum_definitions[attr_name]
30
30
  unless send(enum_def[:name].to_s.pluralize).values.include?(value)
31
31
  params = { :value => value}
32
- params[:default] = configuration[:message] if configuration[:message].present?
32
+ params[:message] = configuration[:message] if configuration[:message].present?
33
33
  record.errors.add(enum_def[:name], :invalid_enum, params)
34
34
  end
35
35
  end
@@ -1,5 +1,5 @@
1
1
  module SimpleEnum
2
2
 
3
3
  # +SimpleEnum+ version string.
4
- VERSION = "1.4.1"
4
+ VERSION = "1.5.0"
5
5
  end
data/locales/en.yml CHANGED
@@ -4,3 +4,7 @@ en:
4
4
  errors:
5
5
  messages:
6
6
  invalid_enum: invalid option supplied.
7
+ mongoid:
8
+ errors:
9
+ messages:
10
+ invalid_enum: invalid option supplied.
data/simple_enum.gemspec CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
6
6
  s.name = "simple_enum"
7
7
  s.version = SimpleEnum::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.summary = "Simple enum-like field support for active records."
10
- s.description = ""
9
+ s.summary = "Simple enum-like field support for models."
10
+ s.description = "Provides enum-like fields for ActiveRecord, ActiveModel and Mongoid models."
11
11
 
12
12
  s.required_ruby_version = ">= 1.8.7"
13
13
  s.required_rubygems_version = ">= 1.3.6"
@@ -22,10 +22,12 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.license = 'MIT'
24
24
 
25
- s.add_dependency "activesupport", "~> 3.0"
26
-
27
- s.add_development_dependency 'rake', '>= 0.8.7'
28
- s.add_development_dependency 'activerecord', '~> 3.0'
25
+ s.add_dependency "activesupport", '>= 3.0.0'
26
+
27
+ s.add_development_dependency 'rake', '>= 0.9.2'
28
+ s.add_development_dependency 'appraisal', '>= 0.4'
29
+ s.add_development_dependency 'minitest', '>= 2.3.0'
30
+ s.add_development_dependency 'activerecord', '>= 3.0.0'
29
31
  s.add_development_dependency 'mongoid', '~> 2.0'
30
32
 
31
33
  unless RUBY_PLATFORM =~ /java/
@@ -1,23 +1,21 @@
1
1
  require 'test_helper'
2
2
 
3
- class ArrayConversionsTest < ActiveSupport::TestCase
3
+ class ArrayConversionsTest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  reload_db :genders => true
6
6
  end
7
7
 
8
- test "that conversion of Gender.find(:all).map {...} to enumeration values as symbols works the same as [:male,:female]" do
9
- class DummyArrayTest1 < ActiveRecord::Base
10
- set_table_name 'dummies'
11
- as_enum :gender, Gender.find(:all).map { |g| [g.name.to_sym, g.id] }
12
- end
13
- with_enum = DummyArrayTest1
8
+ def test_conversion_to_enumartions
9
+ with_enum = named_dummy('DummyArrayTest1') do
10
+ as_enum :gender, Gender.all.map { |g| [g.name.to_sym, g.id] }
11
+ end
14
12
 
15
- assert_equal 0, with_enum.male
16
- assert_equal 1, with_enum.female
17
- assert_equal 1, with_enum.genders(:female)
13
+ assert_equal @male.id, with_enum.male
14
+ assert_equal @female.id, with_enum.female
15
+ assert_equal @female.id, with_enum.genders(:female)
18
16
 
19
17
  jane = with_enum.new :gender => :female
20
18
  assert_equal :female, jane.gender
21
- assert_equal 1, jane.gender_cd
19
+ assert_equal @female.id, jane.gender_cd
22
20
  end
23
21
  end
@@ -1,38 +1,40 @@
1
1
  require 'test_helper'
2
2
 
3
- class ClassMethodsTest < ActiveSupport::TestCase
3
+ class ClassMethodsTest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  reload_db
6
6
  end
7
7
 
8
- test "that Klass.genders[:sym] == Klass.genders(:sym)" do
8
+ def test_that_klass_genders_array_accessor_equal_to_attr_accessor
9
9
  assert_equal 0, Dummy.genders(:male)
10
10
  assert_equal Dummy.genders(:male), Dummy.genders[:male]
11
11
  assert_nil Dummy.genders(:inexistent)
12
12
  assert_nil Dummy.genders[:inexistent]
13
- assert_not_nil Dummy.genders[:female]
13
+ refute_nil Dummy.genders[:female]
14
14
  end
15
15
 
16
- test "inheritance of `genders` to subclasses (#issue/3)" do
16
+ def test_inheritance_of_genders_to_subclasses
17
+ # issue#3
17
18
  assert_equal({ :female => 1, :male => 0}, SpecificDummy.genders)
18
19
  end
19
20
 
20
- test "genders reader created" do
21
+ def test_genders_reader_created
21
22
  assert_equal [0, 1], Dummy.genders.values.sort
22
23
  assert_equal %w{female male}, Dummy.genders.keys.map(&:to_s).sort
23
24
  end
24
25
 
25
- test "that Klass.genders(:sym_a, :sym_b) returns an array of values, useful for IN clauses" do
26
+ def test_that_klass_genders_return_array_of_values
27
+ # usefuled for IN clauses
26
28
  assert_equal [0, 1], Dummy.genders(:male, :female)
27
29
  assert_equal [1, 0], Dummy.genders(:female, :male)
28
30
  end
29
31
 
30
- test "inverted Hash returns synonym by code" do
32
+ def test_inverted_hash_returns_synonym_by_code
31
33
  assert_equal :male, Dummy.genders.invert[0]
32
34
  assert_equal :female, Dummy.genders.invert[1]
33
35
  end
34
36
 
35
- test "generation of value shortcuts on class" do
37
+ def test_generation_of_value_shortcuts_on_class
36
38
  g = Dummy.new
37
39
 
38
40
  assert_equal 0, Dummy.male
@@ -44,24 +46,20 @@ class ClassMethodsTest < ActiveSupport::TestCase
44
46
  assert_respond_to Dummy, :foobar
45
47
  end
46
48
 
47
- test "that no Klass.shortcut are created if :slim => true" do
48
- class Dummy1 < ActiveRecord::Base
49
- set_table_name 'dummies'
49
+ def test_that_no_klass_shortcuts_are_created_if_slim_true
50
+ with_slim = named_dummy('Dummy1') do
50
51
  as_enum :gender, [:male, :female], :slim => true
51
52
  end
52
- with_slim = Dummy1
53
53
 
54
54
  assert !with_slim.respond_to?(:male)
55
55
  assert !with_slim.respond_to?(:female)
56
56
  assert_respond_to with_slim, :genders
57
57
  end
58
58
 
59
- test "that no Klass.shortcut's are created if :slim => :class, though instance shortcuts are" do
60
- class Dummy2 < ActiveRecord::Base
61
- set_table_name 'dummies'
59
+ def test_that_no_klass_shortcuts_are_created_if_slim_class_though_instance_shortcuts_are
60
+ with_slim_class = named_dummy('Dummy2') do
62
61
  as_enum :gender, [:male, :female], :slim => :class
63
62
  end
64
- with_slim_class = Dummy2
65
63
 
66
64
  jane = with_slim_class.new
67
65
 
@@ -74,12 +72,10 @@ class ClassMethodsTest < ActiveSupport::TestCase
74
72
  assert_same 1, with_slim_class.genders[:female]
75
73
  end
76
74
 
77
- test "that Klass.shortcut respect :prefix => true and are prefixed by \#{enum_cd}" do
78
- class Dummy3 < ActiveRecord::Base
79
- set_table_name 'dummies'
75
+ def test_that_klass_shortcuts_respect_prefix_true_and_are_prefixed_by_enum_cd
76
+ with_prefix = named_dummy('Dummy3') do
80
77
  as_enum :gender, [:male, :female], :prefix => true
81
78
  end
82
- with_prefix = Dummy3
83
79
 
84
80
  assert !with_prefix.respond_to?(:male)
85
81
  assert !with_prefix.respond_to?(:female)
@@ -89,12 +85,10 @@ class ClassMethodsTest < ActiveSupport::TestCase
89
85
  assert_respond_to with_prefix, :genders
90
86
  end
91
87
 
92
- test "to ensure that Klass.shortcut also work with custom prefixes" do
93
- class Dummy4 < ActiveRecord::Base
94
- set_table_name 'dummies'
88
+ def test_to_ensure_that_klass_shortcut_also_work_with_custom_prefixes
89
+ with_custom_prefix = named_dummy('Dummy4') do
95
90
  as_enum :gender, [:male, :female], :prefix => :g
96
91
  end
97
- with_custom_prefix = Dummy4
98
92
 
99
93
  assert !with_custom_prefix.respond_to?(:male)
100
94
  assert !with_custom_prefix.respond_to?(:female)
@@ -105,22 +99,14 @@ class ClassMethodsTest < ActiveSupport::TestCase
105
99
  assert_respond_to with_custom_prefix, :genders
106
100
  end
107
101
 
108
- test "that the human_enum_name method returns translated/humanized values" do
102
+ def test_that_the_human_enum_name_method_returns_translated_humanized_values
109
103
  assert_equal :male.to_s.humanize, Dummy.human_enum_name(:genders, :male)
110
104
  assert_equal "Girl", Dummy.human_enum_name(:genders, :female)
111
105
  assert_equal "Foo", Dummy.human_enum_name(:didums, :foo)
112
106
  assert_equal "Foos", Dummy.human_enum_name(:didums, :foo, :count => 5)
113
107
  end
114
108
 
115
- test "enum_for_select class method" do
116
- for_select = Dummy.genders_for_select
117
- genders = Dummy.genders
118
- assert_equal genders.first.first, for_select.first.second
119
- assert_equal ["Male", :male], for_select.first
120
- assert_equal ["Girl", :female], for_select.last
121
- end
122
-
123
- test "enum_for_select(:value) class method" do
109
+ def test_enum_for_select_value_class_method
124
110
  for_select = Dummy.genders_for_select(:value)
125
111
  assert_equal ["Male", 0], for_select.first
126
112
  assert_equal ["Girl", 1], for_select.last