enumerated_state 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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)