attr_enumerator 0.4.1 → 0.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/README.rdoc +28 -32
- data/VERSION +1 -1
- data/attr_enumerator.gemspec +2 -2
- data/lib/attr_enumerator.rb +9 -17
- data/spec/attr_enumerator_spec.rb +71 -93
- data/spec/spec_helper.rb +0 -5
- data/watchr.rb +2 -0
- metadata +5 -5
data/README.rdoc
CHANGED
@@ -4,10 +4,10 @@ A method for restricting an attribute to a set of choices.
|
|
4
4
|
|
5
5
|
An invocation of <tt>attr_enumerator</tt> will create:
|
6
6
|
|
7
|
-
*
|
8
|
-
*
|
9
|
-
* <b>
|
10
|
-
* <b>
|
7
|
+
* a <b>class constant</b> containing all valid choices
|
8
|
+
* a <b>validation</b> requiring the attribute's value to be one of the choices
|
9
|
+
* <b>instance methods</b> for each choice, returning <tt>true</tt> if the attribute is that value and <tt>false</tt> otherwise
|
10
|
+
* <b>scopes</b> for each choice that retrieve records where the attribute is that value
|
11
11
|
|
12
12
|
== Example
|
13
13
|
|
@@ -15,26 +15,30 @@ An invocation of <tt>attr_enumerator</tt> will create:
|
|
15
15
|
attr_enumerator :color, ['red', 'blue']
|
16
16
|
end
|
17
17
|
|
18
|
+
# constant
|
19
|
+
Car::COLORS # => ['red', 'blue']
|
20
|
+
|
21
|
+
# validation
|
18
22
|
car = Car.new
|
23
|
+
car.color = 'green'
|
24
|
+
car.valid? # => false
|
25
|
+
car.errors # => {:color => ["is invalid"]}
|
19
26
|
car.color = 'red'
|
27
|
+
car.valid? # => true
|
20
28
|
|
21
|
-
|
22
|
-
car.
|
23
|
-
|
24
|
-
Car::COLORS # => ['red', 'blue']
|
29
|
+
# instance methods
|
30
|
+
car.red? # => true
|
31
|
+
car.blue? # => false
|
25
32
|
|
33
|
+
# scopes
|
26
34
|
car.save
|
27
|
-
Car.
|
28
|
-
|
29
|
-
car.color = 'green'
|
30
|
-
car.valid? # => false
|
31
|
-
car.errors # => #<OrderedHash {:color=>["is invalid"]}>
|
35
|
+
Car.red # => [<#Car>]
|
32
36
|
|
33
37
|
== With or without ActiveRecord
|
34
38
|
|
35
|
-
The <tt>AttrEnumerator</tt> module
|
39
|
+
The <tt>AttrEnumerator</tt> module will be automatically included in <tt>ActiveRecord::Base</tt>, making the <tt>attr_enumerator</tt> method available in all ActiveRecord models.
|
36
40
|
|
37
|
-
To
|
41
|
+
To include <tt>AttrEnumerator</tt> on a non-ActiveRecord model the class must also include <tt>ActiveModel::Validations</tt> and provide an accessor to the attribute. The model will have all the above functionality except no scopes will be generated.
|
38
42
|
|
39
43
|
class Car
|
40
44
|
include ActiveModel::Validations
|
@@ -46,17 +50,17 @@ To use <tt>attr_enumerator</tt> on a non-ActiveRecord model the class must inclu
|
|
46
50
|
|
47
51
|
== Configuration
|
48
52
|
|
49
|
-
|
53
|
+
Options may be passed as the last argument to <tt>attr_enumerator</tt> to configure its behavior. For example:
|
50
54
|
|
51
55
|
class Car < ActiveRecord::Base
|
52
|
-
attr_enumerator :color, ['red', 'blue'], :constant => :PAINT_COLORS, :prefix => :
|
56
|
+
attr_enumerator :color, ['red', 'blue'], :constant => :PAINT_COLORS, :prefix => :painted
|
53
57
|
end
|
54
58
|
|
55
|
-
Car::PAINT_COLORS
|
59
|
+
Car::PAINT_COLORS # => ['red', 'blue']
|
56
60
|
|
57
61
|
car = Car.new
|
58
62
|
car.color = 'red'
|
59
|
-
car.
|
63
|
+
car.painted_red? # => true
|
60
64
|
|
61
65
|
=== Options
|
62
66
|
|
@@ -64,30 +68,22 @@ An options hash may be passed as the last argument to <tt>attr_enumerator</tt> t
|
|
64
68
|
|
65
69
|
Set a custom constant name.
|
66
70
|
|
67
|
-
* <tt>prefix</tt> (default:
|
71
|
+
* <tt>prefix</tt> (default: <tt>nil</tt>)
|
68
72
|
|
69
|
-
Set a
|
73
|
+
Set a prefix for generated methods and scopes.
|
70
74
|
|
71
75
|
* <tt>message</tt> (default: internationalized <tt>"is invalid"</tt>)
|
72
76
|
|
73
77
|
Set the validation error message when the attribute is not a valid value. Use <tt>%{value}</tt> to refer to the value of the attribute, e.g. <tt>"%{value} is not a valid choice"</tt>.
|
74
78
|
|
75
|
-
* <tt>allow_nil</tt> (default: <tt>false</tt>)
|
79
|
+
* <tt>allow_nil</tt> / <tt>allow_blank</tt> (default: <tt>false</tt>)
|
76
80
|
|
77
|
-
|
81
|
+
Do not fail validation when the attribute is <tt>nil</tt> or blank.
|
78
82
|
|
79
|
-
* <tt>
|
80
|
-
|
81
|
-
Allow the attribute to be blank.
|
82
|
-
|
83
|
-
* <tt>if</tt> (default: unused)
|
83
|
+
* <tt>if</tt> / <tt>unless</tt> (default: unused)
|
84
84
|
|
85
85
|
Set a method, proc or string to call to determine if the validation should occur. See <tt>ActiveModel::Validations</tt> for more details.
|
86
86
|
|
87
|
-
* <tt>unless</tt> (default: unused)
|
88
|
-
|
89
|
-
Set a method, proc or string to call to determine if the validation should <em>not</em> occur.
|
90
|
-
|
91
87
|
== Contributing to attr_enumerator
|
92
88
|
|
93
89
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/attr_enumerator.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{attr_enumerator}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Chris Baker"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-07-07}
|
13
13
|
s.description = %q{A method for restricting an attribute to a set of choices}
|
14
14
|
s.email = %q{baker.chris.3@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/attr_enumerator.rb
CHANGED
@@ -5,27 +5,19 @@ module AttrEnumerator
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
def attr_enumerator(
|
9
|
-
constant = options.delete(:constant) ||
|
8
|
+
def attr_enumerator(attribute, choices, options = {})
|
9
|
+
constant = options.delete(:constant) || attribute.to_s.pluralize.upcase
|
10
|
+
prefix = options[:prefix] ? options.delete(:prefix).to_s + '_' : ''
|
11
|
+
options[:message] ||= :invalid
|
12
|
+
|
10
13
|
const_set(constant, choices).freeze
|
11
|
-
|
12
|
-
raw_prefix = options.delete(:prefix)
|
13
|
-
|
14
|
-
prefix = case raw_prefix
|
15
|
-
when false, '' then ''
|
16
|
-
when nil then field.to_s + '_'
|
17
|
-
else raw_prefix.to_s + '_'
|
18
|
-
end
|
14
|
+
validates_inclusion_of attribute, options.merge(:in => choices)
|
19
15
|
|
20
16
|
choices.each do |choice|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
scope formatted_choice, where(field => choice) if self.respond_to? :scope
|
17
|
+
choice_string = prefix + choice.to_s.underscore.parameterize('_')
|
18
|
+
define_method(choice_string + '?') { send(attribute) == choice }
|
19
|
+
scope choice_string, where(attribute => choice) if respond_to? :scope
|
25
20
|
end
|
26
|
-
|
27
|
-
options[:message] ||= :invalid
|
28
|
-
validates field, :inclusion => options.merge(:in => choices)
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
@@ -1,119 +1,110 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "AttrEnumerator" do
|
4
|
-
|
5
|
-
|
6
|
-
def instance
|
7
|
-
@instance ||= subject.new
|
8
|
-
end
|
9
|
-
|
10
|
-
after(:each) do
|
11
|
-
begin
|
12
|
-
Object.send(:remove_const, :TestModel)
|
13
|
-
rescue NameError
|
14
|
-
end
|
15
|
-
end
|
4
|
+
let(:car) { Car.new }
|
16
5
|
|
17
6
|
context "without ActiveRecord" do
|
18
7
|
before(:each) do
|
19
|
-
class
|
8
|
+
class Car
|
20
9
|
include ActiveModel::Validations
|
21
10
|
include AttrEnumerator
|
22
|
-
attr_accessor :
|
11
|
+
attr_accessor :color
|
23
12
|
end
|
24
13
|
end
|
14
|
+
|
15
|
+
after(:each) { Object.send(:remove_const, :Car) }
|
25
16
|
|
26
17
|
context "validation" do
|
27
18
|
it "should pass when the value is one of the choices" do
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
20
|
+
car.color = 'blue'
|
21
|
+
car.should be_valid
|
31
22
|
end
|
32
23
|
|
33
24
|
it "should fail when the value is not one of the choices" do
|
34
|
-
|
35
|
-
|
36
|
-
|
25
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
26
|
+
car.color = 'green'
|
27
|
+
car.should_not be_valid
|
37
28
|
end
|
38
29
|
|
39
30
|
it "should have a default message" do
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
32
|
+
car.valid?
|
33
|
+
car.errors.should == {:color => ['is invalid']}
|
43
34
|
end
|
44
35
|
|
45
36
|
it "should allow for a custom message" do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
37
|
+
Car.attr_enumerator :color, ['red', 'blue'], :message => '%{value} is not a valid color'
|
38
|
+
car.color = 'green'
|
39
|
+
car.valid?
|
40
|
+
car.errors.should == {:color => ['green is not a valid color']}
|
50
41
|
end
|
51
42
|
|
52
43
|
it "should handle allow_blank" do
|
53
|
-
|
44
|
+
Car.attr_enumerator :color, ['red', 'blue'], :allow_blank => true
|
54
45
|
|
55
|
-
|
56
|
-
|
46
|
+
car.color = nil
|
47
|
+
car.should be_valid
|
57
48
|
|
58
|
-
|
59
|
-
|
49
|
+
car.color = ''
|
50
|
+
car.should be_valid
|
60
51
|
end
|
61
52
|
|
62
53
|
it "should handle allow_nil" do
|
63
|
-
|
54
|
+
Car.attr_enumerator :color, ['red', 'blue'], :allow_nil => true
|
64
55
|
|
65
|
-
|
66
|
-
|
56
|
+
car.color = nil
|
57
|
+
car.should be_valid
|
67
58
|
|
68
|
-
|
69
|
-
|
59
|
+
car.color = ''
|
60
|
+
car.should_not be_valid
|
70
61
|
end
|
71
62
|
|
72
|
-
it "should handle symbol
|
73
|
-
|
63
|
+
it "should handle symbol choices distinctively from strings" do
|
64
|
+
Car.attr_enumerator :color, [:red, :blue]
|
74
65
|
|
75
|
-
|
76
|
-
|
77
|
-
|
66
|
+
car.color = :red
|
67
|
+
car.should be_valid
|
68
|
+
car.should be_red
|
78
69
|
|
79
|
-
|
80
|
-
|
81
|
-
|
70
|
+
car.color = 'red'
|
71
|
+
car.should_not be_valid
|
72
|
+
car.should_not be_red
|
82
73
|
end
|
83
74
|
end
|
84
75
|
|
85
76
|
context "class constant" do
|
86
|
-
it "should create a constant
|
87
|
-
|
88
|
-
|
77
|
+
it "should create a constant" do
|
78
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
79
|
+
Car::COLORS.should == ['red', 'blue']
|
89
80
|
end
|
90
81
|
|
91
|
-
it "should freeze the constant
|
92
|
-
|
93
|
-
|
82
|
+
it "should freeze the constant" do
|
83
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
84
|
+
Car::COLORS.should be_frozen
|
94
85
|
end
|
95
86
|
|
96
87
|
it "should allow for a custom constant name using a symbol" do
|
97
|
-
|
98
|
-
|
88
|
+
Car.attr_enumerator :color, ['red', 'blue'], :constant => :POSSIBLE_COLORS
|
89
|
+
Car::POSSIBLE_COLORS.should == ['red', 'blue']
|
99
90
|
end
|
100
91
|
|
101
92
|
it "should allow for a custom constant name using a string" do
|
102
|
-
|
103
|
-
|
93
|
+
Car.attr_enumerator :color, ['red', 'blue'], :constant => 'POSSIBLE_COLORS'
|
94
|
+
Car::POSSIBLE_COLORS.should == ['red', 'blue']
|
104
95
|
end
|
105
96
|
end
|
106
97
|
|
107
98
|
context "methods" do
|
108
|
-
it "should create methods for each
|
109
|
-
|
110
|
-
|
99
|
+
it "should create methods for each choice" do
|
100
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
101
|
+
car.color = 'red'
|
111
102
|
|
112
|
-
|
113
|
-
|
103
|
+
car.should respond_to :red?
|
104
|
+
car.should be_red
|
114
105
|
|
115
|
-
|
116
|
-
|
106
|
+
car.should respond_to :blue?
|
107
|
+
car.should_not be_blue
|
117
108
|
end
|
118
109
|
|
119
110
|
it "should create methods with friendly names" do
|
@@ -126,43 +117,35 @@ describe "AttrEnumerator" do
|
|
126
117
|
:ends_with_dot? => 'ends.with.dot.'
|
127
118
|
}
|
128
119
|
|
129
|
-
|
120
|
+
Car.attr_enumerator :color, enumerations.values
|
130
121
|
|
131
122
|
enumerations.keys.each do |method_name|
|
132
|
-
|
123
|
+
car.should respond_to method_name
|
133
124
|
end
|
134
125
|
end
|
135
126
|
|
136
127
|
it "should allow for a custom prefix" do
|
137
|
-
|
138
|
-
|
128
|
+
Car.attr_enumerator :color, ['red', 'blue'], :prefix => 'painted'
|
129
|
+
car.color = 'red'
|
139
130
|
|
140
|
-
|
141
|
-
|
131
|
+
car.should respond_to :painted_red?
|
132
|
+
car.should be_painted_red
|
142
133
|
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
it "should allow for no prefix" do
|
148
|
-
subject.attr_enumerator :choice, ['red', 'blue'], :prefix => false
|
149
|
-
instance.choice = 'red'
|
150
|
-
|
151
|
-
instance.should respond_to :red?
|
152
|
-
instance.should be_red
|
153
|
-
|
154
|
-
instance.should respond_to :blue?
|
155
|
-
instance.should_not be_blue
|
134
|
+
car.should respond_to :painted_blue?
|
135
|
+
car.should_not be_painted_blue
|
156
136
|
end
|
157
137
|
end
|
158
138
|
end
|
159
139
|
|
160
140
|
context "with ActiveRecord" do
|
161
141
|
before(:each) do
|
162
|
-
class
|
163
|
-
|
142
|
+
class Car < ActiveRecord::Base
|
143
|
+
establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
144
|
+
attr_accessor :color
|
164
145
|
end
|
165
146
|
end
|
147
|
+
|
148
|
+
after(:each) { Object.send(:remove_const, :Car) }
|
166
149
|
|
167
150
|
it "should automatically be included in ActiveRecord::Base" do
|
168
151
|
ActiveRecord::Base.should respond_to :attr_enumerator
|
@@ -170,18 +153,13 @@ describe "AttrEnumerator" do
|
|
170
153
|
|
171
154
|
describe "scopes" do
|
172
155
|
it "should create a scope for each enumeration" do
|
173
|
-
|
174
|
-
|
175
|
-
end
|
176
|
-
|
177
|
-
it "should create a scope for each enumeration with custom prefix " do
|
178
|
-
subject.attr_enumerator :choice, ['red', 'blue'], :prefix => 'colored'
|
179
|
-
subject.colored_red.should be_a ActiveRecord::Relation
|
156
|
+
Car.attr_enumerator :color, ['red', 'blue']
|
157
|
+
Car.red.should be_a ActiveRecord::Relation
|
180
158
|
end
|
181
159
|
|
182
|
-
it "should
|
183
|
-
|
184
|
-
|
160
|
+
it "should allow for scopes with a custom prefix" do
|
161
|
+
Car.attr_enumerator :color, ['red', 'blue'], :prefix => 'painted'
|
162
|
+
Car.painted_red.should be_a ActiveRecord::Relation
|
185
163
|
end
|
186
164
|
end
|
187
165
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,2 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'attr_enumerator'
|
3
|
-
|
4
|
-
class ActiveRecordModel < ActiveRecord::Base
|
5
|
-
establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
6
|
-
connection.execute("CREATE TABLE #{table_name} (#{primary_key} integer PRIMARY KEY AUTOINCREMENT)")
|
7
|
-
end
|
data/watchr.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attr_enumerator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chris Baker
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-07-07 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|