state_pattern 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +188 -6
  3. data/Rakefile +0 -58
  4. data/examples/rails_2_3_8_button_example/README +243 -0
  5. data/examples/rails_2_3_8_button_example/Rakefile +10 -0
  6. data/examples/rails_2_3_8_button_example/app/controllers/application_controller.rb +2 -0
  7. data/examples/rails_2_3_8_button_example/app/controllers/buttons_controller.rb +18 -0
  8. data/examples/rails_2_3_8_button_example/app/helpers/application_helper.rb +3 -0
  9. data/examples/rails_2_3_8_button_example/app/models/button.rb +4 -0
  10. data/examples/rails_2_3_8_button_example/app/models/button/off.rb +7 -0
  11. data/examples/rails_2_3_8_button_example/app/models/button/on.rb +8 -0
  12. data/examples/rails_2_3_8_button_example/app/views/buttons/show.html.erb +9 -0
  13. data/examples/rails_2_3_8_button_example/app/views/layouts/application.html.erb +12 -0
  14. data/examples/rails_2_3_8_button_example/config/boot.rb +110 -0
  15. data/examples/rails_2_3_8_button_example/config/database.yml +22 -0
  16. data/examples/rails_2_3_8_button_example/config/environment.rb +41 -0
  17. data/examples/rails_2_3_8_button_example/config/environments/development.rb +17 -0
  18. data/examples/rails_2_3_8_button_example/config/environments/production.rb +28 -0
  19. data/examples/rails_2_3_8_button_example/config/environments/test.rb +28 -0
  20. data/examples/rails_2_3_8_button_example/config/initializers/backtrace_silencers.rb +7 -0
  21. data/examples/rails_2_3_8_button_example/config/initializers/cookie_verification_secret.rb +7 -0
  22. data/examples/rails_2_3_8_button_example/config/initializers/inflections.rb +10 -0
  23. data/examples/rails_2_3_8_button_example/config/initializers/mime_types.rb +5 -0
  24. data/examples/rails_2_3_8_button_example/config/initializers/new_rails_defaults.rb +21 -0
  25. data/examples/rails_2_3_8_button_example/config/initializers/session_store.rb +15 -0
  26. data/examples/rails_2_3_8_button_example/config/locales/en.yml +5 -0
  27. data/examples/rails_2_3_8_button_example/config/routes.rb +4 -0
  28. data/examples/rails_2_3_8_button_example/db/development.sqlite3 +0 -0
  29. data/examples/rails_2_3_8_button_example/db/migrate/20101009073737_create_buttons.rb +13 -0
  30. data/examples/rails_2_3_8_button_example/db/schema.rb +20 -0
  31. data/examples/rails_2_3_8_button_example/db/seeds.rb +7 -0
  32. data/examples/rails_2_3_8_button_example/db/test.sqlite3 +0 -0
  33. data/examples/rails_2_3_8_button_example/doc/README_FOR_APP +2 -0
  34. data/examples/rails_2_3_8_button_example/public/images/rails.png +0 -0
  35. data/examples/rails_2_3_8_button_example/public/javascripts/application.js +2 -0
  36. data/examples/rails_2_3_8_button_example/public/javascripts/controls.js +963 -0
  37. data/examples/rails_2_3_8_button_example/public/javascripts/dragdrop.js +973 -0
  38. data/examples/rails_2_3_8_button_example/public/javascripts/effects.js +1128 -0
  39. data/examples/rails_2_3_8_button_example/public/javascripts/prototype.js +4320 -0
  40. data/examples/rails_2_3_8_button_example/public/javascripts/rails.js +175 -0
  41. data/examples/rails_2_3_8_button_example/script/about +4 -0
  42. data/examples/rails_2_3_8_button_example/script/console +3 -0
  43. data/examples/rails_2_3_8_button_example/script/dbconsole +3 -0
  44. data/examples/rails_2_3_8_button_example/script/destroy +3 -0
  45. data/examples/rails_2_3_8_button_example/script/generate +3 -0
  46. data/examples/rails_2_3_8_button_example/script/performance/benchmarker +3 -0
  47. data/examples/rails_2_3_8_button_example/script/performance/profiler +3 -0
  48. data/examples/rails_2_3_8_button_example/script/plugin +3 -0
  49. data/examples/rails_2_3_8_button_example/script/runner +3 -0
  50. data/examples/rails_2_3_8_button_example/script/server +3 -0
  51. data/examples/rails_3_button_example/Gemfile +31 -0
  52. data/examples/rails_3_button_example/Gemfile.lock +75 -0
  53. data/examples/rails_3_button_example/Rakefile +7 -0
  54. data/examples/rails_3_button_example/app/controllers/application_controller.rb +3 -0
  55. data/examples/rails_3_button_example/app/controllers/buttons_controller.rb +13 -0
  56. data/examples/rails_3_button_example/app/models/button.rb +4 -0
  57. data/examples/rails_3_button_example/app/models/button/off.rb +7 -0
  58. data/examples/rails_3_button_example/app/models/button/on.rb +8 -0
  59. data/examples/rails_3_button_example/app/views/buttons/show.html.erb +9 -0
  60. data/examples/rails_3_button_example/app/views/layouts/application.html.erb +13 -0
  61. data/examples/rails_3_button_example/config.ru +4 -0
  62. data/examples/rails_3_button_example/config/application.rb +42 -0
  63. data/examples/rails_3_button_example/config/boot.rb +13 -0
  64. data/examples/rails_3_button_example/config/database.yml +22 -0
  65. data/examples/rails_3_button_example/config/environment.rb +5 -0
  66. data/examples/rails_3_button_example/config/environments/development.rb +26 -0
  67. data/examples/rails_3_button_example/config/initializers/backtrace_silencers.rb +7 -0
  68. data/examples/rails_3_button_example/config/initializers/inflections.rb +10 -0
  69. data/examples/rails_3_button_example/config/initializers/mime_types.rb +5 -0
  70. data/examples/rails_3_button_example/config/initializers/secret_token.rb +7 -0
  71. data/examples/rails_3_button_example/config/initializers/session_store.rb +8 -0
  72. data/examples/rails_3_button_example/config/locales/en.yml +5 -0
  73. data/examples/rails_3_button_example/config/routes.rb +5 -0
  74. data/examples/rails_3_button_example/db/development.sqlite3 +0 -0
  75. data/examples/rails_3_button_example/db/migrate/20101009052900_create_buttons.rb +13 -0
  76. data/examples/rails_3_button_example/db/schema.rb +21 -0
  77. data/examples/rails_3_button_example/db/test.sqlite3 +0 -0
  78. data/examples/rails_3_button_example/public/javascripts/application.js +2 -0
  79. data/examples/rails_3_button_example/public/javascripts/prototype.js +6001 -0
  80. data/examples/rails_3_button_example/public/javascripts/rails.js +175 -0
  81. data/examples/rails_3_button_example/public/stylesheets/scaffold.css +56 -0
  82. data/examples/rails_3_button_example/script/rails +6 -0
  83. data/examples/semaphore.rb +58 -0
  84. data/lib/state_pattern.rb +3 -1
  85. data/lib/state_pattern/active_record.rb +44 -0
  86. data/rails/init.rb +3 -0
  87. data/test/state_pattern/active_record/active_record_test.rb +71 -0
  88. data/test/state_pattern/active_record/schema.rb +7 -0
  89. data/test/state_pattern/active_record/test_helper.rb +25 -0
  90. data/test/test_helper.rb +1 -0
  91. metadata +204 -24
  92. data/VERSION +0 -1
  93. 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,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ $LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
4
+ require 'commands/about'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/dbconsole'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/benchmarker'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/profiler'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/plugin'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/runner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/server'
@@ -0,0 +1,31 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '3.0.0'
4
+ gem 'state_pattern', '1.3.0'
5
+
6
+ # Bundle edge Rails instead:
7
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
8
+
9
+ gem 'sqlite3-ruby', :require => 'sqlite3'
10
+
11
+ # Use unicorn as the web server
12
+ # gem 'unicorn'
13
+
14
+ # Deploy with Capistrano
15
+ # gem 'capistrano'
16
+
17
+ # To use debugger
18
+ # gem 'ruby-debug'
19
+
20
+ # Bundle the extra gems:
21
+ # gem 'bj'
22
+ # gem 'nokogiri'
23
+ # gem 'sqlite3-ruby', :require => 'sqlite3'
24
+ # gem 'aws-s3', :require => 'aws/s3'
25
+
26
+ # Bundle gems for the local environment. Make sure to
27
+ # put test-only gems in this group so their generators
28
+ # and rake tasks are available in development mode:
29
+ # group :development, :test do
30
+ # gem 'webrat'
31
+ # end
@@ -0,0 +1,75 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.0)
6
+ actionpack (= 3.0.0)
7
+ mail (~> 2.2.5)
8
+ actionpack (3.0.0)
9
+ activemodel (= 3.0.0)
10
+ activesupport (= 3.0.0)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.4.1)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.12)
16
+ rack-test (~> 0.5.4)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.0)
19
+ activesupport (= 3.0.0)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.4.1)
22
+ activerecord (3.0.0)
23
+ activemodel (= 3.0.0)
24
+ activesupport (= 3.0.0)
25
+ arel (~> 1.0.0)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.0)
28
+ activemodel (= 3.0.0)
29
+ activesupport (= 3.0.0)
30
+ activesupport (3.0.0)
31
+ arel (1.0.1)
32
+ activesupport (~> 3.0.0)
33
+ builder (2.1.2)
34
+ erubis (2.6.6)
35
+ abstract (>= 1.0.0)
36
+ i18n (0.4.1)
37
+ mail (2.2.7)
38
+ activesupport (>= 2.3.6)
39
+ mime-types
40
+ treetop (>= 1.4.5)
41
+ mime-types (1.16)
42
+ polyglot (0.3.1)
43
+ rack (1.2.1)
44
+ rack-mount (0.6.13)
45
+ rack (>= 1.0.0)
46
+ rack-test (0.5.6)
47
+ rack (>= 1.0)
48
+ rails (3.0.0)
49
+ actionmailer (= 3.0.0)
50
+ actionpack (= 3.0.0)
51
+ activerecord (= 3.0.0)
52
+ activeresource (= 3.0.0)
53
+ activesupport (= 3.0.0)
54
+ bundler (~> 1.0.0)
55
+ railties (= 3.0.0)
56
+ railties (3.0.0)
57
+ actionpack (= 3.0.0)
58
+ activesupport (= 3.0.0)
59
+ rake (>= 0.8.4)
60
+ thor (~> 0.14.0)
61
+ rake (0.8.7)
62
+ sqlite3-ruby (1.3.1)
63
+ state_pattern (1.3.0)
64
+ thor (0.14.3)
65
+ treetop (1.4.8)
66
+ polyglot (>= 0.3.1)
67
+ tzinfo (0.3.23)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ rails (= 3.0.0)
74
+ sqlite3-ruby
75
+ state_pattern (= 1.3.0)
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
+
7
+ ButtonExample::Application.load_tasks
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,13 @@
1
+ class ButtonsController < ApplicationController
2
+ before_filter do
3
+ @button = Button.first || Button.create!
4
+ end
5
+
6
+ def show
7
+ end
8
+
9
+ def push
10
+ flash[:notice] = @button.push!
11
+ redirect_to button_path
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ class Button < ActiveRecord::Base
2
+ include StatePattern::ActiveRecord
3
+ set_initial_state On
4
+ end
@@ -0,0 +1,7 @@
1
+ class Button::Off < StatePattern::State
2
+ def push!
3
+ transition_to(Button::On)
4
+ stateable.save!
5
+ "I am turned on :)"
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ class Button::On < StatePattern::State
2
+ def push!
3
+ transition_to(Button::Off)
4
+ stateable.save!
5
+ "I am turned off :("
6
+ end
7
+ end
8
+
@@ -0,0 +1,9 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <p>
4
+ <b>State:</b>
5
+ <%= @button.state %>
6
+ </p>
7
+
8
+
9
+ <%= link_to 'Push', push_button_path, :method => :put %> |
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Button example</title>
5
+ <%= javascript_include_tag "prototype", "rails" %>
6
+ <%= csrf_meta_tag %>
7
+ </head>
8
+ <body>
9
+
10
+ <%= yield %>
11
+
12
+ </body>
13
+ </html>
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run ButtonExample::Application
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'rails/all'
4
+
5
+ # If you have a Gemfile, require the gems listed there, including any gems
6
+ # you've limited to :test, :development, or :production.
7
+ Bundler.require(:default, Rails.env) if defined?(Bundler)
8
+
9
+ module ButtonExample
10
+ class Application < Rails::Application
11
+ # Settings in config/environments/* take precedence over those specified here.
12
+ # Application configuration should go into files in config/initializers
13
+ # -- all .rb files in that directory are automatically loaded.
14
+
15
+ # Custom directories with classes and modules you want to be autoloadable.
16
+ # config.autoload_paths += %W(#{config.root}/extras)
17
+
18
+ # Only load the plugins named here, in the order given (default is alphabetical).
19
+ # :all can be used as a placeholder for all plugins not explicitly named.
20
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
21
+
22
+ # Activate observers that should always be running.
23
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
24
+
25
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
26
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
27
+ # config.time_zone = 'Central Time (US & Canada)'
28
+
29
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
30
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
31
+ # config.i18n.default_locale = :de
32
+
33
+ # JavaScript files you want as :defaults (application.js is always included).
34
+ # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
35
+
36
+ # Configure the default encoding used in templates for Ruby 1.9.
37
+ config.encoding = "utf-8"
38
+
39
+ # Configure sensitive parameters which will be filtered from the log file.
40
+ config.filter_parameters += [:password]
41
+ end
42
+ end