enumerated_state 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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 Implementation
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
- == Basic implementation
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
- Enumerated State lets you clean it up as so
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
- == Multi-variable state and enum value conflicts
58
+ === Multi-variable state and enum value conflicts
57
59
 
58
- Use the :module option to avoid naming conflicts between enumerated attributes
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 overlap when mapped to modules
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
@@ -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
- if (value != (old_value = self.read_enumerated_attribute(attribute)))
31
- unless old_value.nil?
32
- _module = self.class.get_module_for_enumerated_state(attribute, old_value)
33
- self.unmix(_module) if _module
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
- end
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
- - 4
9
- version: 0.0.4
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-28 00:00:00 -07:00
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.6
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)