active_enum 0.3.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/MIT-LICENSE +20 -0
- data/README.rdoc +134 -0
- data/Rakefile +74 -0
- data/lib/active_enum.rb +31 -0
- data/lib/active_enum/acts_as_enum.rb +57 -0
- data/lib/active_enum/base.rb +76 -0
- data/lib/active_enum/extensions.rb +130 -0
- data/lib/active_enum/version.rb +3 -0
- data/spec/active_enum/acts_as_enum_spec.rb +28 -0
- data/spec/active_enum/base_spec.rb +120 -0
- data/spec/active_enum/extensions_spec.rb +163 -0
- data/spec/active_enum_spec.rb +20 -0
- data/spec/schema.rb +13 -0
- data/spec/spec_helper.rb +25 -0
- metadata +68 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Adam Meehan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
= ActiveEnum
|
2
|
+
|
3
|
+
Define enum classes in Rails and use them to enumerate ActiveRecord attributes. Brings together some ideas
|
4
|
+
of similar plugins that I liked and does it they way I prefer.
|
5
|
+
|
6
|
+
Enum values are stored in memory at the moment but I plan to add database and yaml.
|
7
|
+
|
8
|
+
== Install
|
9
|
+
|
10
|
+
On Gemcutter:
|
11
|
+
|
12
|
+
sudo gem install active_enum
|
13
|
+
|
14
|
+
And add to your Rails environment.rb
|
15
|
+
|
16
|
+
config.gem 'active_enum'
|
17
|
+
|
18
|
+
== Example
|
19
|
+
|
20
|
+
Define an enum class with values
|
21
|
+
|
22
|
+
class Sex < ActiveEnum::Base
|
23
|
+
value :id => 1, :name => 'Male'
|
24
|
+
value :id => 2, :name => 'Female'
|
25
|
+
end
|
26
|
+
|
27
|
+
Define using implicit id values
|
28
|
+
|
29
|
+
class Sex < ActiveEnum::Base
|
30
|
+
value :name => 'Male'
|
31
|
+
value :name => 'Female'
|
32
|
+
end
|
33
|
+
|
34
|
+
Beware that if you change the order of values defined in an enum which don't have explicit ids, then the ids will change.
|
35
|
+
This could corrupt your data if the enum values have been stored in a model record, as they will no longer map to
|
36
|
+
the original enum.
|
37
|
+
|
38
|
+
Enum class usage
|
39
|
+
|
40
|
+
Sex[1] # => 'Male'
|
41
|
+
Sex['Male'] # => 1
|
42
|
+
Sex[:male] # => 1
|
43
|
+
Sex.to_select # => [['Male', 1], ['Female',2]] for select form helpers
|
44
|
+
|
45
|
+
Use the enum to enumerate an ActiveRecord model attribute
|
46
|
+
|
47
|
+
class User < ActiveRecord::Base
|
48
|
+
enumerate :sex, :with => Sex
|
49
|
+
end
|
50
|
+
|
51
|
+
Skip the with option if the enum can be implied from the attribute
|
52
|
+
|
53
|
+
class User < ActiveRecord::Base
|
54
|
+
enumerate :sex
|
55
|
+
end
|
56
|
+
|
57
|
+
Define enum class implicitly in enumerate block
|
58
|
+
|
59
|
+
class User < ActiveRecord::Base
|
60
|
+
# defines UserSex enum
|
61
|
+
enumerate :sex do
|
62
|
+
value :name => 'Male'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Access the enum values and the enum class using the attribute method with a symbol for the enum component you want
|
67
|
+
|
68
|
+
user = User.new
|
69
|
+
user.sex = 1
|
70
|
+
user.sex # => 1
|
71
|
+
|
72
|
+
user.sex(:id) # => 1
|
73
|
+
user.sex(:name) # => 'Male'
|
74
|
+
user.sex(:enum) # => Sex
|
75
|
+
|
76
|
+
You can check if the attribute value matches a particular enum value by passing the enum value as an argument to the question method
|
77
|
+
|
78
|
+
user.sex?(:male) # => true
|
79
|
+
user.sex?(:Male) # => true
|
80
|
+
user.sex?('Male') # => true
|
81
|
+
user.sex?('Female') # => false
|
82
|
+
|
83
|
+
A convience method on the class is available to the enum class of any enumerated attribute
|
84
|
+
|
85
|
+
User.enum_for(:sex) # => Sex
|
86
|
+
|
87
|
+
You can set the default to return the enum name value for enumerated attribute
|
88
|
+
|
89
|
+
ActiveEnum.use_name_as_value = true
|
90
|
+
user.sex # => 'Male'
|
91
|
+
|
92
|
+
Define enum classes in bulk without class files, in an initializer file for example.
|
93
|
+
|
94
|
+
ActiveEnum.define do
|
95
|
+
|
96
|
+
# defines Sex
|
97
|
+
enum(:sex) do
|
98
|
+
value :name => 'Male'
|
99
|
+
value :name => 'Female'
|
100
|
+
end
|
101
|
+
|
102
|
+
# defines Language
|
103
|
+
enum(:language) do
|
104
|
+
value :name => 'English'
|
105
|
+
value :name => 'German'
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
All defined enum classes are stored in ActiveEnum.enum_classes array if you need look them up or iterate over them.
|
111
|
+
|
112
|
+
You can make an existing model class behave like an enum class with acts_as_enum
|
113
|
+
|
114
|
+
class User < ActiveRecord::Base
|
115
|
+
acts_as_enum :name_column => 'first_name'
|
116
|
+
end
|
117
|
+
|
118
|
+
Giving you the familiar enum methods
|
119
|
+
|
120
|
+
User[1]
|
121
|
+
User['Dave']
|
122
|
+
User.to_select
|
123
|
+
|
124
|
+
|
125
|
+
== TODO
|
126
|
+
* more docs
|
127
|
+
* storage options of memory, database or yaml
|
128
|
+
* use custom method name for the enumerated attribute
|
129
|
+
* named_scopes
|
130
|
+
* question methods for enum names e.g. user.male?
|
131
|
+
* possibly allow string enum values to assigned to attributes
|
132
|
+
* add enum value class for instances if there is a need
|
133
|
+
|
134
|
+
Copyright (c) 2009 Adam Meehan, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rubygems/specification'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'lib/active_enum/version'
|
7
|
+
|
8
|
+
GEM_NAME = "active_enum"
|
9
|
+
GEM_VERSION = ActiveEnum::VERSION
|
10
|
+
AUTHOR = "Adam Meehan"
|
11
|
+
EMAIL = "adam.meehan@gmail.com"
|
12
|
+
HOMEPAGE = "http://github.com/adzap/active_enum"
|
13
|
+
SUMMARY = "Define enum classes in Rails and use them to enumerate ActiveRecord attributes"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = GEM_NAME
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.rubyforge_project = "active_enum"
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
22
|
+
s.summary = SUMMARY
|
23
|
+
s.description = s.summary
|
24
|
+
s.author = AUTHOR
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
|
28
|
+
s.require_path = 'lib'
|
29
|
+
s.autorequire = GEM_NAME
|
30
|
+
s.files = %w(MIT-LICENSE README.rdoc Rakefile) + Dir.glob("{lib,spec}/**/*")
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Default: run specs.'
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
spec_files = Rake::FileList["spec/**/*_spec.rb"]
|
37
|
+
|
38
|
+
desc "Run specs"
|
39
|
+
Spec::Rake::SpecTask.new do |t|
|
40
|
+
t.spec_files = spec_files
|
41
|
+
t.spec_opts = ["-c"]
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Generate code coverage"
|
45
|
+
Spec::Rake::SpecTask.new(:coverage) do |t|
|
46
|
+
t.spec_files = spec_files
|
47
|
+
t.rcov = true
|
48
|
+
t.rcov_opts = ['--exclude', 'spec,/var/lib/gems']
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Generate documentation for plugin.'
|
52
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = 'ActiveEnum'
|
55
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
56
|
+
rdoc.rdoc_files.include('README')
|
57
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
58
|
+
end
|
59
|
+
|
60
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
61
|
+
pkg.gem_spec = spec
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "install the gem locally"
|
65
|
+
task :install => [:package] do
|
66
|
+
sh %{sudo gem install pkg/#{GEM_NAME}-#{GEM_VERSION}}
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "create a gemspec file"
|
70
|
+
task :make_spec do
|
71
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
72
|
+
file.puts spec.to_ruby
|
73
|
+
end
|
74
|
+
end
|
data/lib/active_enum.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_enum/base'
|
2
|
+
require 'active_enum/extensions'
|
3
|
+
require 'active_enum/acts_as_enum'
|
4
|
+
require 'active_enum/version'
|
5
|
+
|
6
|
+
module ActiveEnum
|
7
|
+
mattr_accessor :enum_classes
|
8
|
+
self.enum_classes = []
|
9
|
+
|
10
|
+
mattr_accessor :use_name_as_value
|
11
|
+
self.use_name_as_value = false
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
def enum(name, &block)
|
15
|
+
class_name = name.to_s.classify
|
16
|
+
class_def = <<-end_eval
|
17
|
+
class #{class_name} < ActiveEnum::Base
|
18
|
+
end
|
19
|
+
end_eval
|
20
|
+
eval(class_def, TOPLEVEL_BINDING)
|
21
|
+
new_enum = Module.const_get(class_name)
|
22
|
+
new_enum.class_eval(&block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.define(&block)
|
27
|
+
raise "Define requires block" unless block_given?
|
28
|
+
Configuration.new.instance_eval(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveEnum
|
2
|
+
|
3
|
+
module ActsAsEnum
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def acts_as_enum(options={})
|
12
|
+
class_inheritable_accessor :active_enum_options
|
13
|
+
self.active_enum_options = options.reverse_merge(:name_column => 'name')
|
14
|
+
named_scope :enum_values,
|
15
|
+
:select => "#{primary_key}, #{active_enum_options[:name_column]}",
|
16
|
+
:conditions => active_enum_options[:conditions],
|
17
|
+
:order => active_enum_options[:order]
|
18
|
+
end
|
19
|
+
|
20
|
+
def ids
|
21
|
+
enum_values.map {|v| v.id }
|
22
|
+
end
|
23
|
+
|
24
|
+
def names
|
25
|
+
enum_values.map {|v| v.send(active_enum_options[:name_column]) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_select
|
29
|
+
enum_values.map {|v| [v.send(active_enum_options[:name_column]), v.id] }
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](index)
|
33
|
+
if index.is_a?(Fixnum)
|
34
|
+
v = lookup_by_id(index)
|
35
|
+
v.send(active_enum_options[:name_column]) unless v.blank?
|
36
|
+
else
|
37
|
+
v = lookup_by_name(index)
|
38
|
+
v.id unless v.blank?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def lookup_by_id(index)
|
45
|
+
enum_values.find_by_id(index)
|
46
|
+
end
|
47
|
+
|
48
|
+
def lookup_by_name(index)
|
49
|
+
enum_values.find(:first, :conditions => ["#{active_enum_options[:name_column]} like ?", index.to_s])
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ActiveRecord::Base.send :include, ActiveEnum::ActsAsEnum
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ActiveEnum
|
2
|
+
class DuplicateValue < StandardError; end
|
3
|
+
|
4
|
+
class Base
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def inherited(subclass)
|
9
|
+
ActiveEnum.enum_classes << subclass
|
10
|
+
end
|
11
|
+
|
12
|
+
# :id => 1, :title => 'Foo'
|
13
|
+
# :title => 'Foo'
|
14
|
+
#
|
15
|
+
def value(enum_value={})
|
16
|
+
@values ||= []
|
17
|
+
|
18
|
+
id = enum_value[:id] || next_id
|
19
|
+
check_duplicate(id, enum_value[:name])
|
20
|
+
|
21
|
+
@values << [id, enum_value[:name]]
|
22
|
+
@values.sort! {|a,b| a[0] <=> b[0] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def all
|
26
|
+
@values || []
|
27
|
+
end
|
28
|
+
|
29
|
+
def ids
|
30
|
+
@values.map {|v| v[0] }
|
31
|
+
end
|
32
|
+
|
33
|
+
def names
|
34
|
+
@values.map {|v| v[1] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_select
|
38
|
+
@values.map {|v| [v[1], v[0]] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](index)
|
42
|
+
if index.is_a?(Fixnum)
|
43
|
+
row = lookup_by_id(index)
|
44
|
+
row[1] if row
|
45
|
+
else
|
46
|
+
row = lookup_by_name(index)
|
47
|
+
row[0] if row
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def lookup_by_id(index)
|
54
|
+
@values.assoc(index)
|
55
|
+
end
|
56
|
+
|
57
|
+
def lookup_by_name(index)
|
58
|
+
@values.rassoc(index.to_s) || @values.rassoc(index.to_s.titleize)
|
59
|
+
end
|
60
|
+
|
61
|
+
def next_id
|
62
|
+
(ids.max || 0) + 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_duplicate(id, name)
|
66
|
+
if lookup_by_id(id)
|
67
|
+
raise ActiveEnum::DuplicateValue, "The id #{id} is already defined for #{self} enum."
|
68
|
+
elsif lookup_by_name(name)
|
69
|
+
raise ActiveEnum::DuplicateValue, "The name #{name} is already defined for #{self} enum."
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module ActiveEnum
|
2
|
+
class EnumNotFound < StandardError; end
|
3
|
+
|
4
|
+
module Extensions
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.class_inheritable_accessor :enumerated_attributes
|
9
|
+
base.enumerated_attributes = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
# Declare an attribute to be enumerated by an enum class
|
15
|
+
#
|
16
|
+
# class Person < ActiveRecord::Base
|
17
|
+
# enumerate :sex, :with => Sex
|
18
|
+
# enumerate :sex # implies a Sex enum class exists
|
19
|
+
#
|
20
|
+
# # Pass a block to create implicit enum class as ModelAttribute e.g. PersonSex
|
21
|
+
# enumerate :sex do
|
22
|
+
# value :id => 1, :name => 'Male'
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
def enumerate(attribute, options={}, &block)
|
26
|
+
attribute = attribute.to_sym
|
27
|
+
if block_given?
|
28
|
+
enum_name = "#{self.to_s.underscore}_#{attribute}"
|
29
|
+
ActiveEnum.define { enum(enum_name, &block) }
|
30
|
+
enum = enum_name.classify.constantize
|
31
|
+
else
|
32
|
+
enum = options[:with] || attribute.to_s.classify.constantize
|
33
|
+
end
|
34
|
+
|
35
|
+
self.enumerated_attributes[attribute] = enum
|
36
|
+
|
37
|
+
define_active_enum_read_method(attribute)
|
38
|
+
define_active_enum_write_method(attribute)
|
39
|
+
define_active_enum_question_method(attribute)
|
40
|
+
rescue NameError => e
|
41
|
+
raise e unless e.message =~ /uninitialized constant/
|
42
|
+
raise ActiveEnum::EnumNotFound, "Enum class could not be found for attribute '#{attribute}' in class #{self}. Specify the enum class using the :with option."
|
43
|
+
end
|
44
|
+
|
45
|
+
def enum_for(attribute)
|
46
|
+
self.enumerated_attributes[attribute.to_sym]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Define read method to allow an argument for the enum component
|
50
|
+
#
|
51
|
+
# user.sex
|
52
|
+
# user.sex(:id)
|
53
|
+
# user.sex(:name)
|
54
|
+
# user.sex(:enum)
|
55
|
+
#
|
56
|
+
def define_active_enum_read_method(attribute)
|
57
|
+
unless instance_method_already_implemented?(attribute)
|
58
|
+
define_read_method(attribute, attribute.to_s, columns_hash[attribute.to_s])
|
59
|
+
end
|
60
|
+
|
61
|
+
old_method = "#{attribute}_without_enum"
|
62
|
+
define_method("#{attribute}_with_enum") do |*arg|
|
63
|
+
arg = arg.first
|
64
|
+
value = send(old_method)
|
65
|
+
|
66
|
+
enum = self.class.enum_for(attribute)
|
67
|
+
case arg
|
68
|
+
when :id
|
69
|
+
value if enum[value]
|
70
|
+
when :name
|
71
|
+
enum[value]
|
72
|
+
when :enum
|
73
|
+
enum
|
74
|
+
else
|
75
|
+
ActiveEnum.use_name_as_value ? enum[value] : value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method_chain attribute, :enum
|
80
|
+
end
|
81
|
+
|
82
|
+
# Define write method to also handle enum value
|
83
|
+
#
|
84
|
+
# user.sex = 1
|
85
|
+
# user.sex = :male
|
86
|
+
#
|
87
|
+
def define_active_enum_write_method(attribute)
|
88
|
+
unless instance_method_already_implemented?("#{attribute}=")
|
89
|
+
define_write_method(attribute)
|
90
|
+
end
|
91
|
+
|
92
|
+
old_method = "#{attribute}_without_enum="
|
93
|
+
define_method("#{attribute}_with_enum=") do |arg|
|
94
|
+
enum = self.class.enum_for(attribute)
|
95
|
+
if arg.is_a?(Symbol)
|
96
|
+
value = enum[arg]
|
97
|
+
send(old_method, value)
|
98
|
+
else
|
99
|
+
send(old_method, arg)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
alias_method_chain "#{attribute}=".to_sym, :enum
|
104
|
+
end
|
105
|
+
|
106
|
+
# Define question method to check enum value against attribute value
|
107
|
+
#
|
108
|
+
# user.sex?(:male)
|
109
|
+
#
|
110
|
+
def define_active_enum_question_method(attribute)
|
111
|
+
define_question_method(attribute) unless instance_method_already_implemented?("#{attribute}?")
|
112
|
+
|
113
|
+
old_method = "#{attribute}_without_enum?"
|
114
|
+
define_method("#{attribute}_with_enum?") do |*arg|
|
115
|
+
arg = arg.first
|
116
|
+
if arg
|
117
|
+
send(attribute) == self.class.enum_for(attribute)[arg]
|
118
|
+
else
|
119
|
+
send(old_method)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
alias_method_chain "#{attribute}?".to_sym, :enum
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
ActiveRecord::Base.send :include, ActiveEnum::Extensions
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class Person < ActiveRecord::Base
|
4
|
+
acts_as_enum :name_column => 'first_name'
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ActiveEnum::ActsAsEnum do
|
8
|
+
before(:all) do
|
9
|
+
@person = Person.create!(:first_name => 'Dave', :last_name => 'Smith')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'return name column value when passing id to [] method' do
|
13
|
+
Person[@person.id].should == @person.first_name
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'return id column value when passing string name to [] method' do
|
17
|
+
Person['Dave'].should == @person.id
|
18
|
+
Person['dave'].should == @person.id
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'return id column value when passing symbol name to [] method' do
|
22
|
+
Person[:dave].should == @person.id
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return array for select helpers from to_select' do
|
26
|
+
Person.to_select.should == [[@person.first_name, @person.id]]
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ActiveEnum::Base do
|
4
|
+
it 'should return empty array from :all method when no values defined' do
|
5
|
+
ActiveEnum.enum_classes = []
|
6
|
+
class NewEnum < ActiveEnum::Base
|
7
|
+
end
|
8
|
+
ActiveEnum.enum_classes.should == [NewEnum]
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return empty array from :all method when no values defined' do
|
12
|
+
define_enum.all.should == []
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should allow me to define a value with an id and name' do
|
16
|
+
enum = define_enum do
|
17
|
+
value :id => 1, :name => 'Name'
|
18
|
+
end
|
19
|
+
enum.all.should == [[1,'Name']]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should allow me to define a value with a name only' do
|
23
|
+
enum = define_enum do
|
24
|
+
value :name => 'Name'
|
25
|
+
end
|
26
|
+
enum.all.should == [[1,'Name']]
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should increment value ids when defined without ids' do
|
30
|
+
enum = define_enum do
|
31
|
+
value :name => 'Name 1'
|
32
|
+
value :name => 'Name 2'
|
33
|
+
end
|
34
|
+
enum.all.should == [[1,'Name 1'], [2, 'Name 2']]
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should raise error is the id is a duplicate' do
|
38
|
+
lambda do
|
39
|
+
define_enum do
|
40
|
+
value :id => 1, :name => 'Name 1'
|
41
|
+
value :id => 1, :name => 'Name 2'
|
42
|
+
end
|
43
|
+
end.should raise_error(ActiveEnum::DuplicateValue)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should raise error is the name is a duplicate' do
|
47
|
+
lambda do
|
48
|
+
define_enum do
|
49
|
+
value :id => 1, :name => 'Name'
|
50
|
+
value :id => 2, :name => 'Name'
|
51
|
+
end
|
52
|
+
end.should raise_error(ActiveEnum::DuplicateValue)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return sorted values by id from :all' do
|
56
|
+
enum = define_enum do
|
57
|
+
value :id => 2, :name => 'Name 2'
|
58
|
+
value :id => 1, :name => 'Name 1'
|
59
|
+
end
|
60
|
+
enum.all.first[0].should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should return array of ids' do
|
64
|
+
enum = define_enum do
|
65
|
+
value :id => 1, :name => 'Name 1'
|
66
|
+
value :id => 2, :name => 'Name 2'
|
67
|
+
end
|
68
|
+
enum.ids.should == [1,2]
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return array of names' do
|
72
|
+
enum = define_enum do
|
73
|
+
value :id => 1, :name => 'Name 1'
|
74
|
+
value :id => 2, :name => 'Name 2'
|
75
|
+
end
|
76
|
+
enum.names.should == ['Name 1', 'Name 2']
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "element reference method" do
|
80
|
+
|
81
|
+
it 'should return name when given an id' do
|
82
|
+
enum = define_enum do
|
83
|
+
value :id => 1, :name => 'Name 1'
|
84
|
+
value :id => 2, :name => 'Name 2'
|
85
|
+
end
|
86
|
+
enum[1].should == 'Name 1'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should return id when given a name' do
|
90
|
+
enum = define_enum do
|
91
|
+
value :id => 1, :name => 'Name 1'
|
92
|
+
value :id => 2, :name => 'Name 2'
|
93
|
+
end
|
94
|
+
enum['Name 1'].should == 1
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should return id when given a symbol of the name' do
|
98
|
+
enum = define_enum do
|
99
|
+
value :id => 1, :name => 'Name 1'
|
100
|
+
value :id => 2, :name => 'Name 2'
|
101
|
+
end
|
102
|
+
enum[:Name_1].should == 1
|
103
|
+
enum[:name_1].should == 1
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should return array for select helpers from to_select' do
|
109
|
+
enum = define_enum do
|
110
|
+
value :id => 1, :name => 'Name 1'
|
111
|
+
value :id => 2, :name => 'Name 2'
|
112
|
+
end
|
113
|
+
enum.to_select.should == [['Name 1',1], ['Name 2',2]]
|
114
|
+
end
|
115
|
+
|
116
|
+
def define_enum(&block)
|
117
|
+
Class.new(ActiveEnum::Base, &block)
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class Sex < ActiveEnum::Base
|
4
|
+
value :id => 1, :name => 'Male'
|
5
|
+
value :id => 2, :name => 'Female'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ActiveEnum::Extensions do
|
9
|
+
before do
|
10
|
+
Person.class_eval do
|
11
|
+
enumerate :sex, :with => Sex
|
12
|
+
end
|
13
|
+
@person = Person.new(:sex =>1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should add class :enumerate method to ActiveRecord' do
|
17
|
+
ActiveRecord::Base.should respond_to(:enumerate)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should add class :enum_for method to ActiveRecord' do
|
21
|
+
ActiveRecord::Base.should respond_to(:enum_for)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should allow implicit enumeration class from attribute name' do
|
25
|
+
Person.class_eval do
|
26
|
+
enumerate :sex
|
27
|
+
end
|
28
|
+
Person.enum_for(:sex).should == Sex
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should allow implicit enumeration class from block' do
|
32
|
+
Person.class_eval do
|
33
|
+
enumerate :sex do
|
34
|
+
value :id => 1, :name => 'Male'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Person.enum_for(:sex).should == PersonSex
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should raise error if implicit enumeration class cannot be found' do
|
41
|
+
lambda do
|
42
|
+
Person.class_eval { enumerate :first_name }
|
43
|
+
end.should raise_error(ActiveEnum::EnumNotFound)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "attribute with value" do
|
47
|
+
it 'should return value with no arg' do
|
48
|
+
@person.sex.should == 1
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should return enum id for value' do
|
52
|
+
@person.sex(:id).should == 1
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return enum name for value' do
|
56
|
+
@person.sex(:name).should == 'Male'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return enum class for attribute' do
|
60
|
+
@person.sex(:enum).should == Sex
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "nil attribute value" do
|
65
|
+
before do
|
66
|
+
@person.sex = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return nil with no arg' do
|
70
|
+
@person.sex.should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return nil enum id' do
|
74
|
+
@person.sex(:id).should be_nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should return nil enum name' do
|
78
|
+
@person.sex(:name).should be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return enum class for attribute' do
|
82
|
+
@person.sex(:enum).should == Sex
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "attribute with undefined value" do
|
87
|
+
before do
|
88
|
+
@person.sex = -1
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should return value with no arg' do
|
92
|
+
@person.sex.should == -1
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should return nil enum id' do
|
96
|
+
@person.sex(:id).should be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should return nil enum name' do
|
100
|
+
@person.sex(:name).should be_nil
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should return enum class for attribute' do
|
104
|
+
@person.sex(:enum).should == Sex
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "attribute question method" do
|
109
|
+
before do
|
110
|
+
@person.sex = 1
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should return normal value without arg' do
|
114
|
+
@person.sex?.should be_true
|
115
|
+
@person.sex = nil
|
116
|
+
@person.sex?.should be_false
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should return true if string name matches for id value' do
|
120
|
+
@person.sex?("Male").should be_true
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should return true if symbol name matches for id value' do
|
124
|
+
@person.sex?(:male).should be_true
|
125
|
+
@person.sex?(:Male).should be_true
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should return false if name does not match for id value' do
|
129
|
+
@person.sex?("Female").should be_false
|
130
|
+
@person.sex?(:female).should be_false
|
131
|
+
@person.sex?(:Female).should be_false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "assigning enum name symbol to attribute" do
|
136
|
+
|
137
|
+
it 'should store id value when valid enum name' do
|
138
|
+
@person.sex = :female
|
139
|
+
@person.sex.should == 2
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should store nil value when invalid enum name' do
|
143
|
+
@person.sex = :invalid
|
144
|
+
@person.sex.should == nil
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "use enum name as attribute value" do
|
150
|
+
before(:all) do
|
151
|
+
ActiveEnum.use_name_as_value = true
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should return text name value for attribute' do
|
155
|
+
@person.sex.should == 'Male'
|
156
|
+
end
|
157
|
+
|
158
|
+
after(:all) do
|
159
|
+
ActiveEnum.use_name_as_value = false
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Bulk enum definitions" do
|
4
|
+
|
5
|
+
it 'define enum constants using block' do
|
6
|
+
ActiveEnum.define do
|
7
|
+
enum(:foo) do
|
8
|
+
value :id => 1, :name => 'Foo 1'
|
9
|
+
end
|
10
|
+
|
11
|
+
enum(:bar) do
|
12
|
+
value :id => 1, :name => 'Bar 1'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Foo.all.should == [[1,'Foo 1']]
|
17
|
+
Bar.all.should == [[1,'Bar 1']]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/spec/schema.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'spec'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
require 'active_record'
|
8
|
+
require 'active_enum'
|
9
|
+
|
10
|
+
RAILS_ROOT = File.dirname(__FILE__)
|
11
|
+
|
12
|
+
ActiveRecord::Migration.verbose = false
|
13
|
+
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'})
|
14
|
+
|
15
|
+
require 'schema'
|
16
|
+
|
17
|
+
class Person < ActiveRecord::Base; end
|
18
|
+
|
19
|
+
module SpecHelper
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
Spec::Runner.configure do |config|
|
24
|
+
config.include SpecHelper
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_enum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Meehan
|
8
|
+
autorequire: active_enum
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-05 00:00:00 +11:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Define enum classes in Rails and use them to enumerate ActiveRecord attributes
|
17
|
+
email: adam.meehan@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README.rdoc
|
27
|
+
- Rakefile
|
28
|
+
- lib/active_enum.rb
|
29
|
+
- lib/active_enum/base.rb
|
30
|
+
- lib/active_enum/version.rb
|
31
|
+
- lib/active_enum/extensions.rb
|
32
|
+
- lib/active_enum/acts_as_enum.rb
|
33
|
+
- spec/schema.rb
|
34
|
+
- spec/active_enum_spec.rb
|
35
|
+
- spec/spec_helper.rb
|
36
|
+
- spec/active_enum/acts_as_enum_spec.rb
|
37
|
+
- spec/active_enum/extensions_spec.rb
|
38
|
+
- spec/active_enum/base_spec.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/adzap/active_enum
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: active_enum
|
63
|
+
rubygems_version: 1.3.4
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Define enum classes in Rails and use them to enumerate ActiveRecord attributes
|
67
|
+
test_files: []
|
68
|
+
|