crudify 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.
Files changed (64) hide show
  1. data/.gitignore +4 -2
  2. data/Gemfile.lock +57 -28
  3. data/README.md +121 -3
  4. data/Rakefile +3 -4
  5. data/crudify.gemspec +5 -2
  6. data/lib/crudify.rb +5 -1
  7. data/lib/crudify/base.rb +8 -7
  8. data/lib/crudify/class_methods.rb +35 -21
  9. data/lib/crudify/hook_methods.rb +30 -33
  10. data/lib/crudify/version.rb +1 -1
  11. data/test/dummy/Rakefile +7 -0
  12. data/test/dummy/app/controllers/admin/peanut_butters_controller.rb +5 -0
  13. data/test/dummy/app/controllers/application_controller.rb +3 -0
  14. data/test/dummy/app/controllers/jellies_controller.rb +7 -0
  15. data/test/dummy/app/models/jelly.rb +9 -0
  16. data/test/dummy/app/models/peanut_butter.rb +8 -0
  17. data/test/dummy/app/views/admin/peanut_butters/_fields.html.erb +4 -0
  18. data/test/dummy/app/views/admin/peanut_butters/edit.html.erb +11 -0
  19. data/test/dummy/app/views/admin/peanut_butters/index.html.erb +23 -0
  20. data/test/dummy/app/views/admin/peanut_butters/new.html.erb +11 -0
  21. data/test/dummy/app/views/admin/peanut_butters/show.html.erb +14 -0
  22. data/test/dummy/app/views/jellies/_fields.html.erb +8 -0
  23. data/test/dummy/app/views/jellies/edit.html.erb +11 -0
  24. data/test/dummy/app/views/jellies/index.html.erb +23 -0
  25. data/test/dummy/app/views/jellies/new.html.erb +11 -0
  26. data/test/dummy/app/views/jellies/show.html.erb +15 -0
  27. data/test/dummy/app/views/layouts/application.html.erb +72 -0
  28. data/test/dummy/app/views/shared/_error_messages.html.erb +9 -0
  29. data/test/dummy/config.ru +4 -0
  30. data/test/dummy/config/application.rb +45 -0
  31. data/test/dummy/config/boot.rb +10 -0
  32. data/test/dummy/config/database.yml +22 -0
  33. data/test/dummy/config/environment.rb +5 -0
  34. data/test/dummy/config/environments/development.rb +26 -0
  35. data/test/dummy/config/environments/production.rb +49 -0
  36. data/test/dummy/config/environments/test.rb +38 -0
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/dummy/config/initializers/green_eggs_and_spam.rb +2 -0
  39. data/test/dummy/config/initializers/inflections.rb +10 -0
  40. data/test/dummy/config/initializers/mime_types.rb +5 -0
  41. data/test/dummy/config/initializers/secret_token.rb +7 -0
  42. data/test/dummy/config/initializers/session_store.rb +8 -0
  43. data/test/dummy/config/routes.rb +11 -0
  44. data/test/dummy/db/migrate/20110223073415_create_jellies.rb +13 -0
  45. data/test/dummy/db/migrate/20110223073427_create_peanut_butters.rb +12 -0
  46. data/test/dummy/db/schema.rb +28 -0
  47. data/test/dummy/public/404.html +26 -0
  48. data/test/dummy/public/422.html +26 -0
  49. data/test/dummy/public/500.html +26 -0
  50. data/{log/development.log → test/dummy/public/favicon.ico} +0 -0
  51. data/test/dummy/public/javascripts/application.js +2 -0
  52. data/test/dummy/public/javascripts/controls.js +965 -0
  53. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  54. data/test/dummy/public/javascripts/effects.js +1123 -0
  55. data/test/dummy/public/javascripts/index.html +239 -0
  56. data/test/dummy/public/javascripts/prototype.js +6001 -0
  57. data/test/dummy/public/javascripts/rails.js +191 -0
  58. data/test/dummy/public/stylesheets/styles.css +126 -0
  59. data/test/dummy/script/rails +6 -0
  60. data/test/functional/jellies_controller_test.rb +55 -0
  61. data/test/helper.rb +42 -31
  62. data/test/integration/demo_test.rb +79 -0
  63. data/test/{test_controller.rb → unit/crudify_test.rb} +17 -17
  64. metadata +149 -13
@@ -0,0 +1,191 @@
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
+
176
+ Ajax.Responders.register({
177
+ onCreate: function(request) {
178
+ var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
179
+
180
+ if (csrf_meta_tag) {
181
+ var header = 'X-CSRF-Token',
182
+ token = csrf_meta_tag.readAttribute('content');
183
+
184
+ if (!request.options.requestHeaders) {
185
+ request.options.requestHeaders = {};
186
+ }
187
+ request.options.requestHeaders[header] = token;
188
+ }
189
+ }
190
+ });
191
+ })();
@@ -0,0 +1,126 @@
1
+ body {
2
+ font-family: "HelveticaNeue", Helvetica, Arial, sans-serif;
3
+ font-size: 80%;
4
+ color: #080603;
5
+ }
6
+ a {
7
+ text-decoration: none;
8
+ color: #68962c;
9
+ }
10
+
11
+ p {
12
+ margin-top: 0;
13
+ }
14
+
15
+ h4 {
16
+ margin-top: 1em;
17
+ margin-bottom: 0.5em;
18
+ }
19
+
20
+ #container {
21
+ width: 540px;
22
+ margin: 0 auto;
23
+ }
24
+
25
+ #header h1 {
26
+ margin-bottom: 0;
27
+ }
28
+ #header h2 {
29
+ margin: 0 0 1.5em 0;
30
+ font-size: 1em;
31
+ font-weight: normal;
32
+ font-style: italic;
33
+ }
34
+ #header a {
35
+ display: inline-block;
36
+ padding: 4px 10px;
37
+ background-color: #eee;
38
+ }
39
+
40
+ #content {
41
+ padding: 4px 7px;
42
+ background-color: #fafafa;
43
+ border: 1px solid #f0f0f0;
44
+ margin-bottom: 3em;
45
+ }
46
+ #content h3 {
47
+ margin-top: 0.5em;
48
+ }
49
+
50
+
51
+
52
+
53
+ hr {
54
+ border: 0;
55
+ border-bottom: 1px solid #ddd;
56
+ background: transparent;
57
+ }
58
+
59
+ pre {
60
+ padding: 4px 7px;
61
+ background-color: #fafafa;
62
+ border: 1px solid #f0f0f0;
63
+ font-family: Courier;
64
+ font-size: 14px;
65
+ }
66
+
67
+
68
+ fieldset {
69
+ border: 0;
70
+ border-top: 1px solid #ddd;
71
+ border-bottom: 1px solid #ddd;
72
+ }
73
+
74
+ label {
75
+ display: inline-block;
76
+ width: 50px;
77
+ padding-right: 5px;
78
+ text-align: right;
79
+ }
80
+
81
+ form p {
82
+ margin: 0 0 1em 0;
83
+ }
84
+
85
+ form p.action {
86
+ padding-left: 10px;
87
+ }
88
+
89
+
90
+ .flash {
91
+ padding: 10px 7px;
92
+ border-top: 1px solid #ddd;
93
+ border-bottom: 1px solid #ddd;
94
+ background-color: #fafafa;
95
+ }
96
+ #flash_notice {
97
+ color: #68962c;
98
+ border-color: #68962c;
99
+ }
100
+ #flash_error {
101
+ color: #c00e0e;
102
+ border-color: #c00e0e;
103
+ }
104
+ .flash ul.errors {
105
+ padding-left: 20px;
106
+ margin: 0.3em 0;
107
+ }
108
+
109
+
110
+ ul.items {
111
+ list-style: none;
112
+ padding: 0;
113
+ margin: 0;
114
+ }
115
+ ul.items li {
116
+ list-style: none;
117
+ margin: 0.5em;
118
+ }
119
+ ul.items li h3 {
120
+ margin: 0;
121
+ }
122
+
123
+
124
+ div.field_with_errors {
125
+ display: inline;
126
+ }
@@ -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,55 @@
1
+ require 'helper'
2
+
3
+ class JelliesControllerTest < ActionController::TestCase
4
+
5
+ should "get index" do
6
+ get :index
7
+ assert_response :success
8
+ assert_not_nil assigns(:jellies)
9
+ end
10
+
11
+ should "get new" do
12
+ get :new
13
+ assert_response :success
14
+ assert_not_nil assigns(:jelly)
15
+ end
16
+
17
+ should "post to create" do
18
+ count1 = Jelly.count
19
+ post :create, :jelly => { :title => "Controller Jelly", :name => "Controlaberry" }
20
+ assert_redirected_to jellies_path
21
+ assert_equal (count1 + 1), Jelly.count
22
+ end
23
+
24
+ context "with a jelly" do
25
+
26
+ setup do
27
+ @jelly = Jelly.last
28
+ end
29
+
30
+ should "get show" do
31
+ get :show, :id => @jelly.id
32
+ assert_response :success
33
+ assert_not_nil assigns(:jelly)
34
+ end
35
+
36
+ should "get edit" do
37
+ get :edit, :id => @jelly.id
38
+ assert_response :success
39
+ assert_not_nil assigns(:jelly)
40
+ end
41
+
42
+ should "put update" do
43
+ put :update, :id => @jelly.id, :jelly => { :title => "Updated Controller Jelly", :name => "Controlafresh" }
44
+ assert_redirected_to jellies_path
45
+ end
46
+
47
+ should "delete, destroy and maybe conquer" do
48
+ count1 = Jelly.count
49
+ delete :destroy, :id => @jelly.id
50
+ assert_redirected_to jellies_path
51
+ assert_equal (count1 - 1), Jelly.count
52
+ end
53
+
54
+ end
55
+ end
data/test/helper.rb CHANGED
@@ -1,40 +1,51 @@
1
- begin
2
- require 'rubygems'
3
- require 'bundler/setup'
4
- require 'rails/all'
5
- require 'shoulda'
6
- require 'crudify'
7
- require 'will_paginate'
8
- #require 'sqlite3'
9
- rescue LoadError => e
10
- puts "Load error!"
11
- puts e.inspect
12
- exit
13
- end
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
14
3
 
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+ require "shoulda"
15
7
 
16
- class Jelly < ActiveRecord::Base
17
- cattr_reader :per_page
18
- @@per_page = 2
19
- end
8
+ ActionMailer::Base.delivery_method = :test
9
+ ActionMailer::Base.perform_deliveries = true
10
+ ActionMailer::Base.default_url_options[:host] = "test.com"
20
11
 
21
- db = File.expand_path('../db/test.sqlite3', __FILE__)
22
- `rm #{db}` if File.exists?(db)
12
+ Rails.backtrace_cleaner.remove_silencers!
23
13
 
24
- config = { 'adapter' => 'sqlite3', 'database' => 'test/db/test.sqlite3' }
25
- sql = 'CREATE TABLE "jellies" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "name" varchar(255), "created_at" datetime, "updated_at" datetime)'
26
- ActiveRecord::Base.establish_connection(config)
27
- ActiveRecord::Base.connection.execute(sql)
14
+ # Configure capybara for integration testing
15
+ require "capybara/rails"
16
+ require "selenium/webdriver"
28
17
 
18
+ Capybara.default_driver = :selenium
29
19
 
30
- ["blackberry", "blueberry", "strawberry"].each do |jelly|
31
- Jelly.create(:title => "#{jelly.capitalize} Jelly", :name => jelly)
32
- end
20
+ # Run any available migrations
21
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
33
22
 
34
23
 
35
- class CrudifyTestController < ActionController::Base
36
-
37
- crudify :jelly
38
-
39
- end
40
24
 
25
+ # Include capybara and some extras into rails tests
26
+ module ActionController
27
+ class IntegrationTest
28
+
29
+ # turn off transactions for sqlite
30
+ self.use_transactional_fixtures = false
31
+
32
+ include Capybara
33
+
34
+ def assert_seen(text, opts={})
35
+ if opts[:within]
36
+ within(selector_for(opts[:within])) do
37
+ assert page.has_content?(text)
38
+ end
39
+ else
40
+ assert page.has_content?(text)
41
+ end
42
+ end
43
+
44
+ def assert_flash(key, text)
45
+ within("#flash_#{key}") do
46
+ assert_seen(text)
47
+ end
48
+ end
49
+
50
+ end
51
+ end