mcommons-enum_for 0.0.3 → 0.0.4
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/README.rdoc +69 -29
- data/Rakefile +1 -1
- data/enum_for.gemspec +1 -1
- data/lib/enum_for.rb +5 -5
- data/spec/enum_for_spec.rb +73 -17
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -1,25 +1,16 @@
|
|
1
|
-
=
|
1
|
+
= enum_for
|
2
|
+
|
3
|
+
enum_for is an ActiveRecord extension enabling the easy use of enumerated types for your models.
|
4
|
+
|
5
|
+
== Description
|
2
6
|
|
3
7
|
enum_for makes your ActiveRecord-backed class work with an enumerable type. Instead of existing
|
4
8
|
ActiveRecord plugins such as enum_fu, which store the enumerable attribute as an integer, enum_for
|
5
9
|
stores the content of the enumerable attribute in a varchar column of the database.
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
enum_fu defines constants corresponding to each of the valid enumerable types on your model. For example,
|
12
|
-
if you have an enumerable column called "states" with valid states :starting and :finished, enum_fu would
|
13
|
-
define constants on your model Model::STATE_STARTING and Model::STATE_FINISHED with the contents of these
|
14
|
-
constants :starting and :finished respectively.
|
15
|
-
|
16
|
-
enum_fu also creates predicate methods on instances of your class so that you can ask if they have any
|
17
|
-
of the given enumerable states. For example, if a Taco class has an enumerable type :taste with values
|
18
|
-
:good and :bad, taco.good? would return a boolean value indicating whether or not the taste is good.
|
19
|
-
|
20
|
-
Finally, enum_fu creates named scopes on your model, so that you can easily find all records belonging to
|
21
|
-
a given enumerable type. Following the above example, Taco.taste_good would return all tacos that taste
|
22
|
-
good.
|
11
|
+
enum_for will also optionally create named scopes, predicate methods, and constants defining the
|
12
|
+
possible values for enumerable types on your model. By default, however, it avoids polluting your
|
13
|
+
model with things you may not need unless these features are specifically requested.
|
23
14
|
|
24
15
|
== Installation
|
25
16
|
|
@@ -29,34 +20,83 @@ enum_for is available as a gem available on GitHub. Install with:
|
|
29
20
|
|
30
21
|
You'll probable want a line like the following in your environment.rb:
|
31
22
|
|
32
|
-
config.gem
|
23
|
+
config.gem 'mcommons-enum_for', :lib => 'enum_for'
|
33
24
|
|
34
|
-
==
|
25
|
+
== Basic Usage
|
35
26
|
|
36
|
-
|
27
|
+
The following example sets up an enumerable attribute on an ActiveRecord model. This assumes that a previous
|
37
28
|
migration has created a column of type VARCHAR on the table "taco".
|
38
29
|
|
39
30
|
class Taco < ActiveRecord::Base
|
40
31
|
enum_for :state, :has => [ :new, :composed, :served, :eaten ]
|
41
32
|
end
|
42
|
-
|
43
|
-
To query all eaten tacos using the automatically-generated named scopes:
|
44
33
|
|
45
|
-
|
46
|
-
|
47
|
-
|
34
|
+
For all enum_for enabled models, valid states are able to be read for an attribute by calling the plural of
|
35
|
+
the attribute name:
|
36
|
+
|
37
|
+
>> Taco.states
|
38
|
+
=> [ :new, :composed, :served, :eaten ]
|
39
|
+
|
40
|
+
== Options
|
41
|
+
|
42
|
+
enum_for will optionally create named scopes, predicate methods, and constants defining values for
|
43
|
+
enumerable types on your model. These may be specified on a case-by-case basis by using the :adds
|
44
|
+
option. As an example, the following would create an enumerable attribute called "flavor" with the
|
45
|
+
possible values "sour" and "sweet", while creating named scopes, predicate methods, and constants on
|
46
|
+
your class:
|
47
|
+
|
48
|
+
enum_for :flavor, :has => [ :sour, :sweet ], :adds => [ :named_scopes, :predicate_methods, :constants ]
|
49
|
+
|
50
|
+
The different additive options are described below.
|
51
|
+
|
52
|
+
=== Named Scopes
|
53
|
+
|
54
|
+
The named_scopes option adds a named scope, with either the default or custom prefix, to your model.
|
55
|
+
For example, the following model definition would create a named_scope Taco.flavor_sour on your class:
|
48
56
|
|
49
|
-
Taco
|
57
|
+
class Taco < ActiveRecord::Base
|
58
|
+
enum_for :flavor, :has => [ :sour, :sweet ], :adds => :named_scopes
|
59
|
+
end
|
60
|
+
|
61
|
+
Afterwards, you may use the named scopes as follows. Remember to add the prefix!
|
62
|
+
|
63
|
+
Taco.flavor_sour
|
64
|
+
Taco.flavor_sweet
|
65
|
+
|
66
|
+
The prefix may be overridden or omitted by using the :prefix option.
|
67
|
+
|
68
|
+
== Predicate methods
|
69
|
+
|
70
|
+
enum_for also creates predicate methods on instances of your class so that you can ask if they have any
|
71
|
+
of the given enumerable states. For example, if a Taco class has an enumerable type :taste with values
|
72
|
+
:good and :bad, taco.good? would return a boolean value indicating whether or not the taste is good.
|
73
|
+
|
74
|
+
This option is only enabled when the additive option predicate_methods is specified.
|
75
|
+
|
76
|
+
=== Constants
|
77
|
+
|
78
|
+
enum_for optionally defines constants corresponding to each of the valid enumerable types on your model.
|
79
|
+
For example, if you have an enumerable column called "states" with valid states :starting and :finished,
|
80
|
+
enum_for would define constants on your model Model::STATE_STARTING and Model::STATE_FINISHED with the
|
81
|
+
contents of these constants :starting and :finished respectively. This is only enabled when the additive
|
82
|
+
option :constants is specified.
|
50
83
|
|
51
|
-
|
84
|
+
== Configuration
|
85
|
+
|
86
|
+
enum_for by default adds the attribute being modified as a prefix to constant declarations, named scopes,
|
87
|
+
and predicate methods. If you wish to modify this prefix, pass the :prefix option to enum_for. You may
|
88
|
+
also omit the addition of the prefix by passing :prefix => nil to enum_for. Example:
|
52
89
|
|
53
90
|
class Taco < ActiveRecord::Base
|
54
91
|
enum_for :state, :has => [ :new, :composed, :served, :eaten ], :prefix => 'wacky'
|
55
92
|
end
|
56
93
|
|
57
94
|
This makes Taco respond to named scopes like Taco.wacky_composed instead of the default, which
|
58
|
-
would have prefixed the named_scopes with the name of the attribute.
|
59
|
-
|
95
|
+
would have prefixed the named_scopes with the name of the attribute.
|
96
|
+
|
97
|
+
= TODO
|
98
|
+
|
99
|
+
* Add option for default value
|
60
100
|
|
61
101
|
== Authors
|
62
102
|
|
data/Rakefile
CHANGED
@@ -16,6 +16,6 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
16
16
|
rdoc.rdoc_dir = 'rdoc'
|
17
17
|
rdoc.title = 'Enum For'
|
18
18
|
rdoc.options << '--line-numbers' << '--inline-source'
|
19
|
-
rdoc.rdoc_files.include('README')
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
21
|
end
|
data/enum_for.gemspec
CHANGED
data/lib/enum_for.rb
CHANGED
@@ -14,6 +14,7 @@ module EnumFor
|
|
14
14
|
# to +enum_for+.
|
15
15
|
def enum_for(*args)
|
16
16
|
options = args.extract_options!
|
17
|
+
additives = options[:add].respond_to?(:each) ? options[:add] : ( options[:add].nil? ? [ ] : [ options[:add] ] )
|
17
18
|
attribute = args.first
|
18
19
|
|
19
20
|
plural_attribute = attribute.to_s.pluralize
|
@@ -22,7 +23,7 @@ module EnumFor
|
|
22
23
|
# so no need to accept only one form in the validation.
|
23
24
|
all_valid_values = options[:has].map{|v| v.to_s} | options[:has].map{|v| v.to_sym}
|
24
25
|
|
25
|
-
validates_inclusion_of attribute, options.except(:has, :prefix).merge(:in => all_valid_values )
|
26
|
+
validates_inclusion_of attribute, options.except(:has, :prefix, :add).merge(:in => all_valid_values )
|
26
27
|
const_set(plural_attribute.upcase, options[:has])
|
27
28
|
|
28
29
|
prefix = options.has_key?(:prefix) ? options[:prefix] : attribute.to_s
|
@@ -32,14 +33,13 @@ module EnumFor
|
|
32
33
|
end
|
33
34
|
|
34
35
|
prefixed_values.each do |pv, v|
|
35
|
-
|
36
|
-
const_set(pv.upcase, v)
|
36
|
+
const_set(pv.upcase, v) if additives.include?(:constants)
|
37
37
|
|
38
38
|
# Create named scope for this value
|
39
|
-
named_scope pv, :conditions => { attribute => v.to_s }
|
39
|
+
named_scope pv, :conditions => { attribute => v.to_s } if additives.include?(:named_scopes)
|
40
40
|
|
41
41
|
# Create predicate methods for values
|
42
|
-
|
42
|
+
if additives.include?(:predicate_methods) && !self.instance_methods.include?(pv)
|
43
43
|
define_method("#{pv}?") do
|
44
44
|
read_attribute(attribute) == v.to_s
|
45
45
|
end
|
data/spec/enum_for_spec.rb
CHANGED
@@ -18,15 +18,16 @@ ActiveRecord::Base.silence do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
class Taco < ActiveRecord::Base
|
22
|
-
enum_for :state, :has => [ :new, :composed, :served, :eaten ]
|
23
|
-
end
|
24
21
|
|
25
22
|
describe EnumFor do
|
26
23
|
before do
|
27
24
|
@taco = Taco.new(:state => 'new')
|
28
25
|
end
|
29
26
|
|
27
|
+
class Taco < ActiveRecord::Base
|
28
|
+
enum_for :state, :has => [ :new, :composed, :served, :eaten ]
|
29
|
+
end
|
30
|
+
|
30
31
|
describe "model validation" do
|
31
32
|
it "should make a valid model when given a valid state" do
|
32
33
|
@taco.should be_valid
|
@@ -57,22 +58,49 @@ describe EnumFor do
|
|
57
58
|
it "should return all possible states when plural of attribute is called as class method" do
|
58
59
|
Taco.states.should == [ :new, :composed, :served, :eaten ]
|
59
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "definition of constants for each attribute value" do
|
64
|
+
class WithoutConstants < ActiveRecord::Base
|
65
|
+
enum_for :state, :has => [ :new, :composed, :served, :eaten ]
|
66
|
+
end
|
67
|
+
|
68
|
+
class WithConstants < ActiveRecord::Base
|
69
|
+
enum_for :state, :has => [ :new, :composed, :served, :eaten ], :add => :constants
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be disabled by default" do
|
73
|
+
WithoutConstants.constants.should_not include('WithoutConstants::STATE_NEW')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should be enabled when added" do
|
77
|
+
WithConstants.constants.should_not include('WithoutConstants::STATE_NEW')
|
78
|
+
end
|
60
79
|
|
61
80
|
it "should define constants for each type" do
|
62
|
-
|
81
|
+
WithConstants::STATE_EATEN.should == :eaten
|
63
82
|
end
|
64
83
|
end
|
65
84
|
|
66
85
|
describe "definition of predicate methods" do
|
67
|
-
|
68
|
-
|
86
|
+
class WithPredicateMethods < ActiveRecord::Base
|
87
|
+
set_table_name "tacos"
|
88
|
+
enum_for :state, :has => [ :new, :composed, :served, :eaten ], :add => :predicate_methods
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not define predicate methods for each valid state by default" do
|
92
|
+
@taco.should_not respond_to(:state_eaten?)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should define predicate methods for each state when specified" do
|
96
|
+
WithPredicateMethods.new.should respond_to(:state_eaten?)
|
69
97
|
end
|
70
98
|
end
|
71
99
|
|
72
100
|
describe "with prefix option" do
|
73
101
|
class Food < ActiveRecord::Base
|
74
102
|
set_table_name "tacos"
|
75
|
-
enum_for :state, :has => [:stuff, :morestuff], :prefix => nil
|
103
|
+
enum_for :state, :has => [:stuff, :morestuff], :prefix => nil, :add => :predicate_methods
|
76
104
|
end
|
77
105
|
|
78
106
|
it "should not prefix predicate methods if asked not to" do
|
@@ -91,6 +119,21 @@ describe EnumFor do
|
|
91
119
|
end
|
92
120
|
end
|
93
121
|
|
122
|
+
describe "with an Array of additives" do
|
123
|
+
class BeefJerkey < ActiveRecord::Base
|
124
|
+
set_table_name "tacos"
|
125
|
+
enum_for :flavor, :has => [:sour, :spicy], :add => [:named_scopes, :predicate_methods]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should construct named scopes" do
|
129
|
+
BeefJerkey.should respond_to(:flavor_sour)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should construct predicate methods" do
|
133
|
+
BeefJerkey.new.should respond_to(:flavor_sour?)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
94
137
|
describe "behavior with existing methods of same name" do
|
95
138
|
class Balloon < ActiveRecord::Base
|
96
139
|
set_table_name "tacos"
|
@@ -122,19 +165,32 @@ describe EnumFor do
|
|
122
165
|
end
|
123
166
|
|
124
167
|
describe "named scope creation" do
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
3.times { Taco.create(:state => 'composed') }
|
168
|
+
describe "when not added" do
|
169
|
+
it "should not create named scopes" do
|
170
|
+
Taco.should_not respond_to(:state_composed)
|
171
|
+
end
|
130
172
|
end
|
131
173
|
|
132
|
-
|
133
|
-
|
134
|
-
|
174
|
+
describe "when added" do
|
175
|
+
class Tequila < ActiveRecord::Base
|
176
|
+
set_table_name "tacos"
|
177
|
+
enum_for :state, :has => [ :wormy, :delicious ], :add => :named_scopes
|
178
|
+
end
|
179
|
+
|
180
|
+
before do
|
181
|
+
Tequila.delete_all
|
182
|
+
|
183
|
+
2.times { Tequila.create(:state => 'wormy') }
|
184
|
+
3.times { Tequila.create(:state => 'delicious') }
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should have two wormy tequilas" do
|
188
|
+
Tequila.state_wormy.size.should == 2
|
189
|
+
end
|
135
190
|
|
136
|
-
|
137
|
-
|
191
|
+
it "should have two delicious tequilas" do
|
192
|
+
Tequila.state_delicious.size.should == 3
|
193
|
+
end
|
138
194
|
end
|
139
195
|
end
|
140
196
|
|