mcommons-enum_for 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,25 +1,16 @@
1
- = Enum For
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
- It also defines certain useful methods on your model. For example, if you declare :state to be
8
- an enumerable column, enum_fu allow you to see the valid states by calling the method "states"
9
- (note the automatically pluralized form) on the class.
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 "enum_for"
23
+ config.gem 'mcommons-enum_for', :lib => 'enum_for'
33
24
 
34
- == Examples
25
+ == Basic Usage
35
26
 
36
- Sets up a basic enumerable attribute on an ActiveRecord model. This assumes that a previous
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
- Taco.state_eaten
46
-
47
- To find out valid states on a model:
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.states
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
- To create an enumerable type on a model, overriding the default prefix given to named_scopes:
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. Note that this feature
59
- also allows for the prefix to be omitted entirely if the value 'nil' is given instead of a String.
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{enum_for}
3
- s.version = "0.0.3"
3
+ s.version = "0.0.4"
4
4
 
5
5
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
6
  s.authors = ["Mal McKay and Justin Leitgeb"]
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
- # Set constants for values
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
- unless self.instance_methods.include?(pv)
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
@@ -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
- Taco::STATE_EATEN.should == :eaten
81
+ WithConstants::STATE_EATEN.should == :eaten
63
82
  end
64
83
  end
65
84
 
66
85
  describe "definition of predicate methods" do
67
- it "should define predicate methods for each valid state" do
68
- @taco.should respond_to(:state_eaten?)
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
- before do
126
- Taco.delete_all
127
-
128
- 2.times { Taco.create(:state => 'new') }
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
- it "should have two new tacos" do
133
- Taco.state_new.size.should == 2
134
- end
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
- it "should have two composed tacos" do
137
- Taco.state_composed.size.should == 3
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
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcommons-enum_for
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mal McKay and Justin Leitgeb