turkee_rails4 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +27 -0
- data/.travis.yml +8 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +121 -0
- data/Guardfile +12 -0
- data/LICENSE +20 -0
- data/README.rdoc +205 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/generators/turkee/templates/add_completed_tasks.rb.erb +17 -0
- data/lib/generators/turkee/templates/add_expired.rb.erb +15 -0
- data/lib/generators/turkee/templates/add_hit_duration.rb.erb +15 -0
- data/lib/generators/turkee/templates/add_imported_assignment_details.rb.erb +33 -0
- data/lib/generators/turkee/templates/create_turkee_study.rb.erb +18 -0
- data/lib/generators/turkee/templates/turkee.rb +8 -0
- data/lib/generators/turkee/templates/turkee_imported_assignments.rb.erb +16 -0
- data/lib/generators/turkee/templates/turkee_migration.rb.erb +25 -0
- data/lib/generators/turkee/turkee_generator.rb +51 -0
- data/lib/helpers/turkee_forms_helper.rb +69 -0
- data/lib/models/turkee_imported_assignment.rb +15 -0
- data/lib/models/turkee_study.rb +11 -0
- data/lib/models/turkee_task.rb +259 -0
- data/lib/tasks/turkee.rb +29 -0
- data/lib/turkee.rb +8 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +5 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/surveys_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/survey.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +19 -0
- data/spec/dummy/config/application.rb +41 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +26 -0
- data/spec/dummy/config/environments/production.rb +54 -0
- data/spec/dummy/config/environments/test.rb +38 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +61 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +23 -0
- data/spec/dummy/db/migrate/20120819164528_add_association_with_class_name.rb +12 -0
- data/spec/dummy/db/migrate/20130203095901_create_company.rb +14 -0
- data/spec/dummy/db/schema.rb +45 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/tmp/cache/.gitkeep +0 -0
- data/spec/factories/survey_factory.rb +7 -0
- data/spec/factories/turkee_task_factory.rb +21 -0
- data/spec/helpers/turkee_forms_helper_spec.rb +75 -0
- data/spec/models/turkee_study_spec.rb +19 -0
- data/spec/models/turkee_task_spec.rb +146 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +89 -0
- data/turkee.gemspec +59 -0
- metadata +232 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
class TurkeeGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
# Implement the required interface for Rails::Generators::Migration.
|
8
|
+
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
9
|
+
def self.next_migration_number(dirname)
|
10
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
11
|
+
end
|
12
|
+
|
13
|
+
source_root File.expand_path("../templates", __FILE__)
|
14
|
+
|
15
|
+
desc "Creates initializer and migrations."
|
16
|
+
|
17
|
+
def create_migrations
|
18
|
+
migration_template "turkee_migration.rb.erb", "db/migrate/create_turkee_tasks.rb"
|
19
|
+
|
20
|
+
# Need this sleep so that we don't get the same migration timestamp for both migrations
|
21
|
+
sleep 1
|
22
|
+
|
23
|
+
migration_template "turkee_imported_assignments.rb.erb", "db/migrate/create_turkee_imported_assignments.rb"
|
24
|
+
|
25
|
+
sleep 1
|
26
|
+
|
27
|
+
migration_template "add_completed_tasks.rb.erb", "db/migrate/add_completed_tasks.rb"
|
28
|
+
|
29
|
+
sleep 1
|
30
|
+
|
31
|
+
migration_template "add_imported_assignment_details.rb.erb", "db/migrate/add_imported_assignment_details.rb"
|
32
|
+
|
33
|
+
sleep 1
|
34
|
+
|
35
|
+
migration_template "add_hit_duration.rb.erb", "db/migrate/add_hit_duration.rb"
|
36
|
+
|
37
|
+
sleep 1
|
38
|
+
|
39
|
+
migration_template "add_expired.rb.erb", "db/migrate/add_expired.rb"
|
40
|
+
|
41
|
+
sleep 1
|
42
|
+
|
43
|
+
migration_template "create_turkee_study.rb.erb", "db/migrate/create_turkee_study.rb"
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_initializer
|
48
|
+
template "turkee.rb", "config/initializers/turkee.rb"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Turkee
|
2
|
+
|
3
|
+
module TurkeeFormHelper
|
4
|
+
def turkee_form_for(record, params, options = {}, &proc)
|
5
|
+
raise ArgumentError, "turkee_form_for now requires that you pass in the entire params hash, instead of just the assignmentId value. " unless params.is_a?(Hash)
|
6
|
+
|
7
|
+
options.merge!({:url => mturk_url})
|
8
|
+
|
9
|
+
capture do
|
10
|
+
form_for record, options do |f|
|
11
|
+
params.each do |k,v|
|
12
|
+
unless ['action','controller'].include?(k) || !v.is_a?(String)
|
13
|
+
concat hidden_field_tag(k, v)
|
14
|
+
cookies[k] = v
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
['assignmentId', 'workerId', 'hitId'].each do |k|
|
19
|
+
concat hidden_field_tag(k, cookies[k]) if !params.has_key?(k) && cookies.has_key?(k)
|
20
|
+
end
|
21
|
+
|
22
|
+
concat(capture(f, &proc))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def turkee_study(id = nil)
|
28
|
+
task = id.nil? ? Turkee::TurkeeTask.last : Turkee::TurkeeTask.find(id)
|
29
|
+
study = Turkee::TurkeeStudy.new
|
30
|
+
disabled = Turkee::TurkeeFormHelper::disable_form_fields?(params[:assignmentId])
|
31
|
+
|
32
|
+
if task.present?
|
33
|
+
style = "position: fixed; top: 120px; right: 30px; color: #FFF;"
|
34
|
+
style << "width: 400px; height: 375px; z-index: 100; padding: 10px;"
|
35
|
+
style << "background-color: rgba(0,0,0, 0.5); border: 1px solid #000;"
|
36
|
+
|
37
|
+
div_for(task, :style => style) do
|
38
|
+
capture do
|
39
|
+
concat content_tag(:h3, "DIRECTIONS", :style => 'text-align: right; color:#FF0000;')
|
40
|
+
concat task.hit_description.html_safe
|
41
|
+
concat '<hr/>'.html_safe
|
42
|
+
concat(turkee_form_for(study, params) do |f|
|
43
|
+
concat f.label(:feedback, "Feedback?:")
|
44
|
+
concat f.text_area(:feedback, :rows => 3, :disabled => disabled)
|
45
|
+
concat f.label(:gold_response, "Enter the fourth word from your above feedback :")
|
46
|
+
concat f.text_field(:gold_response, :disabled => disabled)
|
47
|
+
concat f.hidden_field(:turkee_task_id, :value => task.id)
|
48
|
+
concat '<br/>'.html_safe
|
49
|
+
concat f.submit('Submit', :disabled => disabled)
|
50
|
+
end)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the external Mechanical Turk url used to post form data based on whether RTurk is cofigured
|
57
|
+
# for sandbox use or not.
|
58
|
+
def mturk_url
|
59
|
+
RTurk.sandbox? ? "https://workersandbox.mturk.com/mturk/externalSubmit" : "https://www.mturk.com/mturk/externalSubmit"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns whether the form fields should be disabled or not (based on the assignment_id)
|
63
|
+
def self.disable_form_fields?(assignment)
|
64
|
+
assignment_id = assignment.is_a?(Hash) ? assignment[:assignmentId] : assignment
|
65
|
+
(assignment_id.nil? || assignment_id == 'ASSIGNMENT_ID_NOT_AVAILABLE')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Turkee
|
4
|
+
class TurkeeImportedAssignment < ActiveRecord::Base
|
5
|
+
attr_accessible :assignment_id, :turkee_task_id, :worker_id, :result_id if ActiveRecord::VERSION::MAJOR < 4
|
6
|
+
|
7
|
+
def self.record_imported_assignment(assignment, result, turk)
|
8
|
+
TurkeeImportedAssignment.create!(:assignment_id => assignment.id,
|
9
|
+
:turkee_task_id => turk.id,
|
10
|
+
:worker_id => assignment.worker_id,
|
11
|
+
:result_id => result.id)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Turkee
|
2
|
+
class TurkeeStudy < ActiveRecord::Base
|
3
|
+
GOLD_RESPONSE_INDEX = 3
|
4
|
+
attr_accessible :turkee_task_id, :feedback, :gold_response if ActiveRecord::VERSION::MAJOR < 4
|
5
|
+
|
6
|
+
def approve?
|
7
|
+
words = feedback.split(/\W+/)
|
8
|
+
gold_response.present? ? (gold_response == words[GOLD_RESPONSE_INDEX]) : true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'socket'
|
3
|
+
require 'rturk'
|
4
|
+
require 'lockfile'
|
5
|
+
require 'active_record'
|
6
|
+
require "active_support/core_ext/object/to_query"
|
7
|
+
require 'action_controller'
|
8
|
+
|
9
|
+
module Turkee
|
10
|
+
|
11
|
+
class TurkeeTask < ActiveRecord::Base
|
12
|
+
attr_accessible :sandbox, :hit_title, :hit_description, :hit_reward, :hit_num_assignments, :hit_lifetime, :hit_duration,
|
13
|
+
:form_url, :hit_url, :hit_id, :task_type, :complete if ActiveRecord::VERSION::MAJOR < 4
|
14
|
+
|
15
|
+
HIT_FRAMEHEIGHT = 1000
|
16
|
+
|
17
|
+
scope :unprocessed_hits, lambda { where('complete = ? AND sandbox = ?', false, RTurk.sandbox?) }
|
18
|
+
|
19
|
+
# Use this method to go out and retrieve the data for all of the posted Turk Tasks.
|
20
|
+
# Each specific TurkeeTask object (determined by task_type field) is in charge of
|
21
|
+
# accepting/rejecting the assignment and importing the data into their respective tables.
|
22
|
+
def self.process_hits(turkee_task = nil)
|
23
|
+
|
24
|
+
begin
|
25
|
+
# Using a lockfile to prevent multiple calls to Amazon.
|
26
|
+
Lockfile.new('/tmp/turk_processor.lock', :max_age => 3600, :retries => 10) do
|
27
|
+
|
28
|
+
turks = task_items(turkee_task)
|
29
|
+
|
30
|
+
turks.each do |turk|
|
31
|
+
hit = RTurk::Hit.new(turk.hit_id)
|
32
|
+
|
33
|
+
callback_models = Set.new
|
34
|
+
hit.assignments.each do |assignment|
|
35
|
+
next unless submitted?(assignment.status)
|
36
|
+
next if assignment_exists?(assignment)
|
37
|
+
|
38
|
+
model, param_hash = map_imported_values(assignment, turk.task_type)
|
39
|
+
next if model.nil?
|
40
|
+
|
41
|
+
callback_models << model
|
42
|
+
|
43
|
+
result = save_imported_values(model, param_hash)
|
44
|
+
|
45
|
+
# If there's a custom approve? method, see if we should approve the submitted assignment
|
46
|
+
# otherwise just approve it by default
|
47
|
+
turk.process_result(assignment, result)
|
48
|
+
|
49
|
+
TurkeeImportedAssignment.record_imported_assignment(assignment, result, turk)
|
50
|
+
end
|
51
|
+
|
52
|
+
turk.set_expired?(callback_models) if !turk.set_complete?(hit, callback_models)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
rescue Lockfile::MaxTriesLockError => e
|
56
|
+
logger.info "TurkTask.process_hits is already running or the lockfile /tmp/turk_processor.lock exists from an improperly shutdown previous process. Exiting method call."
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.save_imported_values(model, param_hash)
|
62
|
+
key = model.to_s.underscore.gsub('/','_') # Namespaced model will come across as turkee/turkee_study,
|
63
|
+
# we must translate to turkee_turkee_study"
|
64
|
+
model.create(param_hash[key])
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a new Mechanical Turk task on AMZN with the given title, desc, etc
|
68
|
+
def self.create_hit(host, hit_title, hit_description, typ, num_assignments, reward, lifetime,
|
69
|
+
duration = nil, qualifications = {}, params = {}, opts = {})
|
70
|
+
model = typ.to_s.constantize
|
71
|
+
f_url = build_url(host, model, params, opts)
|
72
|
+
|
73
|
+
h = RTurk::Hit.create(:title => hit_title) do |hit|
|
74
|
+
hit.max_assignments = num_assignments if hit.respond_to?(:max_assignments)
|
75
|
+
hit.assignments = num_assignments if hit.respond_to?(:assignments)
|
76
|
+
|
77
|
+
hit.description = hit_description
|
78
|
+
hit.reward = reward
|
79
|
+
hit.lifetime = lifetime.to_i.days.seconds.to_i
|
80
|
+
hit.duration = duration.to_i.hours.seconds.to_i if duration
|
81
|
+
hit.question(f_url, :frame_height => HIT_FRAMEHEIGHT)
|
82
|
+
unless qualifications.empty?
|
83
|
+
qualifications.each do |key, value|
|
84
|
+
hit.qualifications.add key, value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
TurkeeTask.create(:sandbox => RTurk.sandbox?,
|
90
|
+
:hit_title => hit_title, :hit_description => hit_description,
|
91
|
+
:hit_reward => reward.to_f, :hit_num_assignments => num_assignments.to_i,
|
92
|
+
:hit_lifetime => lifetime, :hit_duration => duration,
|
93
|
+
:form_url => f_url, :hit_url => h.url,
|
94
|
+
:hit_id => h.id, :task_type => typ,
|
95
|
+
:complete => false)
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
##########################################################################################################
|
100
|
+
# DON'T PUSH THIS BUTTON UNLESS YOU MEAN IT. :)
|
101
|
+
def self.clear_all_turks(force = false)
|
102
|
+
# Do NOT execute this function if we're in production mode
|
103
|
+
raise "You can only clear turks in the sandbox/development environment unless you pass 'true' for the force flag." if Rails.env == 'production' && !force
|
104
|
+
|
105
|
+
hits = RTurk::Hit.all
|
106
|
+
|
107
|
+
logger.info "#{hits.size} reviewable hits. \n"
|
108
|
+
|
109
|
+
unless hits.empty?
|
110
|
+
logger.info "Approving all assignments and disposing of each hit."
|
111
|
+
|
112
|
+
hits.each do |hit|
|
113
|
+
begin
|
114
|
+
hit.expire!
|
115
|
+
hit.assignments.each do |assignment|
|
116
|
+
logger.info "Assignment status : #{assignment.status}"
|
117
|
+
assignment.approve!('__clear_all_turks__approved__') if assignment.status == 'Submitted'
|
118
|
+
end
|
119
|
+
|
120
|
+
turkee_task = TurkeeTask.where(hit_id: hit.id).first
|
121
|
+
turkee_task.complete_task if turkee_task.present?
|
122
|
+
|
123
|
+
hit.dispose!
|
124
|
+
rescue Exception => e
|
125
|
+
# Probably a service unavailable
|
126
|
+
logger.error "Exception : #{e.to_s}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def complete_task
|
134
|
+
self.complete = true
|
135
|
+
save!
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_complete?(hit, models)
|
139
|
+
if completed_assignments?
|
140
|
+
hit.dispose!
|
141
|
+
complete_task
|
142
|
+
initiate_callback(:hit_complete, models)
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
146
|
+
false
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_expired?(models)
|
150
|
+
if expired?
|
151
|
+
self.expired = true
|
152
|
+
save!
|
153
|
+
initiate_callback(:hit_expired, models)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def initiate_callback(method, models)
|
158
|
+
models.each { |model| model.send(method, self) if model.respond_to?(method) }
|
159
|
+
end
|
160
|
+
|
161
|
+
def process_result(assignment, result)
|
162
|
+
if result.errors.size > 0
|
163
|
+
logger.info "Errors : #{result.inspect}"
|
164
|
+
assignment.reject!('Failed to enter proper data.')
|
165
|
+
elsif result.respond_to?(:approve?)
|
166
|
+
logger.debug "Approving : #{result.inspect}"
|
167
|
+
self.increment_complete_assignments
|
168
|
+
result.approve? ? assignment.approve!('') : assignment.reject!('Rejected criteria.')
|
169
|
+
else
|
170
|
+
self.increment_complete_assignments
|
171
|
+
assignment.approve!('')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def increment_complete_assignments
|
176
|
+
raise "Missing :completed_assignments attribute. Please upgrade Turkee to the most recent version." unless respond_to?(:completed_assignments)
|
177
|
+
|
178
|
+
self.completed_assignments += 1
|
179
|
+
save
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def logger
|
185
|
+
@logger ||= Logger.new($stderr)
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.map_imported_values(assignment, default_type)
|
189
|
+
params = assignment_params(assignment.answers)
|
190
|
+
param_hash = Rack::Utils.parse_nested_query(params)
|
191
|
+
|
192
|
+
model = find_model(param_hash)
|
193
|
+
model = default_type.constantize if model.nil?
|
194
|
+
|
195
|
+
return model, param_hash
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.assignment_exists?(assignment)
|
199
|
+
TurkeeImportedAssignment.find_by_assignment_id(assignment.id).present?
|
200
|
+
end
|
201
|
+
|
202
|
+
def completed_assignments?
|
203
|
+
completed_assignments == hit_num_assignments
|
204
|
+
end
|
205
|
+
|
206
|
+
def expired?
|
207
|
+
Time.now >= (created_at + hit_lifetime.days)
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.task_items(turkee_task)
|
211
|
+
turkee_task.nil? ? TurkeeTask.unprocessed_hits : Array.new << turkee_task
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.submitted?(status)
|
215
|
+
(status == 'Submitted')
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.assignment_params(answers)
|
219
|
+
answers.to_query
|
220
|
+
end
|
221
|
+
|
222
|
+
# Method looks at the parameter and attempts to find an ActiveRecord model
|
223
|
+
# in the current app that would match the properties of one of the nested hashes
|
224
|
+
# x = {:submit = 'Create', :iteration_vote => {:iteration_id => 1}}
|
225
|
+
# The above _should_ return an IterationVote model
|
226
|
+
def self.find_model(param_hash)
|
227
|
+
param_hash.each do |k, v|
|
228
|
+
if v.is_a?(Hash)
|
229
|
+
model = k.to_s.camelize.constantize rescue next
|
230
|
+
return model if model.descends_from_active_record? rescue next
|
231
|
+
end
|
232
|
+
end
|
233
|
+
nil
|
234
|
+
end
|
235
|
+
|
236
|
+
# Returns custom URL if opts[:form_url] is specified. Otherwise, builds the default url from the model's :new route
|
237
|
+
def self.build_url(host, model, params, opts)
|
238
|
+
if opts[:form_url]
|
239
|
+
full_url(opts[:form_url], params)
|
240
|
+
else
|
241
|
+
form_url(host, model, params)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns the default url of the model's :new route
|
246
|
+
def self.form_url(host, typ, params = {})
|
247
|
+
@app ||= ActionDispatch::Integration::Session.new(Rails.application)
|
248
|
+
url = (host + @app.send("new_#{typ.to_s.underscore}_path"))
|
249
|
+
full_url(url, params)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Appends params to the url as a query string
|
253
|
+
def self.full_url(u, params)
|
254
|
+
url = u
|
255
|
+
url = "#{u}?#{params.to_query}" unless params.empty?
|
256
|
+
url
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
data/lib/tasks/turkee.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'turkee'
|
3
|
+
|
4
|
+
namespace :turkee do
|
5
|
+
desc "Post your form to Mechanical Turk (HIT). Task takes the application's host URL, HIT title, HIT description, model name, number of responses, reward for each response, number of days the HIT should be valid, and number of hours a worker has to complete the HIT."
|
6
|
+
task :post_hit, [:host, :title, :description, :model, :num_assignments, :reward, :lifetime] => :environment do |t, args|
|
7
|
+
hit = Turkee::TurkeeTask.create_hit(args[:host],args[:title], args[:description], args[:model],
|
8
|
+
args[:num_assignments], args[:reward], args[:lifetime])
|
9
|
+
puts "Hit created : #{hit.hit_url}"
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Retrieve all results from Mechanical Turk for all open HITs."
|
13
|
+
task :get_all_results => :environment do
|
14
|
+
Turkee::TurkeeTask.process_hits
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Create a usability study. Task takes the application's full url, HIT title, HIT description, model name, number of responses, reward for each response, number of days the HIT should be valid, and number of hours a worker has to complete the HIT."
|
18
|
+
task :create_study, [:url, :title, :description, :num_assignments, :reward, :lifetime] => :environment do |t, args|
|
19
|
+
qualifications = {:approval_rate => {:gt => 70}, :country => {:eql => 'US'}}
|
20
|
+
|
21
|
+
hit = Turkee::TurkeeTask.create_hit(args[:url], args[:title], args[:description], "Turkee::TurkeeStudy",
|
22
|
+
args[:num_assignments], args[:reward], args[:lifetime],
|
23
|
+
nil, qualifications, {}, {:form_url => args[:url]})
|
24
|
+
puts
|
25
|
+
puts "Study created : #{hit.hit_url}"
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|
data/lib/turkee.rb
ADDED
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into including all the files listed below.
|
2
|
+
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
3
|
+
// be included in the compiled file accessible from http://example.com/assets/application.js
|
4
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
5
|
+
// the compiled file.
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*= require_tree .
|
7
|
+
*/
|
File without changes
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Dummy</title>
|
5
|
+
|
6
|
+
<% if params[:type] == 'prototype' %>
|
7
|
+
<%= javascript_include_tag 'prototype', 'prototype_nested_form', 'prototype_events_test' %>
|
8
|
+
<% else %>
|
9
|
+
<%= javascript_include_tag 'jquery', 'jquery_nested_form', 'jquery_events_test' %>
|
10
|
+
<% end %>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<%= yield %>
|
15
|
+
|
16
|
+
<div id="console"></div>
|
17
|
+
|
18
|
+
</body>
|
19
|
+
</html>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require 'rails/all'
|
4
|
+
|
5
|
+
Bundler.require
|
6
|
+
|
7
|
+
module Dummy
|
8
|
+
class Application < Rails::Application
|
9
|
+
# Settings in config/environments/* take precedence over those specified here.
|
10
|
+
# Application configuration should go into files in config/initializers
|
11
|
+
# -- all .rb files in that directory are automatically loaded.
|
12
|
+
|
13
|
+
# Custom directories with classes and modules you want to be autoloadable.
|
14
|
+
# config.autoload_paths += %W(#{config.root}/extras)
|
15
|
+
|
16
|
+
# Only load the plugins named here, in the order given (default is alphabetical).
|
17
|
+
# :all can be used as a placeholder for all plugins not explicitly named.
|
18
|
+
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
19
|
+
|
20
|
+
# Activate observers that should always be running.
|
21
|
+
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
22
|
+
|
23
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
24
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
25
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
26
|
+
|
27
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
28
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
29
|
+
# config.i18n.default_locale = :de
|
30
|
+
|
31
|
+
# Configure the default encoding used in templates for Ruby 1.9.
|
32
|
+
config.encoding = "utf-8"
|
33
|
+
|
34
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
35
|
+
config.filter_parameters += [:password]
|
36
|
+
|
37
|
+
# Enable the asset pipeline
|
38
|
+
config.assets.enabled = true if config.respond_to?(:assets)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
gemfile = ENV['BUNDLE_GEMFILE'] || File.expand_path('../../../../Gemfile', __FILE__)
|
4
|
+
if File.exist?(gemfile)
|
5
|
+
ENV['BUNDLE_GEMFILE'] = gemfile
|
6
|
+
require 'bundler'
|
7
|
+
Bundler.setup
|
8
|
+
end
|
9
|
+
|
10
|
+
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# SQLite version 3.x
|
2
|
+
# gem install sqlite3
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem 'sqlite3'
|
6
|
+
development:
|
7
|
+
adapter: sqlite3
|
8
|
+
database: ":memory:"
|
9
|
+
pool: 5
|
10
|
+
timeout: 5000
|
11
|
+
|
12
|
+
# Warning: The database defined as "test" will be erased and
|
13
|
+
# re-generated from your development database when you run "rake".
|
14
|
+
# Do not set this db to the same as development or production.
|
15
|
+
test:
|
16
|
+
adapter: sqlite3
|
17
|
+
database: ":memory:"
|
18
|
+
pool: 5
|
19
|
+
timeout: 5000
|
20
|
+
|
21
|
+
production:
|
22
|
+
adapter: sqlite3
|
23
|
+
database: ":memory:"
|
24
|
+
pool: 5
|
25
|
+
timeout: 5000
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the web server when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
config.eager_load = false if Rails::VERSION::MAJOR >= 4
|
10
|
+
|
11
|
+
# Show full error reports and disable caching
|
12
|
+
config.consider_all_requests_local = true
|
13
|
+
config.action_controller.perform_caching = false
|
14
|
+
|
15
|
+
# Don't care if the mailer can't send
|
16
|
+
config.action_mailer.raise_delivery_errors = false
|
17
|
+
|
18
|
+
# Print deprecation notices to the Rails logger
|
19
|
+
config.active_support.deprecation = :log
|
20
|
+
|
21
|
+
# Only use best-standards-support built into browsers
|
22
|
+
config.action_dispatch.best_standards_support = :builtin
|
23
|
+
|
24
|
+
# Do not compress assets
|
25
|
+
config.assets.compress = false if config.respond_to?(:assets)
|
26
|
+
end
|