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