houdini 0.1.1

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 (60) hide show
  1. data/.document +11 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +122 -0
  6. data/LICENSE +20 -0
  7. data/README.markdown +59 -0
  8. data/Rakefile +35 -0
  9. data/app/controllers/houdini/postbacks_controller.rb +12 -0
  10. data/config/routes.rb +8 -0
  11. data/houdini.gemspec +25 -0
  12. data/lib/houdini/base.rb +36 -0
  13. data/lib/houdini/engine.rb +4 -0
  14. data/lib/houdini/model.rb +58 -0
  15. data/lib/houdini/task.rb +15 -0
  16. data/lib/houdini/version.rb +3 -0
  17. data/lib/houdini.rb +23 -0
  18. data/spec/controllers/houdini/postbacks_controller_spec.rb +0 -0
  19. data/spec/dummy/Rakefile +7 -0
  20. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  21. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  22. data/spec/dummy/app/models/article.rb +25 -0
  23. data/spec/dummy/app/models/post.rb +24 -0
  24. data/spec/dummy/app/models/product_review.rb +23 -0
  25. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  26. data/spec/dummy/app/views/posts/houdini_template.html.erb +6 -0
  27. data/spec/dummy/config/application.rb +51 -0
  28. data/spec/dummy/config/boot.rb +10 -0
  29. data/spec/dummy/config/database.yml +22 -0
  30. data/spec/dummy/config/environment.rb +5 -0
  31. data/spec/dummy/config/environments/development.rb +26 -0
  32. data/spec/dummy/config/environments/production.rb +49 -0
  33. data/spec/dummy/config/environments/test.rb +35 -0
  34. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/spec/dummy/config/initializers/inflections.rb +10 -0
  36. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  37. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  38. data/spec/dummy/config/initializers/session_store.rb +8 -0
  39. data/spec/dummy/config/locales/en.yml +5 -0
  40. data/spec/dummy/config/routes.rb +58 -0
  41. data/spec/dummy/config.ru +4 -0
  42. data/spec/dummy/db/migrate/001_create_posts.rb +16 -0
  43. data/spec/dummy/db/migrate/002_create_product_reviews.rb +15 -0
  44. data/spec/dummy/db/migrate/003_create_articles.rb +15 -0
  45. data/spec/dummy/public/404.html +26 -0
  46. data/spec/dummy/public/422.html +26 -0
  47. data/spec/dummy/public/500.html +26 -0
  48. data/spec/dummy/public/favicon.ico +0 -0
  49. data/spec/dummy/public/javascripts/application.js +2 -0
  50. data/spec/dummy/public/javascripts/controls.js +965 -0
  51. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  52. data/spec/dummy/public/javascripts/effects.js +1123 -0
  53. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  54. data/spec/dummy/public/javascripts/rails.js +175 -0
  55. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  56. data/spec/dummy/script/rails +6 -0
  57. data/spec/houdini_rails_spec.rb +4 -0
  58. data/spec/requests/integration_spec.rb +35 -0
  59. data/spec/spec_helper.rb +34 -0
  60. metadata +227 -0
@@ -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
+ })();
File without changes
@@ -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,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Houdini do
4
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Text Classification" do
4
+ before do
5
+ Article.delete_all
6
+ Houdini::Base.stub!(:request).and_return(["200", "{response:success}"]) # TODO: VCR
7
+ end
8
+
9
+ it "should send task to Houdini and properly receive the postback" do
10
+ p = Article.new(:original_text => 'This is incorect.')
11
+ p.stub!(:id).and_return(1)
12
+
13
+ params = {
14
+ "api_key" => Houdini.api_key,
15
+ "environment" => Houdini.environment,
16
+ "postback_url" => "http://#{Houdini.app_host}/houdini/Article/1/edit_for_grammar/postbacks",
17
+ "task_design" => "edit_for_grammar",
18
+ "task_design_version" => 1,
19
+ "task_info" => {
20
+ "original_text" => "This is incorect."
21
+ }
22
+ }.symbolize_keys
23
+
24
+ Houdini::Base.should_receive(:request).with(params)
25
+
26
+ p.save
27
+ p.reload
28
+ p.houdini_request_sent_at.to_date.should == Time.now.to_date
29
+
30
+ post "houdini/article/#{p.id}/edit_for_grammar/postbacks", {:edited_text => "This is incorrect."}.to_json
31
+
32
+ p.reload
33
+ p.edited_text.should == "This is incorrect."
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rspec/rails"
6
+
7
+ ActionMailer::Base.delivery_method = :test
8
+ ActionMailer::Base.perform_deliveries = true
9
+ ActionMailer::Base.default_url_options[:host] = "test.com"
10
+
11
+ Rails.backtrace_cleaner.remove_silencers!
12
+
13
+ # Configure capybara for integration testing
14
+ require "capybara/rails"
15
+ Capybara.default_driver = :rack_test
16
+ Capybara.default_selector = :css
17
+
18
+ # Run migrations
19
+ db_path = File.expand_path("../dummy/db/test.sqlite3/", __FILE__)
20
+ `rm #{db_path}` if File.exists?(db_path)
21
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
22
+
23
+ # Load support files
24
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
25
+
26
+ RSpec.configure do |config|
27
+ # Remove this line if you don't want RSpec's should and should_not
28
+ # methods or matchers
29
+ require 'rspec/expectations'
30
+ config.include RSpec::Matchers
31
+
32
+ # == Mock Framework
33
+ config.mock_with :rspec
34
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: houdini
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Chris Conley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-26 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 3
31
+ - 0
32
+ - 0
33
+ version: 3.0.0
34
+ prerelease: false
35
+ type: :runtime
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec-rails
39
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 27
45
+ segments:
46
+ - 2
47
+ - 5
48
+ - 0
49
+ version: 2.5.0
50
+ prerelease: false
51
+ type: :development
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: capybara
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 13
61
+ segments:
62
+ - 0
63
+ - 4
64
+ - 1
65
+ version: 0.4.1
66
+ prerelease: false
67
+ type: :development
68
+ requirement: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3-ruby
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ prerelease: false
81
+ type: :development
82
+ requirement: *id004
83
+ description: Rails 3 Engine for using the Houdini Mechanical Turk API
84
+ email: chris@houdiniapi.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files: []
90
+
91
+ files:
92
+ - .document
93
+ - .gitignore
94
+ - .rspec
95
+ - Gemfile
96
+ - Gemfile.lock
97
+ - LICENSE
98
+ - README.markdown
99
+ - Rakefile
100
+ - app/controllers/houdini/postbacks_controller.rb
101
+ - config/routes.rb
102
+ - houdini.gemspec
103
+ - lib/houdini.rb
104
+ - lib/houdini/base.rb
105
+ - lib/houdini/engine.rb
106
+ - lib/houdini/model.rb
107
+ - lib/houdini/task.rb
108
+ - lib/houdini/version.rb
109
+ - spec/controllers/houdini/postbacks_controller_spec.rb
110
+ - spec/dummy/Rakefile
111
+ - spec/dummy/app/controllers/application_controller.rb
112
+ - spec/dummy/app/helpers/application_helper.rb
113
+ - spec/dummy/app/models/article.rb
114
+ - spec/dummy/app/models/post.rb
115
+ - spec/dummy/app/models/product_review.rb
116
+ - spec/dummy/app/views/layouts/application.html.erb
117
+ - spec/dummy/app/views/posts/houdini_template.html.erb
118
+ - spec/dummy/config.ru
119
+ - spec/dummy/config/application.rb
120
+ - spec/dummy/config/boot.rb
121
+ - spec/dummy/config/database.yml
122
+ - spec/dummy/config/environment.rb
123
+ - spec/dummy/config/environments/development.rb
124
+ - spec/dummy/config/environments/production.rb
125
+ - spec/dummy/config/environments/test.rb
126
+ - spec/dummy/config/initializers/backtrace_silencers.rb
127
+ - spec/dummy/config/initializers/inflections.rb
128
+ - spec/dummy/config/initializers/mime_types.rb
129
+ - spec/dummy/config/initializers/secret_token.rb
130
+ - spec/dummy/config/initializers/session_store.rb
131
+ - spec/dummy/config/locales/en.yml
132
+ - spec/dummy/config/routes.rb
133
+ - spec/dummy/db/migrate/001_create_posts.rb
134
+ - spec/dummy/db/migrate/002_create_product_reviews.rb
135
+ - spec/dummy/db/migrate/003_create_articles.rb
136
+ - spec/dummy/public/404.html
137
+ - spec/dummy/public/422.html
138
+ - spec/dummy/public/500.html
139
+ - spec/dummy/public/favicon.ico
140
+ - spec/dummy/public/javascripts/application.js
141
+ - spec/dummy/public/javascripts/controls.js
142
+ - spec/dummy/public/javascripts/dragdrop.js
143
+ - spec/dummy/public/javascripts/effects.js
144
+ - spec/dummy/public/javascripts/prototype.js
145
+ - spec/dummy/public/javascripts/rails.js
146
+ - spec/dummy/public/stylesheets/.gitkeep
147
+ - spec/dummy/script/rails
148
+ - spec/houdini_rails_spec.rb
149
+ - spec/requests/integration_spec.rb
150
+ - spec/spec_helper.rb
151
+ has_rdoc: true
152
+ homepage: http://github.com/chrisconley/houdini-gem
153
+ licenses: []
154
+
155
+ post_install_message:
156
+ rdoc_options: []
157
+
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ hash: 3
166
+ segments:
167
+ - 0
168
+ version: "0"
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ hash: 3
175
+ segments:
176
+ - 0
177
+ version: "0"
178
+ requirements: []
179
+
180
+ rubyforge_project:
181
+ rubygems_version: 1.5.2
182
+ signing_key:
183
+ specification_version: 3
184
+ summary: Rails 3 Engine for using the Houdini Mechanical Turk API
185
+ test_files:
186
+ - spec/controllers/houdini/postbacks_controller_spec.rb
187
+ - spec/dummy/Rakefile
188
+ - spec/dummy/app/controllers/application_controller.rb
189
+ - spec/dummy/app/helpers/application_helper.rb
190
+ - spec/dummy/app/models/article.rb
191
+ - spec/dummy/app/models/post.rb
192
+ - spec/dummy/app/models/product_review.rb
193
+ - spec/dummy/app/views/layouts/application.html.erb
194
+ - spec/dummy/app/views/posts/houdini_template.html.erb
195
+ - spec/dummy/config.ru
196
+ - spec/dummy/config/application.rb
197
+ - spec/dummy/config/boot.rb
198
+ - spec/dummy/config/database.yml
199
+ - spec/dummy/config/environment.rb
200
+ - spec/dummy/config/environments/development.rb
201
+ - spec/dummy/config/environments/production.rb
202
+ - spec/dummy/config/environments/test.rb
203
+ - spec/dummy/config/initializers/backtrace_silencers.rb
204
+ - spec/dummy/config/initializers/inflections.rb
205
+ - spec/dummy/config/initializers/mime_types.rb
206
+ - spec/dummy/config/initializers/secret_token.rb
207
+ - spec/dummy/config/initializers/session_store.rb
208
+ - spec/dummy/config/locales/en.yml
209
+ - spec/dummy/config/routes.rb
210
+ - spec/dummy/db/migrate/001_create_posts.rb
211
+ - spec/dummy/db/migrate/002_create_product_reviews.rb
212
+ - spec/dummy/db/migrate/003_create_articles.rb
213
+ - spec/dummy/public/404.html
214
+ - spec/dummy/public/422.html
215
+ - spec/dummy/public/500.html
216
+ - spec/dummy/public/favicon.ico
217
+ - spec/dummy/public/javascripts/application.js
218
+ - spec/dummy/public/javascripts/controls.js
219
+ - spec/dummy/public/javascripts/dragdrop.js
220
+ - spec/dummy/public/javascripts/effects.js
221
+ - spec/dummy/public/javascripts/prototype.js
222
+ - spec/dummy/public/javascripts/rails.js
223
+ - spec/dummy/public/stylesheets/.gitkeep
224
+ - spec/dummy/script/rails
225
+ - spec/houdini_rails_spec.rb
226
+ - spec/requests/integration_spec.rb
227
+ - spec/spec_helper.rb