simple_enum 1.4.1 → 1.5.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/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