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 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