degu 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/.gitignore +6 -0
- data/Gemfile +5 -0
- data/README.rdoc +150 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/degu.gemspec +44 -0
- data/lib/degu/has_enum.rb +79 -0
- data/lib/degu/has_set.rb +110 -0
- data/lib/degu/polite.rb +6 -0
- data/lib/degu/renum/enumerated_value.rb +226 -0
- data/lib/degu/renum/enumerated_value_type_factory.rb +61 -0
- data/lib/degu/renum.rb +17 -0
- data/lib/degu/rude.rb +12 -0
- data/lib/degu/version.rb +8 -0
- data/lib/degu.rb +3 -0
- data/spec/renum_spec.rb +281 -0
- data/spec/spec_helper.rb +3 -0
- data/test/has_enum_test.rb +184 -0
- data/test/has_set_test.rb +155 -0
- data/test/test_helper.rb +138 -0
- data/test_helper.rb +86 -0
- metadata +137 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'degu/renum/enumerated_value'
|
2
|
+
|
3
|
+
module Degu
|
4
|
+
module Renum
|
5
|
+
module EnumeratedValueTypeFactory
|
6
|
+
class << self
|
7
|
+
def create nest, type_name, values, &block
|
8
|
+
klass = create_class nest, type_name
|
9
|
+
create_values klass, values, &block
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_class nest, type_name
|
13
|
+
klass = Class.new EnumeratedValue
|
14
|
+
nest.const_set(type_name, klass)
|
15
|
+
klass
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_values klass, values, &block
|
19
|
+
setup_for_definition_in_block(klass) if values == :defined_in_block
|
20
|
+
klass.class_eval &block if block_given?
|
21
|
+
if values == :defined_in_block
|
22
|
+
begin
|
23
|
+
klass.block_defined_values.each do |value_name, init_args, instance_block|
|
24
|
+
value = klass.new(value_name)
|
25
|
+
klass.const_set(value_name, value)
|
26
|
+
value.instance_eval &instance_block if instance_block
|
27
|
+
value.init *init_args if value.respond_to? :init
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
teardown_from_definition_in_block(klass)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
values.each do |name|
|
34
|
+
klass.const_set(name, klass.new(name))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
klass.values.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_for_definition_in_block klass
|
41
|
+
klass.class_eval do
|
42
|
+
def self.block_defined_values
|
43
|
+
@block_defined_values ||= []
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.method_missing value_name, *init_args, &instance_block
|
47
|
+
block_defined_values << [value_name, init_args, instance_block]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def teardown_from_definition_in_block klass
|
53
|
+
class << klass
|
54
|
+
remove_method :block_defined_values
|
55
|
+
remove_method :method_missing
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/degu/renum.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'degu/renum/enumerated_value_type_factory'
|
2
|
+
|
3
|
+
module Degu
|
4
|
+
# Requiring 'renum' mixes the Renum module into both the main Object and
|
5
|
+
# Module, so it can be called from anywhere that you might reasonably
|
6
|
+
# define an enumeration with an implicit receiver.
|
7
|
+
module Renum
|
8
|
+
|
9
|
+
# Figures out whether the new enumeration will live in Object or the
|
10
|
+
# receiving Module, then delegates to EnumeratedValueTypeFactory#create for
|
11
|
+
# all the real work.
|
12
|
+
def enum(type_name, values = :defined_in_block, &block)
|
13
|
+
nest = self.is_a?(Module) ? self : Object
|
14
|
+
EnumeratedValueTypeFactory.create(nest, type_name, values, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/degu/rude.rb
ADDED
data/lib/degu/version.rb
ADDED
data/lib/degu.rb
ADDED
data/spec/renum_spec.rb
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
enum :Status, [ :NOT_STARTED, :IN_PROGRESS, :COMPLETE ]
|
4
|
+
|
5
|
+
enum :Fuzzy, [ :FooBar, :BarFoo ]
|
6
|
+
|
7
|
+
describe "basic enum" do
|
8
|
+
|
9
|
+
it "creates a class for the value type" do
|
10
|
+
Status.should be_an_instance_of(Class)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "makes each value an instance of the value type" do
|
14
|
+
Status::NOT_STARTED.should be_an_instance_of(Status)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "exposes array of values" do
|
18
|
+
Status.values.should == [Status::NOT_STARTED, Status::IN_PROGRESS, Status::COMPLETE]
|
19
|
+
Status.all.should == [Status::NOT_STARTED, Status::IN_PROGRESS, Status::COMPLETE]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "groks first and last to retreive value" do
|
23
|
+
Status.first.should == Status::NOT_STARTED
|
24
|
+
Status.last.should == Status::COMPLETE
|
25
|
+
end
|
26
|
+
|
27
|
+
it "enumerates over values" do
|
28
|
+
Status.map {|s| s.name}.should == %w[NOT_STARTED IN_PROGRESS COMPLETE]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "indexes values" do
|
32
|
+
Status[2].should == Status::COMPLETE
|
33
|
+
Color[0].should == Color::RED
|
34
|
+
Status['2'].should == Status::COMPLETE
|
35
|
+
Color['0'].should == Color::RED
|
36
|
+
end
|
37
|
+
|
38
|
+
it "provides index lookup on values" do
|
39
|
+
Status::IN_PROGRESS.index.should == 1
|
40
|
+
Color::GREEN.index.should == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
it "provides an id on values" do
|
44
|
+
Status::IN_PROGRESS.id.should == 1
|
45
|
+
Color::GREEN.id.should == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "provides name lookup on values" do
|
50
|
+
Status.with_name('IN_PROGRESS').should == Status::IN_PROGRESS
|
51
|
+
Color.with_name('GREEN').should == Color::GREEN
|
52
|
+
Color.with_name('IN_PROGRESS').should be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "provides fuzzy name lookup on values" do
|
56
|
+
Fuzzy[0].should == Fuzzy::FooBar
|
57
|
+
Fuzzy[1].should == Fuzzy::BarFoo
|
58
|
+
Fuzzy[:FooBar].should == Fuzzy::FooBar
|
59
|
+
Fuzzy[:BarFoo].should == Fuzzy::BarFoo
|
60
|
+
Fuzzy['FooBar'].should == Fuzzy::FooBar
|
61
|
+
Fuzzy['BarFoo'].should == Fuzzy::BarFoo
|
62
|
+
Fuzzy[:foo_bar].should == Fuzzy::FooBar
|
63
|
+
Fuzzy[:bar_foo].should == Fuzzy::BarFoo
|
64
|
+
Fuzzy['foo_bar'].should == Fuzzy::FooBar
|
65
|
+
Fuzzy['bar_foo'].should == Fuzzy::BarFoo
|
66
|
+
Fuzzy[Fuzzy::FooBar].should == Fuzzy::FooBar
|
67
|
+
Fuzzy[Fuzzy::BarFoo].should == Fuzzy::BarFoo
|
68
|
+
end
|
69
|
+
|
70
|
+
it "provides a reasonable to_s for values" do
|
71
|
+
Status::NOT_STARTED.to_s.should == "Status::NOT_STARTED"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "makes values comparable" do
|
75
|
+
Color::RED.should < Color::GREEN
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module MyNamespace
|
80
|
+
enum :FooValue, %w( Bar Baz Bat )
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "nested enum" do
|
84
|
+
it "is namespaced in the containing module or class" do
|
85
|
+
MyNamespace::FooValue::Bar.class.should == MyNamespace::FooValue
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
enum :Color, [ :RED, :GREEN, :BLUE ] do
|
90
|
+
def abbr
|
91
|
+
name[0..0]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "enum with a block" do
|
96
|
+
it "can define additional instance methods" do
|
97
|
+
Color::RED.abbr.should == "R"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
enum :Size do
|
102
|
+
Small("Really really tiny")
|
103
|
+
Medium("Sort of in the middle")
|
104
|
+
Large("Quite big")
|
105
|
+
Unknown()
|
106
|
+
|
107
|
+
attr_reader :description
|
108
|
+
|
109
|
+
def init description = nil
|
110
|
+
@description = description || "NO DESCRIPTION GIVEN"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
enum :HairColor do
|
115
|
+
BLONDE()
|
116
|
+
BRUNETTE()
|
117
|
+
RED()
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "enum with no values array and values declared in the block" do
|
121
|
+
it "provides another way to declare values where an init method can take extra params" do
|
122
|
+
Size::Small.description.should == "Really really tiny"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "works the same as the basic form with respect to ordering" do
|
126
|
+
Size.values.should == [Size::Small, Size::Medium, Size::Large, Size::Unknown]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "responds as expected to arbitrary method calls, in spite of using method_missing for value definition" do
|
130
|
+
lambda { Size.ExtraLarge() }.should raise_error(NoMethodError)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "supports there being no extra data and no init() method defined, if you don't need them" do
|
134
|
+
HairColor::BLONDE.name.should == "BLONDE"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "calls the init method even if no arguments are provided" do
|
138
|
+
Size::Unknown.description.should == "NO DESCRIPTION GIVEN"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
enum :Rating do
|
143
|
+
NotRated()
|
144
|
+
|
145
|
+
ThumbsDown do
|
146
|
+
def description
|
147
|
+
"real real bad"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
ThumbsUp do
|
152
|
+
def description
|
153
|
+
"so so good"
|
154
|
+
end
|
155
|
+
|
156
|
+
def thumbs_up_only_method
|
157
|
+
"this method is only defined on ThumbsUp"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def description
|
162
|
+
raise NotImplementedError
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "an enum with instance-specific method definitions" do
|
167
|
+
it "allows each instance to have its own behavior" do
|
168
|
+
Rating::ThumbsDown.description.should == "real real bad"
|
169
|
+
Rating::ThumbsUp.description.should == "so so good"
|
170
|
+
end
|
171
|
+
|
172
|
+
it "uses the implementation given at the top level if no alternate definition is given for an instance" do
|
173
|
+
lambda { Rating::NotRated.description }.should raise_error(NotImplementedError)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "allows definition of a method on just one instance" do
|
177
|
+
Rating::ThumbsUp.thumbs_up_only_method.should == "this method is only defined on ThumbsUp"
|
178
|
+
lambda { Rating::NotRated.thumbs_up_only_method }.should raise_error(NoMethodError)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "<=> comparison issue that at one time was causing segfaults on MRI" do
|
183
|
+
it "doesn't cause the ruby process to bomb!" do
|
184
|
+
Color::RED.should < Color::GREEN
|
185
|
+
Color::RED.should_not > Color::GREEN
|
186
|
+
Color::RED.should < Color::BLUE
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
modify_frozen_error =
|
191
|
+
begin
|
192
|
+
[].freeze << true
|
193
|
+
rescue => e
|
194
|
+
e.class
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "prevention of subtle and annoying bugs" do
|
198
|
+
it "prevents you modifying the values array" do
|
199
|
+
lambda { Color.values << 'some crazy value' }.should raise_error(modify_frozen_error, /can't modify frozen/)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "prevents you modifying the name hash" do
|
203
|
+
lambda { Color.values_by_name['MAGENTA'] = 'some crazy value' }.should raise_error(modify_frozen_error, /can't modify frozen/)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "prevents you modifying the name of a value" do
|
207
|
+
lambda { Color::RED.name << 'dish-Brown' }.should raise_error(modify_frozen_error, /can't modify frozen/)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
enum :Foo1 do
|
212
|
+
field :foo
|
213
|
+
field :bar, :default => 'my bar'
|
214
|
+
field :baz do |obj|
|
215
|
+
obj.__id__
|
216
|
+
end
|
217
|
+
|
218
|
+
Baz(
|
219
|
+
:foo => 'my foo'
|
220
|
+
)
|
221
|
+
end
|
222
|
+
|
223
|
+
enum :Foo2 do
|
224
|
+
field :foo
|
225
|
+
field :bar, :default => 'my bar'
|
226
|
+
field :baz do |obj|
|
227
|
+
obj.__id__
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
Baz(
|
232
|
+
:foo => 'my foo'
|
233
|
+
)
|
234
|
+
|
235
|
+
def init(opts = {})
|
236
|
+
super
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "use field method to specify methods and defaults" do
|
241
|
+
it "should define methods with defaults for fields" do
|
242
|
+
Foo1::Baz.foo.should == "my foo"
|
243
|
+
Foo2::Baz.foo.should == "my foo"
|
244
|
+
Foo1::Baz.bar.should == "my bar"
|
245
|
+
Foo2::Baz.bar.should == "my bar"
|
246
|
+
Foo1::Baz.baz.should == Foo1::Baz.__id__
|
247
|
+
Foo2::Baz.baz.should == Foo2::Baz.__id__
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe "serialize and deserialize via Marshal" do
|
252
|
+
it "should define methods with defaults for fields" do
|
253
|
+
Marshal.load(Marshal.dump(Status::NOT_STARTED)).should == Status::NOT_STARTED
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
if defined?(::JSON)
|
258
|
+
describe "serialize and deserialize via JSON" do
|
259
|
+
it "should define methods with defaults for fields" do
|
260
|
+
JSON(JSON(Status::NOT_STARTED)).should == Status::NOT_STARTED
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should not serialize fields by default" do
|
264
|
+
foo1_json = JSON(Foo1::Baz)
|
265
|
+
foo1_hash = JSON.parse(foo1_json, :create_additions => false)
|
266
|
+
foo1_hash.keys.sort.should == %w[name json_class].sort
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should serialize all fields if desired" do
|
270
|
+
foo1_json = Foo1::Baz.to_json(:fields => true)
|
271
|
+
foo1_hash = JSON.parse(foo1_json, :create_additions => false)
|
272
|
+
foo1_hash.keys.sort.should == %w[name json_class bar baz foo].sort
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should serialize requested fields" do
|
276
|
+
foo1_json = Foo1::Baz.to_json(:fields => [ :bar, 'baz' ])
|
277
|
+
foo1_hash = JSON.parse(foo1_json, :create_additions => false)
|
278
|
+
foo1_hash.keys.sort.should == %w[name json_class bar baz].sort
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class HasEnumTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
setup_db
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
teardown_db
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_have_enum
|
14
|
+
assert ClassWithEnum.respond_to?(:has_enum)
|
15
|
+
product_enum = ClassWithEnum.new(:product => Product::Silver)
|
16
|
+
assert_equal Product::Silver, product_enum.product
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_have_enum_column_value_set_to_enum_name
|
20
|
+
product_enum = ClassWithEnum.new
|
21
|
+
product_enum.product = Product::Gold
|
22
|
+
assert_equal Product::Gold.name, product_enum.product_type
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_be_nullable
|
26
|
+
product_enum = ClassWithEnum.new
|
27
|
+
product_enum.product = Product::Silver
|
28
|
+
product_enum.reset_enum_changed
|
29
|
+
assert_equal false, product_enum.product_has_changed?
|
30
|
+
product_enum.product = nil
|
31
|
+
assert_nil product_enum.product
|
32
|
+
assert_equal true, product_enum.product_has_changed?
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_be_nil_if_spaces_string
|
36
|
+
product_enum = ClassWithEnum.new
|
37
|
+
product_enum.product = Product::Silver
|
38
|
+
product_enum.reset_enum_changed
|
39
|
+
assert_equal false, product_enum.product_has_changed?
|
40
|
+
product_enum.product = " "
|
41
|
+
assert_nil product_enum.product
|
42
|
+
assert_equal true, product_enum.product_has_changed?
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_be_setable_by_string
|
46
|
+
product_enum = ClassWithEnum.new
|
47
|
+
product_enum.product = Product::Silver
|
48
|
+
product_enum.reset_enum_changed
|
49
|
+
assert_equal false, product_enum.product_has_changed?
|
50
|
+
product_enum.product = 'Gold'
|
51
|
+
assert_equal Product::Gold, product_enum.product
|
52
|
+
assert_equal true, product_enum.product_has_changed?
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_should_be_setable_by_symbol
|
56
|
+
product_enum = ClassWithEnum.new
|
57
|
+
product_enum.product = Product::Silver
|
58
|
+
product_enum.reset_enum_changed
|
59
|
+
assert_equal false, product_enum.product_has_changed?
|
60
|
+
product_enum.product = :gold
|
61
|
+
assert_equal Product::Gold, product_enum.product
|
62
|
+
assert_equal true, product_enum.product_has_changed?
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_be_setable_by_number
|
66
|
+
product_enum = ClassWithEnum.new
|
67
|
+
product_enum.product = Product::Silver
|
68
|
+
product_enum.reset_enum_changed
|
69
|
+
assert_equal false, product_enum.product_has_changed?
|
70
|
+
product_enum.product = 1
|
71
|
+
assert_equal Product::Gold, product_enum.product
|
72
|
+
assert_equal true, product_enum.product_has_changed?
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_accept_only_defined_enums
|
76
|
+
product_enum = ClassWithEnum.new
|
77
|
+
|
78
|
+
assert_raise(ArgumentError) { product_enum.product = Fakes::NOT_DEFINIED }
|
79
|
+
assert_raise(ArgumentError) { product_enum.product = "Product::Titanium" }
|
80
|
+
assert_raise(ArgumentError) { product_enum.product = Product }
|
81
|
+
assert_raise(ArgumentError) { product_enum.product = :symbol }
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_should_not_set_enum_in_setter_if_new_enum_is_equal_to_current_enum
|
85
|
+
product_enum = ClassWithEnum.new(:product => Product::Silver)
|
86
|
+
assert product_enum.product=Product::Gold
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_should_have_custom_column_name
|
90
|
+
enum_with_custom_column_name = ClassWithCustomNameEnum.new
|
91
|
+
enum_with_custom_column_name.product = Product::Gold
|
92
|
+
assert_equal Product::Gold, enum_with_custom_column_name.product
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_should_mark_enum_as_changed_if_enum_column_was_set_directly
|
96
|
+
product_enum = ClassWithEnum.new
|
97
|
+
assert !product_enum.product_has_changed?
|
98
|
+
product_enum.product_type = "Gold"
|
99
|
+
assert product_enum.product_has_changed?
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_should_only_change_enum_column_if_other_value_is_set
|
103
|
+
product_enum = ClassWithEnum.new
|
104
|
+
product_enum.product_type = "Gold"
|
105
|
+
product_enum.instance_variable_set("@enum_changed", false)
|
106
|
+
product_enum.product_type = "Gold"
|
107
|
+
assert !product_enum.product_has_changed?
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_should_have_custom_column_value_set_to_enum_name
|
111
|
+
enum_with_custom_column_name = ClassWithCustomNameEnum.new
|
112
|
+
enum_with_custom_column_name.product = Product::Gold
|
113
|
+
assert_equal Product::Gold.name, enum_with_custom_column_name.product_enum
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_should_raise_class_not_found_exception_if_enum_class_not_found
|
117
|
+
assert_raise(NameError) { ClassWithoutEnum.has_enum :foo }
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_should_raise_argument_error_if_enum_is_no_renum_enum
|
121
|
+
assert_raise(ArgumentError) { ClassWithoutEnum.has_enum :array }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_should_know_if_enum_has_changed
|
125
|
+
product_enum = ClassWithEnum.new(:product => Product::Silver)
|
126
|
+
assert product_enum.product_has_changed?
|
127
|
+
product_enum.save
|
128
|
+
product_enum.reload
|
129
|
+
product_enum.product = Product::Gold
|
130
|
+
assert product_enum.product_has_changed?
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_should_not_fail_if_no_enum_was_set_yet
|
134
|
+
enum_mixin = ClassWithEnum.new
|
135
|
+
assert_nothing_raised(TypeError) { enum_mixin.product }
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_should_not_change_if_same_enum_was_assigned
|
139
|
+
enum_mixin = ClassWithEnum.new(:product => Product::Silver)
|
140
|
+
enum_mixin.save
|
141
|
+
enum_mixin.reload
|
142
|
+
enum_mixin.product = Product::Silver
|
143
|
+
assert !enum_mixin.product_has_changed?
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_have_reset_changed_state_after_save
|
147
|
+
enum_mixin = ClassWithEnum.new(:product => Product::Silver)
|
148
|
+
enum_mixin.save
|
149
|
+
enum_mixin.reload
|
150
|
+
assert !enum_mixin.product_has_changed?
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_should_not_be_able_to_set_invalid_enum
|
154
|
+
enum_mixin = ClassWithEnum.new
|
155
|
+
assert_raise(NameError) { enum_mixin.product = Product::Platin }
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_should_not_be_able_to_set_invalid_enum_2
|
159
|
+
enum_mixin = ClassWithEnum.new
|
160
|
+
enum_mixin[:product_type] = "Platin"
|
161
|
+
enum_mixin.valid?
|
162
|
+
assert enum_mixin.errors[:product_type]
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_should_not_return_validation_error_if_enum_is_nil
|
166
|
+
enum_mixin = ClassWithEnum.new
|
167
|
+
enum_mixin.valid?
|
168
|
+
assert_equal [], enum_mixin.errors[:product_type]
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_should_return_nil_if_enum_is_of_wrong_type
|
172
|
+
enum_mixin = ClassWithEnum.new
|
173
|
+
enum_mixin[:product_type] = "Platin"
|
174
|
+
assert_nil enum_mixin.product
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_should_execute_all_callbacks
|
178
|
+
enum_mixin = ClassWithEnum.new
|
179
|
+
enum_mixin.product = Product::Gold
|
180
|
+
assert enum_mixin.save
|
181
|
+
assert enum_mixin.callback1_executed
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|