shared_workforce 0.1.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 +4 -0
- data/Gemfile +4 -0
- data/README.rdoc +0 -0
- data/Rakefile +13 -0
- data/lib/shared_workforce.rb +9 -0
- data/lib/shared_workforce/client.rb +34 -0
- data/lib/shared_workforce/end_point.rb +34 -0
- data/lib/shared_workforce/exceptions.rb +4 -0
- data/lib/shared_workforce/frameworks/rails.rb +13 -0
- data/lib/shared_workforce/task.rb +95 -0
- data/lib/shared_workforce/task_request.rb +27 -0
- data/lib/shared_workforce/task_response.rb +17 -0
- data/lib/shared_workforce/task_result.rb +32 -0
- data/lib/shared_workforce/version.rb +4 -0
- data/shared_workforce.gemspec +26 -0
- data/spec/.rspec +1 -0
- data/spec/client_spec.rb +16 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/task_request_spec.rb +126 -0
- data/spec/task_response_spec.rb +15 -0
- data/spec/task_result_spec.rb +40 -0
- data/spec/task_spec.rb +108 -0
- data/spec/tasks/approve_photo.rb +16 -0
- metadata +128 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
task :default => 'spec:unit'
|
7
|
+
|
8
|
+
namespace :spec do
|
9
|
+
desc "Run unit specs"
|
10
|
+
RSpec::Core::RakeTask.new('unit') do |t|
|
11
|
+
t.pattern = 'spec/**/*_spec.rb'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'shared_workforce/exceptions'
|
2
|
+
require 'shared_workforce/client'
|
3
|
+
require 'shared_workforce/version'
|
4
|
+
require 'shared_workforce/task'
|
5
|
+
require 'shared_workforce/task_request'
|
6
|
+
require 'shared_workforce/task_result'
|
7
|
+
require 'shared_workforce/task_response'
|
8
|
+
require 'shared_workforce/end_point'
|
9
|
+
require 'shared_workforce/frameworks/rails' if defined?(Rails)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class Client
|
3
|
+
|
4
|
+
@http_end_point = "http://hci.heroku.com"
|
5
|
+
@load_path = "tasks"
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :api_key
|
9
|
+
attr_accessor :load_path
|
10
|
+
attr_accessor :http_end_point
|
11
|
+
attr_accessor :callback_host
|
12
|
+
attr_accessor :callback_path
|
13
|
+
|
14
|
+
def version
|
15
|
+
SharedWorkforce::VERSION
|
16
|
+
end
|
17
|
+
|
18
|
+
def load!
|
19
|
+
Dir[File.join(load_path, "*.rb")].each do |file|
|
20
|
+
load file
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def callback_url
|
25
|
+
callback_host + '/' + callback_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def callback_path
|
29
|
+
"hci_task_result"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class EndPoint
|
3
|
+
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
if env["PATH_INFO"] =~ /^\/#{Client.callback_path}/
|
10
|
+
process_request(env)
|
11
|
+
else
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def process_request(env)
|
20
|
+
req = Rack::Request.new(env)
|
21
|
+
body = JSON.parse(req.body.read)
|
22
|
+
puts "processing task callback"
|
23
|
+
puts body.inspect
|
24
|
+
SharedWorkforce::TaskResult.new(body).process!
|
25
|
+
|
26
|
+
[ 200,
|
27
|
+
{ "Content-Type" => "text/html",
|
28
|
+
"Content-Length" => "0" },
|
29
|
+
[""]
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
if defined?(ActionController::Metal)
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer :load_hci do |app|
|
4
|
+
SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce::Client.load_path
|
5
|
+
SharedWorkforce::Client.load!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
else
|
9
|
+
Rails.configuration.after_initialize do
|
10
|
+
SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce::Client.load_path
|
11
|
+
SharedWorkforce::Client.load!
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class Task
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
attr_accessor :tasks
|
7
|
+
|
8
|
+
def tasks
|
9
|
+
@tasks ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def define(name, &block)
|
13
|
+
raise ConfigurationError, "Please set your SharedWorkforce api key with SharedWorkforce::Client.api_key = 'your-api-key-here'" unless Client.api_key
|
14
|
+
raise ConfigurationError, "Please set your callback URL with SharedWorkforce::Client.callback_host = 'www.your-domain-name.com'" unless Client.callback_host
|
15
|
+
|
16
|
+
task = self.new
|
17
|
+
task.name = name
|
18
|
+
yield task
|
19
|
+
self.tasks[name] = task
|
20
|
+
end
|
21
|
+
|
22
|
+
def request(name, options)
|
23
|
+
@tasks[name].request(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cancel(name, options)
|
27
|
+
@tasks[name].cancel(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def find(name)
|
31
|
+
self.tasks[name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear!
|
35
|
+
@tasks = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :name
|
41
|
+
attr_accessor :directions
|
42
|
+
attr_accessor :image_url
|
43
|
+
attr_accessor :answer_options
|
44
|
+
attr_accessor :answer_type
|
45
|
+
attr_accessor :responses_required
|
46
|
+
attr_accessor :replace # whether tasks with the same resource id and name should be overwritten
|
47
|
+
|
48
|
+
def replace
|
49
|
+
@replace ||= false
|
50
|
+
end
|
51
|
+
|
52
|
+
def request(options)
|
53
|
+
task_request = TaskRequest.new(self, options)
|
54
|
+
task_request.create
|
55
|
+
end
|
56
|
+
|
57
|
+
def cancel(options)
|
58
|
+
task_request = TaskRequest.new(self, options)
|
59
|
+
task_request.cancel
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_hash
|
63
|
+
{
|
64
|
+
:name=>name,
|
65
|
+
:directions => directions,
|
66
|
+
:image_url => image_url,
|
67
|
+
:answer_options => answer_options,
|
68
|
+
:responses_required => responses_required,
|
69
|
+
:answer_type => answer_type.to_s,
|
70
|
+
:callback_url => Client.callback_url,
|
71
|
+
:replace => replace
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# Callbacks
|
76
|
+
|
77
|
+
def on_completion(&block)
|
78
|
+
@on_complete_proc = block
|
79
|
+
end
|
80
|
+
|
81
|
+
def complete!(results)
|
82
|
+
@on_complete_proc.call(results) if @on_complete_proc
|
83
|
+
end
|
84
|
+
|
85
|
+
def on_failure(&block)
|
86
|
+
@on_failure_proc = block
|
87
|
+
end
|
88
|
+
|
89
|
+
def fail!(results)
|
90
|
+
@on_failure_proc.call(results) if @on_failure_proc
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'json'
|
3
|
+
module SharedWorkforce
|
4
|
+
class TaskRequest
|
5
|
+
|
6
|
+
def initialize(task, params)
|
7
|
+
@task = task
|
8
|
+
@params = params
|
9
|
+
@http_end_point = Client.http_end_point
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
RestClient.post("#{@http_end_point}/tasks", *request_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cancel
|
17
|
+
RestClient.post("#{@http_end_point}/tasks/cancel", *request_params)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def request_params
|
23
|
+
[{:task=>@task.to_hash.merge(@params).merge(:callback_url=>Client.callback_url), :api_key=>Client.api_key}.to_json, {:content_type => :json, :accept => :json}]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class TaskResponse
|
3
|
+
|
4
|
+
def self.create_collection_from_array(ary)
|
5
|
+
ary.collect {|r| TaskResponse.new(r) }
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :answer, :callback_params, :username
|
9
|
+
|
10
|
+
def initialize(params)
|
11
|
+
@answer = params['answer']
|
12
|
+
@callback_params = params['callback_params']
|
13
|
+
@username = params['username']
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SharedWorkforce
|
2
|
+
class TaskResult
|
3
|
+
|
4
|
+
attr_accessor :callback_params
|
5
|
+
attr_accessor :responses
|
6
|
+
attr_accessor :name
|
7
|
+
attr_accessor :status
|
8
|
+
|
9
|
+
def initialize(params)
|
10
|
+
self.callback_params = params['callback_params']
|
11
|
+
self.responses = TaskResponse.create_collection_from_array(params['responses'])
|
12
|
+
self.name = params['name']
|
13
|
+
end
|
14
|
+
|
15
|
+
def answers
|
16
|
+
responses.map(&:answer).flatten
|
17
|
+
end
|
18
|
+
|
19
|
+
def usernames
|
20
|
+
responses.map(&:username).flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def process!
|
24
|
+
if task = Task.find(name)
|
25
|
+
task.complete!(self)
|
26
|
+
else
|
27
|
+
raise "The task #{name} could not be found"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "shared_workforce/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "shared_workforce"
|
7
|
+
s.version = SharedWorkforce::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Sam Oliver"]
|
10
|
+
s.email = ["sam@samoliver.com"]
|
11
|
+
s.homepage = "http://github.com/pigment/shared_workforce"
|
12
|
+
s.summary = %q{Shared Workforce Client}
|
13
|
+
s.description = %q{Shared Workforce is a service and simple API for human intelligence tasks}
|
14
|
+
|
15
|
+
s.rubyforge_project = "shared_workforce_client"
|
16
|
+
|
17
|
+
s.add_dependency "rest-client"
|
18
|
+
s.add_dependency "json"
|
19
|
+
s.add_development_dependency "rspec", ">= 1.2.9"
|
20
|
+
s.add_development_dependency "webmock"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
end
|
data/spec/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Client" do
|
4
|
+
it "should load tasks" do
|
5
|
+
SharedWorkforce::Client.load_path = File.dirname(__FILE__) + '/tasks'
|
6
|
+
SharedWorkforce::Client.load!
|
7
|
+
|
8
|
+
SharedWorkforce::Task.find("Approve photo").should_not == nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return the current version number" do
|
12
|
+
SharedWorkforce::Client.version.should == SharedWorkforce::VERSION
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'shared_workforce'
|
4
|
+
require 'rspec'
|
5
|
+
require 'rspec/autorun'
|
6
|
+
require 'webmock/rspec'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.color_enabled = true
|
10
|
+
config.after :each do
|
11
|
+
SharedWorkforce::Task.clear!
|
12
|
+
end
|
13
|
+
|
14
|
+
config.before :each do
|
15
|
+
SharedWorkforce::Client.api_key = "test-api-key"
|
16
|
+
SharedWorkforce::Client.callback_host = "www.example.com"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "TaskRequest" do
|
4
|
+
|
5
|
+
it "should invoke a task request" do
|
6
|
+
|
7
|
+
task = SharedWorkforce::Task.define "Approve photo" do |h|
|
8
|
+
|
9
|
+
h.directions = "Please classify this photo by choosing the appropriate tickboxes."
|
10
|
+
h.image_url = "http://www.google.com/logo.png"
|
11
|
+
h.answer_type = "tags"
|
12
|
+
h.answer_options = ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children']
|
13
|
+
h.responses_required = 3
|
14
|
+
h.replace = false
|
15
|
+
|
16
|
+
h.on_completion do |result|
|
17
|
+
puts "Complete"
|
18
|
+
end
|
19
|
+
|
20
|
+
h.on_failure do |result|
|
21
|
+
puts "Failed"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
task_request = SharedWorkforce::TaskRequest.new(task, :callback_params=>{:resource_id=>'1234'})
|
27
|
+
|
28
|
+
stub_request(:post, "hci.heroku.com/tasks")
|
29
|
+
task_request.create
|
30
|
+
a_request(:post, "http://hci.heroku.com/tasks").with(:body=>{'task'=>
|
31
|
+
{
|
32
|
+
'name'=>"Approve photo",
|
33
|
+
'directions'=>"Please classify this photo by choosing the appropriate tickboxes.",
|
34
|
+
'image_url'=>"http://www.google.com/logo.png",
|
35
|
+
'answer_options'=> ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children'],
|
36
|
+
'responses_required'=>3,
|
37
|
+
'answer_type'=>'tags',
|
38
|
+
'callback_url'=>"#{SharedWorkforce::Client.callback_host}/hci_task_result",
|
39
|
+
'callback_params'=>{'resource_id'=>'1234'},
|
40
|
+
'replace'=>false
|
41
|
+
}, :api_key=>'test-api-key'}).should have_been_made.once
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
it "should invoke a task cancellation" do
|
47
|
+
|
48
|
+
task = SharedWorkforce::Task.define "Approve photo" do |h|
|
49
|
+
|
50
|
+
h.directions = "Please classify this photo by choosing the appropriate tickboxes."
|
51
|
+
h.image_url = "http://www.google.com/logo.png"
|
52
|
+
h.answer_type = "tags"
|
53
|
+
h.answer_options = ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children']
|
54
|
+
h.responses_required = 3
|
55
|
+
h.replace = false
|
56
|
+
|
57
|
+
h.on_completion do |result|
|
58
|
+
puts "Complete"
|
59
|
+
end
|
60
|
+
|
61
|
+
h.on_failure do |result|
|
62
|
+
puts "Failed"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
task_request = SharedWorkforce::TaskRequest.new(task, :callback_params=>{:resource_id=>'1234'})
|
68
|
+
|
69
|
+
stub_request(:post, "hci.heroku.com/tasks/cancel")
|
70
|
+
task_request.cancel
|
71
|
+
a_request(:post, "http://hci.heroku.com/tasks/cancel").with(:body=>{'task'=>
|
72
|
+
{
|
73
|
+
'name'=>"Approve photo",
|
74
|
+
'directions'=>"Please classify this photo by choosing the appropriate tickboxes.",
|
75
|
+
'image_url'=>"http://www.google.com/logo.png",
|
76
|
+
'answer_options'=> ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children'],
|
77
|
+
'responses_required'=>3,
|
78
|
+
'answer_type'=>'tags',
|
79
|
+
'callback_url'=>"#{SharedWorkforce::Client.callback_host}/hci_task_result",
|
80
|
+
'callback_params'=>{'resource_id'=>'1234'},
|
81
|
+
'replace'=>false
|
82
|
+
}, :api_key=>'test-api-key'}).should have_been_made.once
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should allow options to be overridden when making the request" do
|
87
|
+
|
88
|
+
task = SharedWorkforce::Task.define "Approve photo" do |h|
|
89
|
+
|
90
|
+
h.directions = "Please classify this photo by choosing the appropriate tickboxes."
|
91
|
+
h.image_url = "http://www.google.com/logo.png"
|
92
|
+
h.answer_type = "tags"
|
93
|
+
h.answer_options = ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children']
|
94
|
+
h.responses_required = 3
|
95
|
+
|
96
|
+
h.on_completion do |result|
|
97
|
+
puts "Complete"
|
98
|
+
end
|
99
|
+
|
100
|
+
h.on_failure do |result|
|
101
|
+
puts "Failed"
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
task_request = SharedWorkforce::TaskRequest.new(task, {:callback_params=>{:resource_id=>'1234'}, :image_url=>"http://www.example.com/image.jpg"})
|
107
|
+
|
108
|
+
stub_request(:post, "hci.heroku.com/tasks")
|
109
|
+
task_request.create
|
110
|
+
a_request(:post, "http://hci.heroku.com/tasks").with(:body=>{'task'=>
|
111
|
+
{
|
112
|
+
'name'=>"Approve photo",
|
113
|
+
'directions'=>"Please classify this photo by choosing the appropriate tickboxes.",
|
114
|
+
'image_url'=>"http://www.example.com/image.jpg",
|
115
|
+
'answer_options'=> ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children'],
|
116
|
+
'responses_required'=>3,
|
117
|
+
'answer_type'=>'tags',
|
118
|
+
'callback_url'=>"#{SharedWorkforce::Client.callback_host}/hci_task_result",
|
119
|
+
'callback_params'=>{'resource_id'=>'1234'},
|
120
|
+
'replace'=>false,
|
121
|
+
}, :api_key=>'test-api-key'}).should have_been_made.once
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "TaskResponse" do
|
4
|
+
it "should create responses from an array" do
|
5
|
+
r = SharedWorkforce::TaskResponse.create_collection_from_array([{'answer'=>'answer 1'}, {'answer'=>'answer 2'}])
|
6
|
+
r[0].answer.should == "answer 1"
|
7
|
+
r[1].answer.should == "answer 2"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should accept and store a username" do
|
11
|
+
r = SharedWorkforce::TaskResponse.create_collection_from_array([{'answer'=>'answer 1', 'username'=>'bilbo'}, {'answer'=>'answer 2', 'username'=>'frodo'}])
|
12
|
+
r[0].username.should == "bilbo"
|
13
|
+
r[1].username.should == "frodo"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "TaskResult" do
|
4
|
+
|
5
|
+
it "should invoke a tasks complete callback" do
|
6
|
+
|
7
|
+
resources = {}
|
8
|
+
resources['1'] = OpenStruct.new(:approved=>false)
|
9
|
+
resources['2'] = OpenStruct.new(:approved=>false)
|
10
|
+
resources['3'] = OpenStruct.new(:approved=>false)
|
11
|
+
|
12
|
+
task = SharedWorkforce::Task.define("Approve photo") do |h|
|
13
|
+
|
14
|
+
h.on_completion do |result|
|
15
|
+
if result.responses.first.answer == 'yes'
|
16
|
+
resources[result.callback_params['resource_id']].approved = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
SharedWorkforce::TaskResult.new({'callback_params'=>{'resource_id' => '2'}, 'responses'=>[{'answer'=>'yes'}], 'name'=>"Approve photo"}).process!
|
23
|
+
|
24
|
+
resources['1'].approved.should == false
|
25
|
+
resources['2'].approved.should == true
|
26
|
+
resources['3'].approved.should == false
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should collect the answers" do
|
31
|
+
r = SharedWorkforce::TaskResult.new({'callback_params'=>{'resource_id' => '2'}, 'responses'=>[{'answer'=>'yes'}, {'answer'=>'no'}, {'answer'=>'yes'}], 'name'=>"Approve photo"})
|
32
|
+
r.answers.should == ['yes', 'no', 'yes']
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should collect the usernames" do
|
36
|
+
r = SharedWorkforce::TaskResult.new({'callback_params'=>{'resource_id' => '2'}, 'responses'=>[{'answer'=>'yes', 'username'=>'bilbo'}, {'answer'=>'no', 'username'=>'frodo'}, {'answer'=>'yes', 'username'=>'sam'}], 'name'=>"Approve photo"})
|
37
|
+
r.usernames.should == ['bilbo', 'frodo', 'sam']
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/spec/task_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Task" do
|
4
|
+
it "should define a task" do
|
5
|
+
|
6
|
+
SharedWorkforce::Task.define "Approve photo" do |h|
|
7
|
+
|
8
|
+
h.directions = "Please classify this photo by choosing the appropriate tickboxes."
|
9
|
+
h.image_url = "http://www.google.com/logo.png"
|
10
|
+
h.answer_options = ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children']
|
11
|
+
h.responses_required = 3
|
12
|
+
|
13
|
+
h.on_completion do |result|
|
14
|
+
puts "Complete"
|
15
|
+
end
|
16
|
+
|
17
|
+
h.on_failure do |result|
|
18
|
+
puts "Failed"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
SharedWorkforce::Task.tasks.first[1].directions.should == "Please classify this photo by choosing the appropriate tickboxes."
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should run a completion callback" do
|
28
|
+
|
29
|
+
object = OpenStruct.new(:test=>nil)
|
30
|
+
|
31
|
+
task = SharedWorkforce::Task.define "Approve photo" do |h|
|
32
|
+
|
33
|
+
h.on_completion do |result|
|
34
|
+
object.test = "Complete"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
object.test.should == nil
|
40
|
+
task.complete!({})
|
41
|
+
object.test.should == "Complete"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should run a failure callback" do
|
45
|
+
|
46
|
+
object = OpenStruct.new(:test=>nil)
|
47
|
+
|
48
|
+
task = SharedWorkforce::Task.define "Approve photo" do |h|
|
49
|
+
|
50
|
+
h.on_failure do |result|
|
51
|
+
object.test = "Failed"
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
object.test.should == nil
|
57
|
+
task.fail!({})
|
58
|
+
object.test.should == "Failed"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not raise an error if there is no callback defined" do
|
62
|
+
lambda {
|
63
|
+
task = SharedWorkforce::Task.define("Approve photo") { }
|
64
|
+
task.fail!({})
|
65
|
+
}.should_not raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should request a task" do
|
69
|
+
task = SharedWorkforce::Task.define("Approve photo") { }
|
70
|
+
task.should_receive(:request).with(:request_id=>'123')
|
71
|
+
SharedWorkforce::Task.request("Approve photo", :request_id=>'123')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should cancel a task" do
|
75
|
+
task = SharedWorkforce::Task.define("Approve photo") { }
|
76
|
+
task.should_receive(:request).with(:request_id=>'123')
|
77
|
+
SharedWorkforce::Task.request("Approve photo", :request_id=>'123')
|
78
|
+
|
79
|
+
task.should_receive(:cancel).with(:request_id=>'123')
|
80
|
+
SharedWorkforce::Task.cancel("Approve photo", :request_id=>'123')
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should find a task" do
|
84
|
+
SharedWorkforce::Task.define("Approve photo") { }
|
85
|
+
SharedWorkforce::Task.define("Check profile text") { }
|
86
|
+
SharedWorkforce::Task.define("Check content") { }
|
87
|
+
|
88
|
+
|
89
|
+
SharedWorkforce::Task.find("Check profile text").name.should == "Check profile text"
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should raise a ConfigurationError if a callback host is not set" do
|
94
|
+
SharedWorkforce::Client.callback_host = nil
|
95
|
+
lambda {
|
96
|
+
SharedWorkforce::Task.define("Approve photo") { }
|
97
|
+
}.should raise_error SharedWorkforce::ConfigurationError
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should raise a ConfigurationError if an API key is not set" do
|
101
|
+
SharedWorkforce::Client.api_key = nil
|
102
|
+
lambda {
|
103
|
+
SharedWorkforce::Task.define("Approve photo") { }
|
104
|
+
}.should raise_error SharedWorkforce::ConfigurationError
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
SharedWorkforce::Task.define "Approve photo" do |h|
|
2
|
+
|
3
|
+
h.directions = "Please classify this photo by choosing the appropriate tickboxes."
|
4
|
+
h.image_url = "http://www.google.com/logo.png"
|
5
|
+
h.answer_options = ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children']
|
6
|
+
h.responses_required = 3
|
7
|
+
|
8
|
+
h.on_completion do |result|
|
9
|
+
puts "Complete"
|
10
|
+
end
|
11
|
+
|
12
|
+
h.on_failure do |result|
|
13
|
+
puts "Failed"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shared_workforce
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sam Oliver
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-13 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rest-client
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.2.9
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: webmock
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
description: Shared Workforce is a service and simple API for human intelligence tasks
|
61
|
+
email:
|
62
|
+
- sam@samoliver.com
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files: []
|
68
|
+
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- lib/shared_workforce.rb
|
75
|
+
- lib/shared_workforce/client.rb
|
76
|
+
- lib/shared_workforce/end_point.rb
|
77
|
+
- lib/shared_workforce/exceptions.rb
|
78
|
+
- lib/shared_workforce/frameworks/rails.rb
|
79
|
+
- lib/shared_workforce/task.rb
|
80
|
+
- lib/shared_workforce/task_request.rb
|
81
|
+
- lib/shared_workforce/task_response.rb
|
82
|
+
- lib/shared_workforce/task_result.rb
|
83
|
+
- lib/shared_workforce/version.rb
|
84
|
+
- shared_workforce.gemspec
|
85
|
+
- spec/.rspec
|
86
|
+
- spec/client_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/task_request_spec.rb
|
89
|
+
- spec/task_response_spec.rb
|
90
|
+
- spec/task_result_spec.rb
|
91
|
+
- spec/task_spec.rb
|
92
|
+
- spec/tasks/approve_photo.rb
|
93
|
+
has_rdoc: true
|
94
|
+
homepage: http://github.com/pigment/shared_workforce
|
95
|
+
licenses: []
|
96
|
+
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
requirements: []
|
115
|
+
|
116
|
+
rubyforge_project: shared_workforce_client
|
117
|
+
rubygems_version: 1.5.3
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Shared Workforce Client
|
121
|
+
test_files:
|
122
|
+
- spec/client_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
- spec/task_request_spec.rb
|
125
|
+
- spec/task_response_spec.rb
|
126
|
+
- spec/task_result_spec.rb
|
127
|
+
- spec/task_spec.rb
|
128
|
+
- spec/tasks/approve_photo.rb
|