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 +38 -15
- data/lib/enumerated_state.rb +31 -5
- data/spec/enumerated_state_spec.rb +36 -0
- metadata +3 -14
data/README.rdoc
CHANGED
@@ -15,31 +15,33 @@ Use
|
|
15
15
|
|
16
16
|
== Description
|
17
17
|
|
18
|
-
This gem
|
19
|
-
|
20
|
-
and
|
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
|
-
|
24
|
+
If you are using enumerated_attribute, you may have code looking something like
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
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)
|
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
|
data/lib/enumerated_state.rb
CHANGED
@@ -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.
|
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.
|
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
|
-
-
|
10
|
-
version: 0.0.
|
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.
|
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)
|