state_pattern 1.2.0 → 1.3.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/.gitignore +2 -0
- data/README.rdoc +188 -6
- data/Rakefile +0 -58
- data/examples/rails_2_3_8_button_example/README +243 -0
- data/examples/rails_2_3_8_button_example/Rakefile +10 -0
- data/examples/rails_2_3_8_button_example/app/controllers/application_controller.rb +2 -0
- data/examples/rails_2_3_8_button_example/app/controllers/buttons_controller.rb +18 -0
- data/examples/rails_2_3_8_button_example/app/helpers/application_helper.rb +3 -0
- data/examples/rails_2_3_8_button_example/app/models/button.rb +4 -0
- data/examples/rails_2_3_8_button_example/app/models/button/off.rb +7 -0
- data/examples/rails_2_3_8_button_example/app/models/button/on.rb +8 -0
- data/examples/rails_2_3_8_button_example/app/views/buttons/show.html.erb +9 -0
- data/examples/rails_2_3_8_button_example/app/views/layouts/application.html.erb +12 -0
- data/examples/rails_2_3_8_button_example/config/boot.rb +110 -0
- data/examples/rails_2_3_8_button_example/config/database.yml +22 -0
- data/examples/rails_2_3_8_button_example/config/environment.rb +41 -0
- data/examples/rails_2_3_8_button_example/config/environments/development.rb +17 -0
- data/examples/rails_2_3_8_button_example/config/environments/production.rb +28 -0
- data/examples/rails_2_3_8_button_example/config/environments/test.rb +28 -0
- data/examples/rails_2_3_8_button_example/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails_2_3_8_button_example/config/initializers/cookie_verification_secret.rb +7 -0
- data/examples/rails_2_3_8_button_example/config/initializers/inflections.rb +10 -0
- data/examples/rails_2_3_8_button_example/config/initializers/mime_types.rb +5 -0
- data/examples/rails_2_3_8_button_example/config/initializers/new_rails_defaults.rb +21 -0
- data/examples/rails_2_3_8_button_example/config/initializers/session_store.rb +15 -0
- data/examples/rails_2_3_8_button_example/config/locales/en.yml +5 -0
- data/examples/rails_2_3_8_button_example/config/routes.rb +4 -0
- data/examples/rails_2_3_8_button_example/db/development.sqlite3 +0 -0
- data/examples/rails_2_3_8_button_example/db/migrate/20101009073737_create_buttons.rb +13 -0
- data/examples/rails_2_3_8_button_example/db/schema.rb +20 -0
- data/examples/rails_2_3_8_button_example/db/seeds.rb +7 -0
- data/examples/rails_2_3_8_button_example/db/test.sqlite3 +0 -0
- data/examples/rails_2_3_8_button_example/doc/README_FOR_APP +2 -0
- data/examples/rails_2_3_8_button_example/public/images/rails.png +0 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/application.js +2 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/controls.js +963 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/dragdrop.js +973 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/effects.js +1128 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/prototype.js +4320 -0
- data/examples/rails_2_3_8_button_example/public/javascripts/rails.js +175 -0
- data/examples/rails_2_3_8_button_example/script/about +4 -0
- data/examples/rails_2_3_8_button_example/script/console +3 -0
- data/examples/rails_2_3_8_button_example/script/dbconsole +3 -0
- data/examples/rails_2_3_8_button_example/script/destroy +3 -0
- data/examples/rails_2_3_8_button_example/script/generate +3 -0
- data/examples/rails_2_3_8_button_example/script/performance/benchmarker +3 -0
- data/examples/rails_2_3_8_button_example/script/performance/profiler +3 -0
- data/examples/rails_2_3_8_button_example/script/plugin +3 -0
- data/examples/rails_2_3_8_button_example/script/runner +3 -0
- data/examples/rails_2_3_8_button_example/script/server +3 -0
- data/examples/rails_3_button_example/Gemfile +31 -0
- data/examples/rails_3_button_example/Gemfile.lock +75 -0
- data/examples/rails_3_button_example/Rakefile +7 -0
- data/examples/rails_3_button_example/app/controllers/application_controller.rb +3 -0
- data/examples/rails_3_button_example/app/controllers/buttons_controller.rb +13 -0
- data/examples/rails_3_button_example/app/models/button.rb +4 -0
- data/examples/rails_3_button_example/app/models/button/off.rb +7 -0
- data/examples/rails_3_button_example/app/models/button/on.rb +8 -0
- data/examples/rails_3_button_example/app/views/buttons/show.html.erb +9 -0
- data/examples/rails_3_button_example/app/views/layouts/application.html.erb +13 -0
- data/examples/rails_3_button_example/config.ru +4 -0
- data/examples/rails_3_button_example/config/application.rb +42 -0
- data/examples/rails_3_button_example/config/boot.rb +13 -0
- data/examples/rails_3_button_example/config/database.yml +22 -0
- data/examples/rails_3_button_example/config/environment.rb +5 -0
- data/examples/rails_3_button_example/config/environments/development.rb +26 -0
- data/examples/rails_3_button_example/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails_3_button_example/config/initializers/inflections.rb +10 -0
- data/examples/rails_3_button_example/config/initializers/mime_types.rb +5 -0
- data/examples/rails_3_button_example/config/initializers/secret_token.rb +7 -0
- data/examples/rails_3_button_example/config/initializers/session_store.rb +8 -0
- data/examples/rails_3_button_example/config/locales/en.yml +5 -0
- data/examples/rails_3_button_example/config/routes.rb +5 -0
- data/examples/rails_3_button_example/db/development.sqlite3 +0 -0
- data/examples/rails_3_button_example/db/migrate/20101009052900_create_buttons.rb +13 -0
- data/examples/rails_3_button_example/db/schema.rb +21 -0
- data/examples/rails_3_button_example/db/test.sqlite3 +0 -0
- data/examples/rails_3_button_example/public/javascripts/application.js +2 -0
- data/examples/rails_3_button_example/public/javascripts/prototype.js +6001 -0
- data/examples/rails_3_button_example/public/javascripts/rails.js +175 -0
- data/examples/rails_3_button_example/public/stylesheets/scaffold.css +56 -0
- data/examples/rails_3_button_example/script/rails +6 -0
- data/examples/semaphore.rb +58 -0
- data/lib/state_pattern.rb +3 -1
- data/lib/state_pattern/active_record.rb +44 -0
- data/rails/init.rb +3 -0
- data/test/state_pattern/active_record/active_record_test.rb +71 -0
- data/test/state_pattern/active_record/schema.rb +7 -0
- data/test/state_pattern/active_record/test_helper.rb +25 -0
- data/test/test_helper.rb +1 -0
- metadata +204 -24
- data/VERSION +0 -1
- data/state_pattern.gemspec +0 -59
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
// Technique from Juriy Zaytsev
|
|
3
|
+
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
|
|
4
|
+
function isEventSupported(eventName) {
|
|
5
|
+
var el = document.createElement('div');
|
|
6
|
+
eventName = 'on' + eventName;
|
|
7
|
+
var isSupported = (eventName in el);
|
|
8
|
+
if (!isSupported) {
|
|
9
|
+
el.setAttribute(eventName, 'return;');
|
|
10
|
+
isSupported = typeof el[eventName] == 'function';
|
|
11
|
+
}
|
|
12
|
+
el = null;
|
|
13
|
+
return isSupported;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isForm(element) {
|
|
17
|
+
return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isInput(element) {
|
|
21
|
+
if (Object.isElement(element)) {
|
|
22
|
+
var name = element.nodeName.toUpperCase()
|
|
23
|
+
return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
|
|
24
|
+
}
|
|
25
|
+
else return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var submitBubbles = isEventSupported('submit'),
|
|
29
|
+
changeBubbles = isEventSupported('change')
|
|
30
|
+
|
|
31
|
+
if (!submitBubbles || !changeBubbles) {
|
|
32
|
+
// augment the Event.Handler class to observe custom events when needed
|
|
33
|
+
Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
|
|
34
|
+
function(init, element, eventName, selector, callback) {
|
|
35
|
+
init(element, eventName, selector, callback)
|
|
36
|
+
// is the handler being attached to an element that doesn't support this event?
|
|
37
|
+
if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
|
|
38
|
+
(!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
|
|
39
|
+
// "submit" => "emulated:submit"
|
|
40
|
+
this.eventName = 'emulated:' + this.eventName
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!submitBubbles) {
|
|
47
|
+
// discover forms on the page by observing focus events which always bubble
|
|
48
|
+
document.on('focusin', 'form', function(focusEvent, form) {
|
|
49
|
+
// special handler for the real "submit" event (one-time operation)
|
|
50
|
+
if (!form.retrieve('emulated:submit')) {
|
|
51
|
+
form.on('submit', function(submitEvent) {
|
|
52
|
+
var emulated = form.fire('emulated:submit', submitEvent, true)
|
|
53
|
+
// if custom event received preventDefault, cancel the real one too
|
|
54
|
+
if (emulated.returnValue === false) submitEvent.preventDefault()
|
|
55
|
+
})
|
|
56
|
+
form.store('emulated:submit', true)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!changeBubbles) {
|
|
62
|
+
// discover form inputs on the page
|
|
63
|
+
document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
|
|
64
|
+
// special handler for real "change" events
|
|
65
|
+
if (!input.retrieve('emulated:change')) {
|
|
66
|
+
input.on('change', function(changeEvent) {
|
|
67
|
+
input.fire('emulated:change', changeEvent, true)
|
|
68
|
+
})
|
|
69
|
+
input.store('emulated:change', true)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleRemote(element) {
|
|
75
|
+
var method, url, params;
|
|
76
|
+
|
|
77
|
+
var event = element.fire("ajax:before");
|
|
78
|
+
if (event.stopped) return false;
|
|
79
|
+
|
|
80
|
+
if (element.tagName.toLowerCase() === 'form') {
|
|
81
|
+
method = element.readAttribute('method') || 'post';
|
|
82
|
+
url = element.readAttribute('action');
|
|
83
|
+
params = element.serialize();
|
|
84
|
+
} else {
|
|
85
|
+
method = element.readAttribute('data-method') || 'get';
|
|
86
|
+
url = element.readAttribute('href');
|
|
87
|
+
params = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
new Ajax.Request(url, {
|
|
91
|
+
method: method,
|
|
92
|
+
parameters: params,
|
|
93
|
+
evalScripts: true,
|
|
94
|
+
|
|
95
|
+
onComplete: function(request) { element.fire("ajax:complete", request); },
|
|
96
|
+
onSuccess: function(request) { element.fire("ajax:success", request); },
|
|
97
|
+
onFailure: function(request) { element.fire("ajax:failure", request); }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
element.fire("ajax:after");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function handleMethod(element) {
|
|
104
|
+
var method = element.readAttribute('data-method'),
|
|
105
|
+
url = element.readAttribute('href'),
|
|
106
|
+
csrf_param = $$('meta[name=csrf-param]')[0],
|
|
107
|
+
csrf_token = $$('meta[name=csrf-token]')[0];
|
|
108
|
+
|
|
109
|
+
var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
|
|
110
|
+
element.parentNode.insert(form);
|
|
111
|
+
|
|
112
|
+
if (method !== 'post') {
|
|
113
|
+
var field = new Element('input', { type: 'hidden', name: '_method', value: method });
|
|
114
|
+
form.insert(field);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (csrf_param) {
|
|
118
|
+
var param = csrf_param.readAttribute('content'),
|
|
119
|
+
token = csrf_token.readAttribute('content'),
|
|
120
|
+
field = new Element('input', { type: 'hidden', name: param, value: token });
|
|
121
|
+
form.insert(field);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
form.submit();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
document.on("click", "*[data-confirm]", function(event, element) {
|
|
129
|
+
var message = element.readAttribute('data-confirm');
|
|
130
|
+
if (!confirm(message)) event.stop();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
document.on("click", "a[data-remote]", function(event, element) {
|
|
134
|
+
if (event.stopped) return;
|
|
135
|
+
handleRemote(element);
|
|
136
|
+
event.stop();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
document.on("click", "a[data-method]", function(event, element) {
|
|
140
|
+
if (event.stopped) return;
|
|
141
|
+
handleMethod(element);
|
|
142
|
+
event.stop();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
document.on("submit", function(event) {
|
|
146
|
+
var element = event.findElement(),
|
|
147
|
+
message = element.readAttribute('data-confirm');
|
|
148
|
+
if (message && !confirm(message)) {
|
|
149
|
+
event.stop();
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var inputs = element.select("input[type=submit][data-disable-with]");
|
|
154
|
+
inputs.each(function(input) {
|
|
155
|
+
input.disabled = true;
|
|
156
|
+
input.writeAttribute('data-original-value', input.value);
|
|
157
|
+
input.value = input.readAttribute('data-disable-with');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
var element = event.findElement("form[data-remote]");
|
|
161
|
+
if (element) {
|
|
162
|
+
handleRemote(element);
|
|
163
|
+
event.stop();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
document.on("ajax:after", "form", function(event, element) {
|
|
168
|
+
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
|
|
169
|
+
inputs.each(function(input) {
|
|
170
|
+
input.value = input.readAttribute('data-original-value');
|
|
171
|
+
input.removeAttribute('data-original-value');
|
|
172
|
+
input.disabled = false;
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
})();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
|
2
|
+
|
|
3
|
+
body, p, ol, ul, td {
|
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
|
5
|
+
font-size: 13px;
|
|
6
|
+
line-height: 18px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
pre {
|
|
10
|
+
background-color: #eee;
|
|
11
|
+
padding: 10px;
|
|
12
|
+
font-size: 11px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
a { color: #000; }
|
|
16
|
+
a:visited { color: #666; }
|
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
|
18
|
+
|
|
19
|
+
div.field, div.actions {
|
|
20
|
+
margin-bottom: 10px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#notice {
|
|
24
|
+
color: green;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.field_with_errors {
|
|
28
|
+
padding: 2px;
|
|
29
|
+
background-color: red;
|
|
30
|
+
display: table;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#error_explanation {
|
|
34
|
+
width: 450px;
|
|
35
|
+
border: 2px solid red;
|
|
36
|
+
padding: 7px;
|
|
37
|
+
padding-bottom: 0;
|
|
38
|
+
margin-bottom: 20px;
|
|
39
|
+
background-color: #f0f0f0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#error_explanation h2 {
|
|
43
|
+
text-align: left;
|
|
44
|
+
font-weight: bold;
|
|
45
|
+
padding: 5px 5px 5px 15px;
|
|
46
|
+
font-size: 12px;
|
|
47
|
+
margin: -7px;
|
|
48
|
+
margin-bottom: 0px;
|
|
49
|
+
background-color: #c00;
|
|
50
|
+
color: #fff;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#error_explanation ul li {
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
list-style: square;
|
|
56
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
|
3
|
+
|
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
|
6
|
+
require 'rails/commands'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
|
+
require 'state_pattern'
|
|
3
|
+
|
|
4
|
+
def wait(seconds)
|
|
5
|
+
seconds.downto(1) do |i|
|
|
6
|
+
print " #{i}"
|
|
7
|
+
$stdout.flush
|
|
8
|
+
sleep 1
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Stop < StatePattern::State
|
|
13
|
+
def next
|
|
14
|
+
wait 3
|
|
15
|
+
transition_to(Go)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def color
|
|
19
|
+
"Red"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Go < StatePattern::State
|
|
24
|
+
def next
|
|
25
|
+
wait 2
|
|
26
|
+
transition_to(Caution)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def color
|
|
30
|
+
"Green"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Caution < StatePattern::State
|
|
35
|
+
def next
|
|
36
|
+
wait 1
|
|
37
|
+
transition_to(Stop)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def color
|
|
41
|
+
"Amber"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class TrafficSemaphore
|
|
46
|
+
include StatePattern
|
|
47
|
+
set_initial_state Stop
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
semaphore = TrafficSemaphore.new
|
|
51
|
+
|
|
52
|
+
loop do
|
|
53
|
+
print semaphore.color
|
|
54
|
+
semaphore.next
|
|
55
|
+
puts
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
data/lib/state_pattern.rb
CHANGED
|
@@ -79,7 +79,7 @@ module StatePattern
|
|
|
79
79
|
return @current_state_instance if @current_state_instance.class == state_class
|
|
80
80
|
@current_state_instance = state_class.new(self, @current_state_instance)
|
|
81
81
|
end
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
def current_state_instance
|
|
84
84
|
set_state if @current_state_instance.nil?
|
|
85
85
|
@current_state_instance
|
|
@@ -108,3 +108,5 @@ module StatePattern
|
|
|
108
108
|
valid_transition_targets && valid_transition_targets.include?(to_state)
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
|
+
|
|
112
|
+
require 'state_pattern/active_record' if defined? ActiveRecord::Base
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module StatePattern
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.class_eval do
|
|
5
|
+
include StatePattern
|
|
6
|
+
|
|
7
|
+
after_initialize :set_state_from_db
|
|
8
|
+
def set_state_from_db
|
|
9
|
+
set_state(state_string_as_class)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#enable after_initialize callback
|
|
13
|
+
if Rails.version >= "3.0.0"
|
|
14
|
+
def self.after_initialize; end
|
|
15
|
+
else
|
|
16
|
+
def after_initialize; end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def set_state_with_active_record_attribute(state_class = nil)
|
|
20
|
+
set_state_without_active_record_attribute(state_class)
|
|
21
|
+
write_attribute(self.class.state_attribute, @current_state_instance.class.name)
|
|
22
|
+
end
|
|
23
|
+
alias_method_chain :set_state, :active_record_attribute
|
|
24
|
+
|
|
25
|
+
def state=(new_state_string)
|
|
26
|
+
set_state(state_string_as_class(new_state_string))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def state_string_as_class(state_string = @attributes[self.class.state_attribute])
|
|
30
|
+
state_string.camelize.constantize unless state_string.nil?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.state_attribute
|
|
34
|
+
@state_attribute ||= "state"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.set_state_attribute(state_attr)
|
|
38
|
+
@state_attribute = state_attr.to_s
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
data/rails/init.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'state_pattern/active_record/test_helper'
|
|
2
|
+
|
|
3
|
+
class ARButton < ActiveRecord::Base
|
|
4
|
+
class On < StatePattern::State
|
|
5
|
+
def press
|
|
6
|
+
transition_to(Off)
|
|
7
|
+
"#{stateable.button_name} is off"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Off < StatePattern::State
|
|
12
|
+
def press
|
|
13
|
+
transition_to(On)
|
|
14
|
+
"#{stateable.button_name} is on"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
include StatePattern::ActiveRecord
|
|
19
|
+
set_initial_state Off
|
|
20
|
+
valid_transitions [On, :press] => Off, [Off, :press] => On
|
|
21
|
+
|
|
22
|
+
def button_name
|
|
23
|
+
"The button"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class ARButton2 < ARButton
|
|
28
|
+
set_state_attribute :state2
|
|
29
|
+
set_initial_state ARButton::Off
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Expectations do
|
|
33
|
+
expect "ARButton::Off" do
|
|
34
|
+
ARButton.create.state
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
expect "The button is on" do
|
|
38
|
+
button = ARButton.create
|
|
39
|
+
button.press
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
expect "ARButton::On" do
|
|
43
|
+
button = ARButton.create
|
|
44
|
+
button.press
|
|
45
|
+
button.state
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
expect "The button is off" do
|
|
49
|
+
button = ARButton.create
|
|
50
|
+
button.state = "ARButton::On"
|
|
51
|
+
button.press
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
expect "The button is off" do
|
|
55
|
+
button = ARButton.create
|
|
56
|
+
button.press
|
|
57
|
+
button.press
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
expect "ARButton::On" do
|
|
61
|
+
ARButton.create(:state => "ARButton::On").state
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
expect nil do
|
|
65
|
+
ARButton2.create.state
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
expect "ARButton::Off" do
|
|
69
|
+
ARButton2.create.state2
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'active_record'
|
|
3
|
+
|
|
4
|
+
{
|
|
5
|
+
"nulldb" => "active_record/connection_adapters/nulldb_adapter",
|
|
6
|
+
"expectations" => "expectations"
|
|
7
|
+
}.each do |gem_name, require_arg|
|
|
8
|
+
begin
|
|
9
|
+
require require_arg
|
|
10
|
+
rescue LoadError
|
|
11
|
+
puts "You need to install the #{gem_name} gem to run the tests"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#Nulldb expects Rails.root to be defined
|
|
16
|
+
class Rails
|
|
17
|
+
def self.root
|
|
18
|
+
File.dirname(__FILE__)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
ActiveRecord::Base.establish_connection :adapter => :nulldb, :schema => 'schema.rb'
|
|
23
|
+
|
|
24
|
+
require 'rails/init'
|
|
25
|
+
require 'state_pattern/active_record'
|