state_pattern 1.3.0 → 2.0.0
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 +17 -41
- data/Rakefile +0 -1
- data/examples/rails_2_3_8_button_example/app/models/button/off.rb +1 -1
- data/examples/rails_2_3_8_button_example/app/models/button/on.rb +1 -1
- data/examples/rails_3_button_example/app/models/button/off.rb +1 -1
- data/examples/rails_3_button_example/app/models/button/on.rb +1 -1
- data/examples/rails_3_button_example/app/views/buttons/_form.html.erb +21 -0
- data/examples/rails_3_button_example/app/views/buttons/edit.html.erb +6 -0
- data/examples/rails_3_button_example/app/views/buttons/index.html.erb +23 -0
- data/examples/rails_3_button_example/app/views/buttons/new.html.erb +5 -0
- data/examples/rails_3_button_example/config/environments/production.rb +49 -0
- data/examples/rails_3_button_example/config/environments/test.rb +35 -0
- data/examples/rails_3_button_example/public/javascripts/controls.js +965 -0
- data/examples/rails_3_button_example/public/javascripts/dragdrop.js +974 -0
- data/examples/rails_3_button_example/public/javascripts/effects.js +1123 -0
- data/examples/rails_3_button_example/public/robots.txt +5 -0
- data/lib/state_pattern.rb +10 -78
- data/lib/state_pattern/active_record.rb +2 -2
- data/lib/state_pattern/state.rb +8 -4
- data/rails/init.rb +0 -1
- data/test/hook_test.rb +6 -7
- data/test/state_pattern/active_record/active_record_test.rb +2 -3
- data/test/state_pattern/active_record/test_helper.rb +2 -1
- data/test/state_pattern_test.rb +12 -11
- data/test/test_class_creation_helper.rb +0 -11
- metadata +24 -9
- data/lib/state_pattern/invalid_transition_exception.rb +0 -14
- data/test/querying_test.rb +0 -87
- data/test/transition_validations_test.rb +0 -55
data/lib/state_pattern.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'state_pattern/state'
|
2
|
-
require 'state_pattern/invalid_transition_exception'
|
3
3
|
|
4
4
|
module StatePattern
|
5
5
|
def self.included(base)
|
@@ -13,100 +13,32 @@ module StatePattern
|
|
13
13
|
|
14
14
|
def set_initial_state(state_class)
|
15
15
|
@initial_state_class = state_class
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def state_methods
|
20
|
-
state_classes_with_their_bases = state_classes.map{|c| c.ancestors.select{|a| a.ancestors.include?(StatePattern::State) && a != StatePattern::State}}.flatten.uniq
|
21
|
-
(state_classes_with_their_bases.map{|state_class| state_class.public_instance_methods(false)}.flatten.uniq - ["enter", "exit"]).map{|s| s.to_sym}
|
22
|
-
end
|
23
|
-
|
24
|
-
def state_events
|
25
|
-
transitions_hash.to_a.flatten.uniq.select{|t| t.respond_to?(:to_sym)}.map{|s| s.to_sym}
|
26
|
-
end
|
27
|
-
|
28
|
-
def state_classes
|
29
|
-
(transitions_hash.to_a << initial_state_class).flatten.uniq.select{|t| t.respond_to?(:ancestors) && t.ancestors.include?(StatePattern::State)}
|
30
|
-
end
|
31
|
-
|
32
|
-
def valid_transitions(transitions_hash)
|
33
|
-
@transitions_hash = transitions_hash
|
34
|
-
@transitions_hash.each do |key, value|
|
35
|
-
@transitions_hash[key] = [value] if !value.respond_to?(:to_ary)
|
36
|
-
end
|
37
|
-
create_methods
|
38
|
-
end
|
39
|
-
|
40
|
-
def transitions_hash
|
41
|
-
@transitions_hash
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
def create_methods
|
46
|
-
delegate_all_state_methods
|
47
|
-
create_query_methods
|
48
|
-
end
|
49
|
-
|
50
|
-
def delegate_all_state_methods
|
51
|
-
state_methods.each do |state_method|
|
52
|
-
define_method state_method do |*args|
|
53
|
-
delegate_to_state(state_method, *args)
|
54
|
-
end unless respond_to?(state_method)
|
55
|
-
end
|
16
|
+
include ::StatePattern::Delegation
|
56
17
|
end
|
18
|
+
end
|
57
19
|
|
58
|
-
|
59
|
-
|
60
|
-
method_name = "#{underscore(state_class.name.split("::").last)}?"
|
61
|
-
define_method method_name do
|
62
|
-
current_state_instance.class == state_class
|
63
|
-
end unless respond_to?(method_name)
|
64
|
-
end
|
65
|
-
end
|
20
|
+
module Delegation
|
21
|
+
extend Forwardable
|
66
22
|
|
67
|
-
def
|
68
|
-
|
69
|
-
camel_cased_word.to_s.gsub(/::/, '/').
|
70
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
71
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
72
|
-
tr("-", "_").
|
73
|
-
downcase
|
23
|
+
def self.included(base)
|
24
|
+
def_delegators :current_state_instance, *base.initial_state_class.state_methods
|
74
25
|
end
|
75
26
|
end
|
76
27
|
|
77
|
-
def set_state(state_class = nil)
|
78
|
-
state_class ||= self.class.initial_state_class
|
79
|
-
return @current_state_instance if @current_state_instance.class == state_class
|
80
|
-
@current_state_instance = state_class.new(self, @current_state_instance)
|
81
|
-
end
|
82
|
-
|
83
28
|
def current_state_instance
|
84
29
|
set_state if @current_state_instance.nil?
|
85
30
|
@current_state_instance
|
86
31
|
end
|
87
32
|
|
88
|
-
def
|
89
|
-
@
|
90
|
-
|
33
|
+
def set_state(state_class = self.class.initial_state_class)
|
34
|
+
return @current_state_instance if @current_state_instance.class == state_class
|
35
|
+
@current_state_instance = state_class.new(self, @current_state_instance)
|
91
36
|
end
|
92
37
|
|
93
38
|
def transition_to(next_state_class)
|
94
|
-
raise_invalid_transition_to(next_state_class) unless valid_transition?(current_state_instance.class, next_state_class)
|
95
39
|
current_state_instance.exit
|
96
40
|
set_state(next_state_class)
|
97
41
|
end
|
98
|
-
|
99
|
-
def raise_invalid_transition_to(state_class)
|
100
|
-
raise InvalidTransitionException.new(current_state_instance.class, state_class, @current_method)
|
101
|
-
end
|
102
|
-
|
103
|
-
def valid_transition?(from_state, to_state)
|
104
|
-
transitions = self.class.transitions_hash
|
105
|
-
return true if transitions.nil?
|
106
|
-
|
107
|
-
valid_transition_targets = transitions[from_state] || transitions[[from_state, @current_method]]
|
108
|
-
valid_transition_targets && valid_transition_targets.include?(to_state)
|
109
|
-
end
|
110
42
|
end
|
111
43
|
|
112
44
|
require 'state_pattern/active_record' if defined? ActiveRecord::Base
|
@@ -6,7 +6,7 @@ module StatePattern
|
|
6
6
|
|
7
7
|
after_initialize :set_state_from_db
|
8
8
|
def set_state_from_db
|
9
|
-
set_state(state_string_as_class)
|
9
|
+
set_state(state_string_as_class || self.class.initial_state_class)
|
10
10
|
end
|
11
11
|
|
12
12
|
#enable after_initialize callback
|
@@ -16,7 +16,7 @@ module StatePattern
|
|
16
16
|
def after_initialize; end
|
17
17
|
end
|
18
18
|
|
19
|
-
def set_state_with_active_record_attribute(state_class
|
19
|
+
def set_state_with_active_record_attribute(state_class)
|
20
20
|
set_state_without_active_record_attribute(state_class)
|
21
21
|
write_attribute(self.class.state_attribute, @current_state_instance.class.name)
|
22
22
|
end
|
data/lib/state_pattern/state.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
module StatePattern
|
2
2
|
class State
|
3
|
-
attr_reader :
|
4
|
-
def initialize(
|
5
|
-
@
|
3
|
+
attr_reader :stateful, :previous_state
|
4
|
+
def initialize(stateful, previous_state)
|
5
|
+
@stateful = stateful
|
6
6
|
@previous_state = previous_state
|
7
7
|
enter
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.state_methods
|
11
|
+
public_instance_methods - State.public_instance_methods
|
12
|
+
end
|
13
|
+
|
10
14
|
def transition_to(state_class)
|
11
|
-
@
|
15
|
+
@stateful.transition_to(state_class)
|
12
16
|
end
|
13
17
|
|
14
18
|
def enter
|
data/rails/init.rb
CHANGED
data/test/hook_test.rb
CHANGED
@@ -4,15 +4,15 @@ module Hooks
|
|
4
4
|
class On < StatePattern::State
|
5
5
|
def press
|
6
6
|
transition_to(Off)
|
7
|
-
|
7
|
+
stateful.messages << "#{stateful.button_name} is off"
|
8
8
|
end
|
9
9
|
|
10
10
|
def enter
|
11
|
-
|
11
|
+
stateful.messages << "Entered the On state"
|
12
12
|
end
|
13
13
|
|
14
14
|
def exit
|
15
|
-
|
15
|
+
stateful.messages << "Exited the On state"
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -23,22 +23,21 @@ module Hooks
|
|
23
23
|
class Off < StatePattern::State
|
24
24
|
def press
|
25
25
|
transition_to(On)
|
26
|
-
|
26
|
+
stateful.messages << "#{stateful.button_name} is on"
|
27
27
|
end
|
28
28
|
|
29
29
|
def enter
|
30
|
-
|
30
|
+
stateful.messages << "Entered the Off state"
|
31
31
|
end
|
32
32
|
|
33
33
|
def exit
|
34
|
-
|
34
|
+
stateful.messages << "Exited the Off state"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
class Button
|
39
39
|
include StatePattern
|
40
40
|
set_initial_state Off
|
41
|
-
valid_transitions [On, :press] => Off, [Off, :press] => On
|
42
41
|
|
43
42
|
def button_name
|
44
43
|
"Button"
|
@@ -4,20 +4,19 @@ class ARButton < ActiveRecord::Base
|
|
4
4
|
class On < StatePattern::State
|
5
5
|
def press
|
6
6
|
transition_to(Off)
|
7
|
-
"#{
|
7
|
+
"#{stateful.button_name} is off"
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
class Off < StatePattern::State
|
12
12
|
def press
|
13
13
|
transition_to(On)
|
14
|
-
"#{
|
14
|
+
"#{stateful.button_name} is on"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
include StatePattern::ActiveRecord
|
19
19
|
set_initial_state Off
|
20
|
-
valid_transitions [On, :press] => Off, [Off, :press] => On
|
21
20
|
|
22
21
|
def button_name
|
23
22
|
"The button"
|
data/test/state_pattern_test.rb
CHANGED
@@ -4,7 +4,7 @@ module Family
|
|
4
4
|
class James < StatePattern::State
|
5
5
|
def name
|
6
6
|
transition_to(Lynn)
|
7
|
-
"James #{
|
7
|
+
"James #{stateful.last_name}"
|
8
8
|
end
|
9
9
|
|
10
10
|
def james_method
|
@@ -14,18 +14,19 @@ module Family
|
|
14
14
|
class Lynn < StatePattern::State
|
15
15
|
def name
|
16
16
|
transition_to(James)
|
17
|
-
"Lynn #{
|
17
|
+
"Lynn #{stateful.last_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def james_method
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
24
|
class Member
|
22
25
|
include StatePattern
|
23
26
|
set_initial_state Lynn
|
24
|
-
valid_transitions [James, :name] => Lynn, [Lynn, :name] => James
|
25
27
|
|
26
|
-
#notice this method is optional, it will be delegated automatically if removed
|
27
28
|
def name
|
28
|
-
|
29
|
+
super
|
29
30
|
end
|
30
31
|
|
31
32
|
def last_name
|
@@ -37,20 +38,20 @@ end
|
|
37
38
|
Expectations do
|
38
39
|
expect "Lynn Holbrook" do
|
39
40
|
member = Family::Member.new
|
40
|
-
member.name
|
41
|
+
member.name
|
41
42
|
end
|
42
43
|
|
43
44
|
expect "James Holbrook" do
|
44
45
|
member = Family::Member.new
|
45
|
-
member.name
|
46
|
-
member.name
|
46
|
+
member.name
|
47
|
+
member.name
|
47
48
|
end
|
48
49
|
|
49
50
|
expect "Lynn Holbrook" do
|
50
51
|
member = Family::Member.new
|
51
|
-
member.name
|
52
|
-
member.name
|
53
|
-
member.name
|
52
|
+
member.name
|
53
|
+
member.name
|
54
|
+
member.name
|
54
55
|
end
|
55
56
|
|
56
57
|
expect true do
|
@@ -23,17 +23,6 @@ module TestClassCreationHelper
|
|
23
23
|
created_consts << create_class(main_state_module_name) do
|
24
24
|
include StatePattern
|
25
25
|
set_initial_state Object.const_get(options[:initial_state]) if options.has_key?(:initial_state)
|
26
|
-
if options.has_key?(:valid_transitions)
|
27
|
-
valid_transitions_with_constants = {}
|
28
|
-
options[:valid_transitions].each do |from_module_string_or_array, to_module_string|
|
29
|
-
if from_module_string_or_array.respond_to?(:to_ary)
|
30
|
-
valid_transitions_with_constants[[Object.const_get(from_module_string_or_array.first), from_module_string_or_array.last]] = Object.const_get(to_module_string)
|
31
|
-
else
|
32
|
-
valid_transitions_with_constants[Object.const_get(from_module_string_or_array)] = Object.const_get(to_module_string)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
valid_transitions valid_transitions_with_constants
|
36
|
-
end
|
37
26
|
end
|
38
27
|
|
39
28
|
begin
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_pattern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 3
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Daniel Cadenas
|
@@ -36,7 +36,6 @@ files:
|
|
36
36
|
- Rakefile
|
37
37
|
- rails/init.rb
|
38
38
|
- ./lib/state_pattern/active_record.rb
|
39
|
-
- ./lib/state_pattern/invalid_transition_exception.rb
|
40
39
|
- ./lib/state_pattern/state.rb
|
41
40
|
- ./lib/state_pattern.rb
|
42
41
|
- ./examples/rails_2_3_8_button_example/app/controllers/application_controller.rb
|
@@ -91,6 +90,10 @@ files:
|
|
91
90
|
- ./examples/rails_3_button_example/app/models/button/off.rb
|
92
91
|
- ./examples/rails_3_button_example/app/models/button/on.rb
|
93
92
|
- ./examples/rails_3_button_example/app/models/button.rb
|
93
|
+
- ./examples/rails_3_button_example/app/views/buttons/_form.html.erb
|
94
|
+
- ./examples/rails_3_button_example/app/views/buttons/edit.html.erb
|
95
|
+
- ./examples/rails_3_button_example/app/views/buttons/index.html.erb
|
96
|
+
- ./examples/rails_3_button_example/app/views/buttons/new.html.erb
|
94
97
|
- ./examples/rails_3_button_example/app/views/buttons/show.html.erb
|
95
98
|
- ./examples/rails_3_button_example/app/views/layouts/application.html.erb
|
96
99
|
- ./examples/rails_3_button_example/config/application.rb
|
@@ -98,6 +101,8 @@ files:
|
|
98
101
|
- ./examples/rails_3_button_example/config/database.yml
|
99
102
|
- ./examples/rails_3_button_example/config/environment.rb
|
100
103
|
- ./examples/rails_3_button_example/config/environments/development.rb
|
104
|
+
- ./examples/rails_3_button_example/config/environments/production.rb
|
105
|
+
- ./examples/rails_3_button_example/config/environments/test.rb
|
101
106
|
- ./examples/rails_3_button_example/config/initializers/backtrace_silencers.rb
|
102
107
|
- ./examples/rails_3_button_example/config/initializers/inflections.rb
|
103
108
|
- ./examples/rails_3_button_example/config/initializers/mime_types.rb
|
@@ -114,22 +119,24 @@ files:
|
|
114
119
|
- ./examples/rails_3_button_example/Gemfile.lock
|
115
120
|
- ./examples/rails_3_button_example/log/development.log
|
116
121
|
- ./examples/rails_3_button_example/public/javascripts/application.js
|
122
|
+
- ./examples/rails_3_button_example/public/javascripts/controls.js
|
123
|
+
- ./examples/rails_3_button_example/public/javascripts/dragdrop.js
|
124
|
+
- ./examples/rails_3_button_example/public/javascripts/effects.js
|
117
125
|
- ./examples/rails_3_button_example/public/javascripts/prototype.js
|
118
126
|
- ./examples/rails_3_button_example/public/javascripts/rails.js
|
127
|
+
- ./examples/rails_3_button_example/public/robots.txt
|
119
128
|
- ./examples/rails_3_button_example/public/stylesheets/scaffold.css
|
120
129
|
- ./examples/rails_3_button_example/Rakefile
|
121
130
|
- ./examples/rails_3_button_example/script/rails
|
122
131
|
- ./examples/semaphore.rb
|
123
132
|
- ./test/arguments_of_event_delegation_test.rb
|
124
133
|
- ./test/hook_test.rb
|
125
|
-
- ./test/querying_test.rb
|
126
134
|
- ./test/state_pattern/active_record/active_record_test.rb
|
127
135
|
- ./test/state_pattern/active_record/schema.rb
|
128
136
|
- ./test/state_pattern/active_record/test_helper.rb
|
129
137
|
- ./test/state_pattern_test.rb
|
130
138
|
- ./test/test_class_creation_helper.rb
|
131
139
|
- ./test/test_helper.rb
|
132
|
-
- ./test/transition_validations_test.rb
|
133
140
|
has_rdoc: true
|
134
141
|
homepage: http://github.com/dcadenas/state_pattern
|
135
142
|
licenses: []
|
@@ -217,6 +224,10 @@ test_files:
|
|
217
224
|
- ./examples/rails_3_button_example/app/models/button/off.rb
|
218
225
|
- ./examples/rails_3_button_example/app/models/button/on.rb
|
219
226
|
- ./examples/rails_3_button_example/app/models/button.rb
|
227
|
+
- ./examples/rails_3_button_example/app/views/buttons/_form.html.erb
|
228
|
+
- ./examples/rails_3_button_example/app/views/buttons/edit.html.erb
|
229
|
+
- ./examples/rails_3_button_example/app/views/buttons/index.html.erb
|
230
|
+
- ./examples/rails_3_button_example/app/views/buttons/new.html.erb
|
220
231
|
- ./examples/rails_3_button_example/app/views/buttons/show.html.erb
|
221
232
|
- ./examples/rails_3_button_example/app/views/layouts/application.html.erb
|
222
233
|
- ./examples/rails_3_button_example/config/application.rb
|
@@ -224,6 +235,8 @@ test_files:
|
|
224
235
|
- ./examples/rails_3_button_example/config/database.yml
|
225
236
|
- ./examples/rails_3_button_example/config/environment.rb
|
226
237
|
- ./examples/rails_3_button_example/config/environments/development.rb
|
238
|
+
- ./examples/rails_3_button_example/config/environments/production.rb
|
239
|
+
- ./examples/rails_3_button_example/config/environments/test.rb
|
227
240
|
- ./examples/rails_3_button_example/config/initializers/backtrace_silencers.rb
|
228
241
|
- ./examples/rails_3_button_example/config/initializers/inflections.rb
|
229
242
|
- ./examples/rails_3_button_example/config/initializers/mime_types.rb
|
@@ -240,19 +253,21 @@ test_files:
|
|
240
253
|
- ./examples/rails_3_button_example/Gemfile.lock
|
241
254
|
- ./examples/rails_3_button_example/log/development.log
|
242
255
|
- ./examples/rails_3_button_example/public/javascripts/application.js
|
256
|
+
- ./examples/rails_3_button_example/public/javascripts/controls.js
|
257
|
+
- ./examples/rails_3_button_example/public/javascripts/dragdrop.js
|
258
|
+
- ./examples/rails_3_button_example/public/javascripts/effects.js
|
243
259
|
- ./examples/rails_3_button_example/public/javascripts/prototype.js
|
244
260
|
- ./examples/rails_3_button_example/public/javascripts/rails.js
|
261
|
+
- ./examples/rails_3_button_example/public/robots.txt
|
245
262
|
- ./examples/rails_3_button_example/public/stylesheets/scaffold.css
|
246
263
|
- ./examples/rails_3_button_example/Rakefile
|
247
264
|
- ./examples/rails_3_button_example/script/rails
|
248
265
|
- ./examples/semaphore.rb
|
249
266
|
- ./test/arguments_of_event_delegation_test.rb
|
250
267
|
- ./test/hook_test.rb
|
251
|
-
- ./test/querying_test.rb
|
252
268
|
- ./test/state_pattern/active_record/active_record_test.rb
|
253
269
|
- ./test/state_pattern/active_record/schema.rb
|
254
270
|
- ./test/state_pattern/active_record/test_helper.rb
|
255
271
|
- ./test/state_pattern_test.rb
|
256
272
|
- ./test/test_class_creation_helper.rb
|
257
273
|
- ./test/test_helper.rb
|
258
|
-
- ./test/transition_validations_test.rb
|