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/.gitignore +0 -1
- data/.travis.yml +7 -3
- data/Appraisals +14 -0
- data/Gemfile +7 -1
- data/Gemfile.lock +57 -0
- data/README.rdoc +48 -4
- data/Rakefile +3 -3
- data/gemfiles/rails-3.0.gemfile +11 -0
- data/gemfiles/rails-3.0.gemfile.lock +56 -0
- data/gemfiles/rails-3.1.gemfile +11 -0
- data/gemfiles/rails-3.1.gemfile.lock +58 -0
- data/gemfiles/rails-3.2.gemfile +11 -0
- data/gemfiles/rails-3.2.gemfile.lock +58 -0
- data/lib/simple_enum.rb +35 -16
- data/lib/simple_enum/enum_hash.rb +24 -14
- data/lib/simple_enum/mongoid.rb +52 -0
- data/lib/simple_enum/validation.rb +1 -1
- data/lib/simple_enum/version.rb +1 -1
- data/locales/en.yml +4 -0
- data/simple_enum.gemspec +8 -6
- data/test/array_conversions_test.rb +9 -11
- data/test/class_methods_test.rb +20 -34
- data/test/dirty_attributes_test.rb +4 -5
- data/test/enum_hash_test.rb +16 -21
- data/test/finders_test.rb +13 -9
- data/test/locales.yml +17 -9
- data/test/mongoid_test.rb +38 -0
- data/test/object_backed_test.rb +17 -23
- data/test/orm/active_record.rb +99 -0
- data/test/orm/common.rb +23 -0
- data/test/orm/mongoid.rb +101 -0
- data/test/poro_test.rb +20 -0
- data/test/prefixes_test.rb +5 -7
- data/test/simple_enum_test.rb +68 -55
- data/test/test_helper.rb +22 -49
- data/test/without_shortcuts_test.rb +8 -9
- metadata +101 -39
- data/lib/simple_enum/object_support.rb +0 -37
- data/test/object_support_test.rb +0 -29
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
|
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
|
241
|
+
sym = EnumHash.symbolize(k)
|
230
242
|
|
231
243
|
define_method("#{prefix}#{sym}?") do
|
232
|
-
|
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
|
-
|
251
|
-
|
252
|
-
|
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 <<
|
255
|
-
|
256
|
-
|
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
|
-
#
|
262
|
-
|
278
|
+
# include in AR
|
279
|
+
ActiveSupport.on_load(:active_record) do
|
280
|
+
ActiveRecord::Base.send(:include, SimpleEnum)
|
281
|
+
end
|
263
282
|
|
264
|
-
|
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.
|
19
|
-
ary = args.map { |e| [e, e.id] } if args.first.is_a?(
|
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
|
35
|
+
@sym_value_lookup[EnumHash.symbolize(k)] if k
|
27
36
|
end
|
28
|
-
|
37
|
+
|
29
38
|
def method_missing(symbol, *args)
|
30
|
-
|
31
|
-
|
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
|
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[:
|
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
|
data/lib/simple_enum/version.rb
CHANGED
data/locales/en.yml
CHANGED
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
|
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",
|
26
|
-
|
27
|
-
s.add_development_dependency 'rake', '>= 0.
|
28
|
-
s.add_development_dependency '
|
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 <
|
3
|
+
class ArrayConversionsTest < MiniTest::Unit::TestCase
|
4
4
|
def setup
|
5
5
|
reload_db :genders => true
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
16
|
-
assert_equal
|
17
|
-
assert_equal
|
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
|
19
|
+
assert_equal @female.id, jane.gender_cd
|
22
20
|
end
|
23
21
|
end
|
data/test/class_methods_test.rb
CHANGED
@@ -1,38 +1,40 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ClassMethodsTest <
|
3
|
+
class ClassMethodsTest < MiniTest::Unit::TestCase
|
4
4
|
def setup
|
5
5
|
reload_db
|
6
6
|
end
|
7
7
|
|
8
|
-
|
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
|
-
|
13
|
+
refute_nil Dummy.genders[:female]
|
14
14
|
end
|
15
15
|
|
16
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
78
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
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
|
-
|
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
|