enumerated_state 0.0.4 → 0.0.7
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 +50 -6
- data/lib/enumerated_state.rb +22 -18
- data/spec/enumerated_state_spec.rb +26 -0
- metadata +15 -4
data/README.rdoc
CHANGED
@@ -15,11 +15,13 @@ Use
|
|
15
15
|
|
16
16
|
== Description
|
17
17
|
|
18
|
-
This gem belongs to the ASPIUM family of gems -- (Another State Pattern
|
18
|
+
This gem belongs to the ASPIUM family of gems -- (Another State Pattern Implemented
|
19
19
|
Using Mixology). This ASPIUM adds state pattern support to enumerated attributes (see enumerated_attribute[http://github.com/jeffp/enumerated_attribute])
|
20
20
|
and allows multiple state variables per object, one for each enumerated attribute.
|
21
21
|
|
22
|
-
==
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
=== Basic implementation
|
23
25
|
|
24
26
|
If you are using enumerated_attribute, you may have code looking something like
|
25
27
|
|
@@ -34,7 +36,7 @@ If you are using enumerated_attribute, you may have code looking something like
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
|
39
|
+
We can clean this up a little by using acts_as_enumerated_state like this
|
38
40
|
|
39
41
|
class Tractor
|
40
42
|
enum_attr :gear, %w(reverse ^neutral first)
|
@@ -53,13 +55,15 @@ Enumerated State lets you clean it up as so
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
|
58
|
+
=== Multi-variable state and enum value conflicts
|
57
59
|
|
58
|
-
|
60
|
+
If your attributes share some enum values with the same name, there will be confusion as to which
|
61
|
+
module belongs to which enumeration. You can clear up the collision by using the
|
62
|
+
:module option like this
|
59
63
|
|
60
64
|
class Foobar
|
61
65
|
enum_attr :alpha, %w(state1 state2)
|
62
|
-
enum_attr :beta, %w(state1 state2 state3) # names will
|
66
|
+
enum_attr :beta, %w(state1 state2 state3) # names will collide when mapped to modules
|
63
67
|
|
64
68
|
acts_as_enumerated_state :alpha
|
65
69
|
acts_as_enumerated_state :beta, :module=>'Beta'
|
@@ -74,6 +78,46 @@ Use the :module option to avoid naming conflicts between enumerated attributes
|
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
81
|
+
=== Strict versus non-strict
|
82
|
+
|
83
|
+
By default, acts_as_enumerated_state assigns one module for each enumeration and fails
|
84
|
+
when it cannot find the module. For example, the following code causes an error
|
85
|
+
|
86
|
+
class Tractor
|
87
|
+
enum_attr :gear, %w(reverse neutral first)
|
88
|
+
acts_as_enumerated_state :gear
|
89
|
+
|
90
|
+
module Reverse ... end
|
91
|
+
# where's the module for :neutral?
|
92
|
+
module First ... end
|
93
|
+
end
|
94
|
+
|
95
|
+
Tractor.new.gear = :neutral #error because there's no module
|
96
|
+
|
97
|
+
But sometimes you may not need a module for each enumeration. You may want some enumerations
|
98
|
+
to use a method defined by the object itself. You can back off the strictness
|
99
|
+
by setting the :strict option to false like this
|
100
|
+
|
101
|
+
class Tractor
|
102
|
+
enum_attr :gear, %w(reverse neutral first)
|
103
|
+
acts_as_enumerated_state :gear, :strict=>false
|
104
|
+
|
105
|
+
def motion; 'stopped'; end
|
106
|
+
|
107
|
+
module Reverse
|
108
|
+
def motion; 'backwards'; end
|
109
|
+
end
|
110
|
+
# no neutral module needed
|
111
|
+
module First
|
112
|
+
def motion; 'forwards'; end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
t = Tractor.new
|
117
|
+
t.gear = :neutral
|
118
|
+
t.motion # calls motion on the object and returns 'stopped'
|
119
|
+
|
120
|
+
|
77
121
|
== Dependencies
|
78
122
|
|
79
123
|
* meta_programming
|
data/lib/enumerated_state.rb
CHANGED
@@ -11,41 +11,45 @@ module EnumeratedState
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class Class
|
14
|
-
|
15
14
|
def acts_as_enumerated_state(enum_attr, opts={})
|
16
15
|
enum_attr = enum_attr.to_sym
|
17
16
|
unless (self.respond_to?(:has_enumerated_attribute?) && self.has_enumerated_attribute?(enum_attr))
|
18
17
|
raise ArgumentError, "enumerated attribute :#{enum_attr} not defined"
|
19
18
|
end
|
20
19
|
|
21
|
-
self.extend EnumeratedStateClassMethods
|
22
|
-
self.set_enumerated_state_property(enum_attr, :module_prefix, opts[:module] ? "#{opts[:module]}::" : '')
|
23
|
-
self.set_enumerated_state_property(enum_attr, :strict, opts[:strict] == false ? false : true)
|
24
|
-
|
25
20
|
if self.method_defined?("write_enumerated_attribute_without_#{enum_attr}")
|
26
21
|
raise EnumeratedState::RedefinitionError, "Enumerated state already defined for :#{enum_attr}"
|
27
22
|
end
|
28
23
|
|
24
|
+
self.extend EnumeratedStateClassMethods # unless self.has_module?(EnumeratedStateClassMethods)
|
25
|
+
self.set_enumerated_state_property(enum_attr, :module_prefix, opts[:module] ? "#{opts[:module]}::" : '')
|
26
|
+
self.set_enumerated_state_property(enum_attr, :strict, opts[:strict] == false ? false : true)
|
27
|
+
|
29
28
|
define_chained_method(:write_enumerated_attribute, enum_attr) do |attribute, value|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
without_method = "write_enumerated_attribute_without_#{enum_attr}".to_sym
|
30
|
+
|
31
|
+
unless enum_attr == attribute.to_sym
|
32
|
+
self.__send__(without_method, attribute, value)
|
33
|
+
else
|
34
|
+
old_value = self.read_enumerated_attribute(enum_attr)
|
35
|
+
result = self.__send__(without_method, attribute, value)
|
36
|
+
|
37
|
+
unless value == old_value
|
38
|
+
unless old_value.nil?
|
39
|
+
_module = self.class.get_module_for_enumerated_state(attribute, old_value)
|
40
|
+
self.unmix(_module) if _module
|
41
|
+
end
|
42
|
+
unless value.nil?
|
43
|
+
_module = self.class.get_module_for_enumerated_state(attribute, value)
|
44
|
+
self.mixin(_module) if _module
|
45
|
+
end
|
34
46
|
end
|
35
|
-
|
36
|
-
self.__send__("write_enumerated_attribute_without_#{enum_attr}".to_sym, attribute, value)
|
37
|
-
if (enum_attr == attribute.to_sym && !value.nil?)
|
38
|
-
_module = self.class.get_module_for_enumerated_state(attribute, value)
|
39
|
-
self.mixin(_module) if _module
|
47
|
+
result
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
43
51
|
alias_method :enumerated_state_pattern, :acts_as_enumerated_state
|
44
52
|
|
45
|
-
module EnumeratedStateHelpers
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
53
|
module EnumeratedStateClassMethods
|
50
54
|
def get_module_for_enumerated_state(attribute, value)
|
51
55
|
value = value.to_sym unless value.nil?
|
@@ -411,6 +411,32 @@ describe 'Enumerated State' do
|
|
411
411
|
end
|
412
412
|
end
|
413
413
|
|
414
|
+
describe "implementation with double states does not cause error" do
|
415
|
+
it "should not raise error" do
|
416
|
+
lambda {
|
417
|
+
class Impl30
|
418
|
+
enum_attr :enum1, %w(e1 e2)
|
419
|
+
acts_as_enumerated_state :enum1
|
420
|
+
|
421
|
+
enum_attr :enum2, %w(e3 e4)
|
422
|
+
acts_as_enumerated_state :enum2
|
423
|
+
|
424
|
+
module E1; def hi; 'hi e1'; end; end
|
425
|
+
module E2; def hi; 'hi e2'; end; end
|
426
|
+
module E3; def hello; 'hello e3'; end; end
|
427
|
+
module E4; def hello; 'hello e4'; end; end
|
428
|
+
end
|
429
|
+
|
430
|
+
obj = Impl30.new
|
431
|
+
obj.enum1 = :e1
|
432
|
+
obj.hi.should == 'hi e1'
|
433
|
+
obj.enum2 = :e3
|
434
|
+
obj.hello.should == 'hello e3'
|
435
|
+
}.should_not raise_exception
|
436
|
+
end
|
437
|
+
|
438
|
+
end
|
439
|
+
|
414
440
|
describe "implementation error checking" do
|
415
441
|
|
416
442
|
it "should raise exception when redeclaring enumerated states in subclass" do
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enumerated_state
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Jeff Patmon
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-05-
|
18
|
+
date: 2010-05-29 00:00:00 -07:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: enumerated_attribute
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
27
30
|
segments:
|
28
31
|
- 0
|
29
32
|
- 2
|
@@ -35,9 +38,11 @@ dependencies:
|
|
35
38
|
name: mixology
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 23
|
41
46
|
segments:
|
42
47
|
- 0
|
43
48
|
- 2
|
@@ -49,9 +54,11 @@ dependencies:
|
|
49
54
|
name: meta_programming
|
50
55
|
prerelease: false
|
51
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
52
58
|
requirements:
|
53
59
|
- - ">="
|
54
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 21
|
55
62
|
segments:
|
56
63
|
- 0
|
57
64
|
- 2
|
@@ -87,25 +94,29 @@ rdoc_options: []
|
|
87
94
|
require_paths:
|
88
95
|
- lib
|
89
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
90
98
|
requirements:
|
91
99
|
- - ">="
|
92
100
|
- !ruby/object:Gem::Version
|
101
|
+
hash: 57
|
93
102
|
segments:
|
94
103
|
- 1
|
95
104
|
- 8
|
96
105
|
- 7
|
97
106
|
version: 1.8.7
|
98
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
99
109
|
requirements:
|
100
110
|
- - ">="
|
101
111
|
- !ruby/object:Gem::Version
|
112
|
+
hash: 3
|
102
113
|
segments:
|
103
114
|
- 0
|
104
115
|
version: "0"
|
105
116
|
requirements: []
|
106
117
|
|
107
118
|
rubyforge_project:
|
108
|
-
rubygems_version: 1.3.
|
119
|
+
rubygems_version: 1.3.7
|
109
120
|
signing_key:
|
110
121
|
specification_version: 3
|
111
122
|
summary: ASPIUM (Another State Pattern Implementation Using Mixology)
|