enumerated_state 0.0.3 → 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/README.rdoc CHANGED
@@ -15,31 +15,33 @@ Use
15
15
 
16
16
  == Description
17
17
 
18
- This gem falls under the family of gems ASPIUM, ie (Another State Pattern Implementation Using Mixology). However,
19
- this one adds much needed state pattern support for enumerated attributes (see http://github.com/jeffp/enumerated_attribute)
20
- and supports multiple states per objection since each attribute manages a state.
18
+ This gem belongs to the ASPIUM family of gems -- (Another State Pattern Implementation
19
+ Using Mixology). This ASPIUM adds state pattern support to enumerated attributes (see enumerated_attribute[http://github.com/jeffp/enumerated_attribute])
20
+ and allows multiple state variables per object, one for each enumerated attribute.
21
21
 
22
22
  == Basic implementation
23
23
 
24
- So if you are using enumerated_attribute for an object tractor, you can replace the following code
24
+ If you are using enumerated_attribute, you may have code looking something like
25
25
 
26
- case
27
- when tractor.gear_is_first? then 'forwards'
28
- when tractor.gear_is_reverse? then 'backwards'
29
- else
30
- 'stopped'
26
+ class Tractor
27
+ def direction
28
+ case
29
+ when tractor.gear_is_first? then 'forwards'
30
+ when tractor.gear_is_reverse? then 'backwards'
31
+ else
32
+ 'stopped'
33
+ end
34
+ end
31
35
  end
32
36
 
33
- with the more maintainable version
34
-
35
- tractor.direction
36
-
37
- if you define
37
+ Enumerated State lets you clean it up as so
38
38
 
39
39
  class Tractor
40
- enum_attr :gear, %w(reverse ^neutral first), allow_nil=>false
40
+ enum_attr :gear, %w(reverse ^neutral first)
41
41
  acts_as_enumerated_state :gear
42
42
 
43
+ def direction; nil; end # called if gear == nil
44
+
43
45
  module Reverse
44
46
  def direction; 'backwards'; end
45
47
  end
@@ -51,6 +53,27 @@ if you define
51
53
  end
52
54
  end
53
55
 
56
+ == Multi-variable state and enum value conflicts
57
+
58
+ Use the :module option to avoid naming conflicts between enumerated attributes
59
+
60
+ class Foobar
61
+ enum_attr :alpha, %w(state1 state2)
62
+ enum_attr :beta, %w(state1 state2 state3) # names will overlap when mapped to modules
63
+
64
+ acts_as_enumerated_state :alpha
65
+ acts_as_enumerated_state :beta, :module=>'Beta'
66
+
67
+ module State1 ... end
68
+ module State2 ... end
69
+
70
+ module Beta
71
+ module State1 ... end
72
+ module State2 ... end
73
+ module State3 ... end
74
+ end
75
+ end
76
+
54
77
  == Dependencies
55
78
 
56
79
  * meta_programming
@@ -20,29 +20,52 @@ class Class
20
20
 
21
21
  self.extend EnumeratedStateClassMethods
22
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)
23
24
 
24
25
  if self.method_defined?("write_enumerated_attribute_without_#{enum_attr}")
25
26
  raise EnumeratedState::RedefinitionError, "Enumerated state already defined for :#{enum_attr}"
26
27
  end
27
28
 
28
29
  define_chained_method(:write_enumerated_attribute, enum_attr) do |attribute, value|
29
- module_prefix = self.class.get_enumerated_state_property(attribute, :module_prefix) || ''
30
30
  if (value != (old_value = self.read_enumerated_attribute(attribute)))
31
31
  unless old_value.nil?
32
- _module = self.class.class_eval(module_prefix + old_value.to_s.split(/_/).map(&:capitalize).join)
33
- self.unmix _module
32
+ _module = self.class.get_module_for_enumerated_state(attribute, old_value)
33
+ self.unmix(_module) if _module
34
34
  end
35
35
  end
36
36
  self.__send__("write_enumerated_attribute_without_#{enum_attr}".to_sym, attribute, value)
37
37
  if (enum_attr == attribute.to_sym && !value.nil?)
38
- _module = self.class.class_eval(module_prefix + value.to_s.split(/_/).map(&:capitalize).join)
39
- self.mixin _module
38
+ _module = self.class.get_module_for_enumerated_state(attribute, value)
39
+ self.mixin(_module) if _module
40
40
  end
41
41
  end
42
42
  end
43
43
  alias_method :enumerated_state_pattern, :acts_as_enumerated_state
44
44
 
45
+ module EnumeratedStateHelpers
46
+
47
+ end
48
+
45
49
  module EnumeratedStateClassMethods
50
+ def get_module_for_enumerated_state(attribute, value)
51
+ value = value.to_sym unless value.nil?
52
+ return self.get_enumerated_state_property(attribute, value) if self.enumerated_state_property_exists?(attribute, value)
53
+
54
+ module_prefix = self.get_enumerated_state_property(attribute, :module_prefix) || ''
55
+ module_name = module_prefix + value.to_s.split(/_/).map(&:capitalize).join
56
+ strict = self.get_enumerated_state_property(attribute, :strict)
57
+ _module = begin
58
+ self.class_eval(module_name)
59
+ rescue
60
+ begin
61
+ Kernel.class_eval(module_name)
62
+ rescue Exception => ex
63
+ raise ex if strict
64
+ end
65
+ end
66
+ self.set_enumerated_state_property(attribute, value, _module)
67
+ _module
68
+ end
46
69
  def get_enumerated_state_property(enum_attr, prop_name)
47
70
  if @_enumerated_state.has_key?(enum_attr)
48
71
  if @_enumerated_state[enum_attr].has_key?(prop_name)
@@ -59,6 +82,9 @@ class Class
59
82
  end
60
83
  return nil
61
84
  end
85
+ def enumerated_state_property_exists?(enum_attr, prop_name)
86
+ @_enumerated_state[enum_attr].has_key?(prop_name) rescue false
87
+ end
62
88
  def set_enumerated_state_property(enum_attr, prop_name, value)
63
89
  @_enumerated_state ||= {}
64
90
  @_enumerated_state[enum_attr] ||= {}
@@ -375,6 +375,42 @@ describe 'Enumerated State' do
375
375
  end
376
376
  end
377
377
 
378
+ describe "implementation with missing module" do
379
+ class Impl20
380
+ enum_attr :enum1, %w(mod1 mod2)
381
+ enum_attr :enum2, %w(mod3 mod2)
382
+ acts_as_enumerated_state :enum1, :strict=>false
383
+ acts_as_enumerated_state :enum2
384
+
385
+ def hello; 'hello Impl'; end
386
+ def hi; 'hi Impl'; end
387
+
388
+ module Mod1
389
+ def hello; 'hello Mod1'; end
390
+ end
391
+ module Mod3
392
+ def hi; 'hi Mod3'; end
393
+ end
394
+ end
395
+
396
+ it "should call Impl hello when enum1 set to Mod2 and :strict option set to false" do
397
+ obj = Impl20.new
398
+ obj.hello.should == 'hello Impl'
399
+ obj.enum1 = :mod1
400
+ obj.hello.should == 'hello Mod1'
401
+ obj.enum1 = :mod2
402
+ obj.hello.should == 'hello Impl'
403
+ end
404
+
405
+ it "should raise exception when enum2 set to Mod2 and :strict option not set" do
406
+ obj = Impl20.new
407
+ obj.hi.should == 'hi Impl'
408
+ obj.enum2 = :mod3
409
+ obj.hi.should == 'hi Mod3'
410
+ lambda { obj.enum2 = :mod2 }.should raise_exception(NameError)
411
+ end
412
+ end
413
+
378
414
  describe "implementation error checking" do
379
415
 
380
416
  it "should raise exception when redeclaring enumerated states in subclass" do
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerated_state
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 0
9
- - 3
10
- version: 0.0.3
8
+ - 4
9
+ version: 0.0.4
11
10
  platform: ruby
12
11
  authors:
13
12
  - Jeff Patmon
@@ -22,11 +21,9 @@ dependencies:
22
21
  name: enumerated_attribute
23
22
  prerelease: false
24
23
  requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
24
  requirements:
27
25
  - - ">="
28
26
  - !ruby/object:Gem::Version
29
- hash: 3
30
27
  segments:
31
28
  - 0
32
29
  - 2
@@ -38,11 +35,9 @@ dependencies:
38
35
  name: mixology
39
36
  prerelease: false
40
37
  requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
38
  requirements:
43
39
  - - ">="
44
40
  - !ruby/object:Gem::Version
45
- hash: 23
46
41
  segments:
47
42
  - 0
48
43
  - 2
@@ -54,11 +49,9 @@ dependencies:
54
49
  name: meta_programming
55
50
  prerelease: false
56
51
  requirement: &id003 !ruby/object:Gem::Requirement
57
- none: false
58
52
  requirements:
59
53
  - - ">="
60
54
  - !ruby/object:Gem::Version
61
- hash: 21
62
55
  segments:
63
56
  - 0
64
57
  - 2
@@ -94,29 +87,25 @@ rdoc_options: []
94
87
  require_paths:
95
88
  - lib
96
89
  required_ruby_version: !ruby/object:Gem::Requirement
97
- none: false
98
90
  requirements:
99
91
  - - ">="
100
92
  - !ruby/object:Gem::Version
101
- hash: 57
102
93
  segments:
103
94
  - 1
104
95
  - 8
105
96
  - 7
106
97
  version: 1.8.7
107
98
  required_rubygems_version: !ruby/object:Gem::Requirement
108
- none: false
109
99
  requirements:
110
100
  - - ">="
111
101
  - !ruby/object:Gem::Version
112
- hash: 3
113
102
  segments:
114
103
  - 0
115
104
  version: "0"
116
105
  requirements: []
117
106
 
118
107
  rubyforge_project:
119
- rubygems_version: 1.3.7
108
+ rubygems_version: 1.3.6
120
109
  signing_key:
121
110
  specification_version: 3
122
111
  summary: ASPIUM (Another State Pattern Implementation Using Mixology)