shared_workforce 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,150 @@
1
+ Shared Workforce Client
2
+ =======================
3
+
4
+ Shared Workforce is a platform for managing and completing repetitive tasks that require human intelligence. For example, tagging photos, approving text and answering simple questions.
5
+
6
+ It differs from other similar services in the following ways:
7
+
8
+ * All tasks should be very simple and typically take no more than 10-15 seconds. (larger tasks can be broken down in to smaller ones).
9
+ * Tasks are displayed from a selection of pre-defined formats.
10
+ * Very simple integration via this ruby gem or the straight forward REST API.
11
+
12
+ The service is currently in private beta. You can apply for an invitation at [sharedworkforce.com](http://www.sharedworkforce.com).
13
+
14
+ Getting started
15
+ ===============
16
+
17
+ ### Step 1 - get an API key
18
+
19
+ Register for a beta invitation at [sharedworkforce.com](http://www.sharedworkforce.com). Once you are invited, you can create your account and retrieve your API key - which will look something like this:
20
+
21
+ acdc30b2-14c5-46ee-ba35-11d50edc65ec
22
+
23
+ ### Step 2 - add the gem
24
+
25
+ Add shared_workforce to your Gemfile:
26
+
27
+ gem "shared_workforce"
28
+
29
+ Or, for Rails 2.x add the gem to your environment.rb
30
+
31
+ config.gem "shared_workforce"
32
+
33
+ Create config/initializers/shared_workforce.rb
34
+
35
+ SharedWorkforce.configure do |config|
36
+ config.api_key = "your-api-key"
37
+ config.callback_host = "http://your-website-host"
38
+ end
39
+
40
+ If you're not using Rails, simply require the gem or include it in your Gemfile, set the client configuration settings as above.
41
+
42
+ ### Step 3 - define tasks
43
+
44
+ Create a directory called 'tasks' in the root of your app. This is where you define your tasks - all files in this directory will be loaded.
45
+
46
+ If, for example, you would like to have a photo tagged on upload, create your first task in a file called tasks/tag_photo.rb
47
+
48
+ SharedWorkforce::Task.define "Tag photo" do |t|
49
+
50
+ t.directions = "Look at this photo. Please tick all that apply."
51
+ t.answer_options = ['Offensive', 'Contains Nudity', 'Blurry or low quality']
52
+ t.answer_type = :tags
53
+ t.responses_required = 1
54
+ t.replace = true
55
+
56
+ t.on_completion do |result|
57
+ photo = Photo.find(result.callback_params['photo_id'])
58
+ if result.answers.include?('Offensive')
59
+ photo.hide!
60
+ photo.add_comment("Photo hidden because it was offensive")
61
+ elsif result.answers.include?('Contains Nudity')
62
+ photo.refer!
63
+ photo.add_comment("Photo referred because it contains nudity")
64
+ else
65
+ photo.approve!
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ ### Step 4 - request tasks
72
+
73
+ Publishing tasks is simply a case of calling SharedWorkforce::Task.request(name, options). If you are using Rails, this could be done in an after save callback on a model:
74
+
75
+ class Photo < ActiveRecord::Base
76
+
77
+ after_create :request_tags
78
+
79
+ def request_tags
80
+ SharedWorkforce::Task.request "Tag photo", {:image_url => self.url, :callback_params => { :photo_id => self.id} }
81
+ end
82
+ end
83
+
84
+
85
+ That's it - once your task is completed the callback you have defined in the task definition will be called. Everything you define in the :callback_params option will be sent back to your callback as shown in the example.
86
+
87
+ Advanced definition options
88
+ ----------------------------------------
89
+
90
+ ### Task types
91
+
92
+ SharedWorkforce currently supports 2 types of task. :tags (multiple select) and :choice (single answer from a list of options). Free-form input is planned in the near future.
93
+
94
+ SharedWorkforce::Task.define |t|
95
+ t.answer_type = #:tags or :choice
96
+ end
97
+
98
+ ###Multiple responses
99
+
100
+ SharedWorkforce supports multiple responses for each task. The callback method provides you with an array of responses from multiple workers. You can create your own logic to decide what to do. This is useful if you want to prevent destructive action unless a number of workers agree.
101
+
102
+ SharedWorkforce::Task.define "Tag photo" do |t|
103
+
104
+ t.directions = "Look at this photo. Please tick all that apply."
105
+ t.answer_options = ['Offensive', 'Contains Nudity', 'Blurry or low quality']
106
+ t.answer_type = :tags
107
+ t.responses_required = 3
108
+
109
+ t.on_completion do |result|
110
+ photo = Photo.find(result.callback_params['photo_id'])
111
+ photo.hide! if result.answers.all? { |a| a == 'Contains Nudity' }
112
+ end
113
+
114
+ end
115
+
116
+ ###Replacing tasks
117
+
118
+ The "replace" option allows you to overwrite or update any existing tasks with the same name and callback params. This could be useful in the example to handle the situation where a user re-uploads their photo - you may only care about the latest one.
119
+
120
+ SharedWorkforce::Task.define "Tag photo" do |t|
121
+ ...
122
+ t.replace=true
123
+ ...
124
+ end
125
+
126
+ ###Cancelling tasks
127
+
128
+ You can cancel tasks when they are no longer relevant.
129
+
130
+ class Photo < ActiveRecord::Base
131
+ after_destroy :cancel_tagging_request
132
+
133
+ def cancel_tagging_request
134
+ SharedWorkforce::Task.cancel "Classify photo", :callback_params=>{:photo_id=>self.id})
135
+ end
136
+ end
137
+
138
+ ###Testing and development
139
+
140
+ You can black-hole requests to SharedWorkforce for testing and development by adding the following configuration option in your initializer:
141
+
142
+ SharedWorkforce.configure do |config|
143
+ config.request_class = SharedWorkforce::TaskRequest::BlackHole
144
+ end
145
+
146
+ License
147
+ -----------
148
+
149
+ The SharedWorkforce Client is (c) [Pigment](http://www.thinkpigment.com) and released under the MIT license
150
+
@@ -1,15 +1,7 @@
1
1
  module SharedWorkforce
2
2
  class Client
3
-
4
- @http_end_point = "http://hci.heroku.com"
5
- @load_path = "tasks"
6
-
7
3
  class << self
8
- attr_accessor :api_key
9
4
  attr_accessor :load_path
10
- attr_accessor :http_end_point
11
- attr_accessor :callback_host
12
- attr_accessor :callback_path
13
5
 
14
6
  def version
15
7
  SharedWorkforce::VERSION
@@ -20,15 +12,6 @@ module SharedWorkforce
20
12
  load file
21
13
  end
22
14
  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
15
  end
32
-
33
16
  end
34
17
  end
@@ -0,0 +1,26 @@
1
+ module SharedWorkforce
2
+ class Configuration
3
+
4
+ attr_accessor :api_key
5
+ attr_accessor :load_path
6
+ attr_accessor :http_end_point
7
+ attr_accessor :callback_host
8
+ attr_accessor :request_class
9
+ attr_writer :callback_path
10
+
11
+ def initialize
12
+ @http_end_point = "http://api.sharedworkforce.com"
13
+ @load_path = "tasks"
14
+ @request_class = TaskRequest::Http
15
+ end
16
+
17
+ def callback_url
18
+ callback_host.to_s + '/' + callback_path.to_s
19
+ end
20
+
21
+ def callback_path
22
+ @callback_path ||= "hci_task_result"
23
+ end
24
+
25
+ end
26
+ end
@@ -6,7 +6,7 @@ module SharedWorkforce
6
6
  end
7
7
 
8
8
  def call(env)
9
- if env["PATH_INFO"] =~ /^\/#{Client.callback_path}/
9
+ if env["PATH_INFO"] =~ /^\/#{callback_path}/
10
10
  process_request(env)
11
11
  else
12
12
  @app.call(env)
@@ -29,6 +29,10 @@ module SharedWorkforce
29
29
  [""]
30
30
  ]
31
31
  end
32
+
33
+ def callback_path
34
+ SharedWorkforce.configuration.callback_path
35
+ end
32
36
 
33
37
  end
34
38
  end
@@ -1,13 +1,13 @@
1
1
  if defined?(ActionController::Metal)
2
2
  class Railtie < Rails::Railtie
3
3
  initializer :load_hci do |app|
4
- SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce::Client.load_path
4
+ SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce.configuration.load_path
5
5
  SharedWorkforce::Client.load!
6
6
  end
7
7
  end
8
8
  else
9
9
  Rails.configuration.after_initialize do
10
- SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce::Client.load_path
10
+ SharedWorkforce::Client.load_path = Rails.root + SharedWorkforce.configuration.load_path
11
11
  SharedWorkforce::Client.load!
12
12
  end
13
13
  end
@@ -10,9 +10,6 @@ module SharedWorkforce
10
10
  end
11
11
 
12
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
13
  task = self.new
17
14
  task.name = name
18
15
  yield task
@@ -50,12 +47,12 @@ module SharedWorkforce
50
47
  end
51
48
 
52
49
  def request(options)
53
- task_request = TaskRequest.new(self, options)
50
+ task_request = remote_request(self, options)
54
51
  task_request.create
55
52
  end
56
53
 
57
54
  def cancel(options)
58
- task_request = TaskRequest.new(self, options)
55
+ task_request = remote_request(self, options)
59
56
  task_request.cancel
60
57
  end
61
58
 
@@ -67,7 +64,7 @@ module SharedWorkforce
67
64
  :answer_options => answer_options,
68
65
  :responses_required => responses_required,
69
66
  :answer_type => answer_type.to_s,
70
- :callback_url => Client.callback_url,
67
+ :callback_url => callback_url,
71
68
  :replace => replace
72
69
  }
73
70
  end
@@ -89,7 +86,15 @@ module SharedWorkforce
89
86
  def fail!(results)
90
87
  @on_failure_proc.call(results) if @on_failure_proc
91
88
  end
92
-
93
-
89
+
90
+ private
91
+
92
+ def callback_url
93
+ SharedWorkforce.configuration.callback_url
94
+ end
95
+
96
+ def remote_request(*args)
97
+ SharedWorkforce.configuration.request_class.new(*args)
98
+ end
94
99
  end
95
100
  end
@@ -0,0 +1,7 @@
1
+ require 'rest_client'
2
+ module SharedWorkforce
3
+ class TaskRequest::BlackHole < TaskRequest
4
+ def create; end
5
+ def cancel; end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ require 'rest_client'
2
+ module SharedWorkforce
3
+ class TaskRequest::Http < TaskRequest
4
+
5
+ def initialize(*args)
6
+ raise ConfigurationError, "Please set your SharedWorkforce api key with SharedWorkforce::Client.api_key = 'your-api-key-here'" unless SharedWorkforce.configuration.api_key
7
+ raise ConfigurationError, "Please set your callback URL with SharedWorkforce::Client.callback_host = 'www.your-domain-name.com'" unless SharedWorkforce.configuration.callback_host
8
+ super(*args)
9
+ end
10
+
11
+ def create
12
+ RestClient.post("#{http_end_point}/tasks", *request_params)
13
+ end
14
+
15
+ def cancel
16
+ RestClient.post("#{http_end_point}/tasks/cancel", *request_params)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+ module SharedWorkforce
3
+ class TaskRequest
4
+
5
+ def initialize(task, params)
6
+ @task = task
7
+ @params = params
8
+ end
9
+
10
+ private
11
+
12
+ def request_params
13
+ [{:task=>@task.to_hash.merge(@params).merge(:callback_url=>callback_url), :api_key=>api_key}.to_json, {:content_type => :json, :accept => :json}]
14
+ end
15
+
16
+ def http_end_point
17
+ SharedWorkforce.configuration.http_end_point
18
+ end
19
+
20
+ def callback_url
21
+ SharedWorkforce.configuration.callback_url
22
+ end
23
+
24
+ def api_key
25
+ SharedWorkforce.configuration.api_key
26
+ end
27
+
28
+ end
29
+ end
@@ -1,4 +1,4 @@
1
1
  module SharedWorkforce
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
 
4
4
  end
@@ -1,9 +1,29 @@
1
+ require 'shared_workforce/configuration'
1
2
  require 'shared_workforce/exceptions'
2
3
  require 'shared_workforce/client'
3
4
  require 'shared_workforce/version'
4
5
  require 'shared_workforce/task'
5
- require 'shared_workforce/task_request'
6
+ require 'shared_workforce/task_request/task_request'
7
+ require 'shared_workforce/task_request/black_hole'
8
+ require 'shared_workforce/task_request/http'
6
9
  require 'shared_workforce/task_result'
7
10
  require 'shared_workforce/task_response'
8
11
  require 'shared_workforce/end_point'
9
- require 'shared_workforce/frameworks/rails' if defined?(Rails)
12
+ require 'shared_workforce/frameworks/rails' if defined?(Rails)
13
+
14
+ module SharedWorkforce
15
+
16
+ class << self
17
+
18
+ attr_writer :configuration
19
+
20
+ def configure
21
+ yield(configuration); nil
22
+ end
23
+
24
+ def configuration
25
+ @configuration ||= SharedWorkforce::Configuration.new
26
+ end
27
+ end
28
+
29
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,10 @@ require 'rspec'
5
5
  require 'rspec/autorun'
6
6
  require 'webmock/rspec'
7
7
 
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ Dir[File.join(File.expand_path('../support', __FILE__), '**/*.rb')].each {|f| require f}
11
+
8
12
  RSpec.configure do |config|
9
13
  config.color_enabled = true
10
14
  config.after :each do
@@ -12,8 +16,10 @@ RSpec.configure do |config|
12
16
  end
13
17
 
14
18
  config.before :each do
15
- SharedWorkforce::Client.api_key = "test-api-key"
16
- SharedWorkforce::Client.callback_host = "www.example.com"
19
+ SharedWorkforce.configure do |config|
20
+ config.api_key = "test-api-key"
21
+ config.callback_host = "www.example.com"
22
+ end
17
23
  end
18
24
  end
19
25
 
@@ -0,0 +1,17 @@
1
+ module ConfigurationHelper
2
+ def configure(&block)
3
+ SharedWorkforce.configure(&block)
4
+ end
5
+
6
+ def with_configuration(&block)
7
+ old_configuration = SharedWorkforce.configuration
8
+ SharedWorkforce.configuration = SharedWorkforce::Configuration.new
9
+ yield(SharedWorkforce.configuration)
10
+ ensure
11
+ SharedWorkforce.configuration = old_configuration
12
+ end
13
+ end
14
+
15
+ RSpec.configure do |config|
16
+ config.include ConfigurationHelper
17
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "TaskRequest::BlackHole" do
4
+ describe "#create" do
5
+ it "should not make an HTTP request" do
6
+ task_request = SharedWorkforce::TaskRequest::BlackHole.new(SharedWorkforce::Task.find("Approve photo"), :callback_params=>{:resource_id=>'1234'})
7
+ task_request.create
8
+ a_request(:any, "api.sharedworkforce.com/tasks").should_not have_been_made
9
+ end
10
+ end
11
+
12
+ describe "#cancel" do
13
+ it "should not make an HTTP request" do
14
+ task_request = SharedWorkforce::TaskRequest::BlackHole.new(SharedWorkforce::Task.find("Approve photo"), :callback_params=>{:resource_id=>'1234'})
15
+ task_request.create
16
+ a_request(:any, "api.sharedworkforce.com/tasks/cancel").should_not have_been_made
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,125 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "TaskRequest::Http" do
4
+ describe "#create" do
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::Http.new(task, :callback_params=>{:resource_id=>'1234'})
27
+
28
+ stub_request(:post, "api.sharedworkforce.com/tasks")
29
+ task_request.create
30
+ a_request(:post, "http://api.sharedworkforce.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.configuration.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
+ it "should allow options to be overridden when making the request" do
46
+
47
+ task = SharedWorkforce::Task.define "Approve photo" do |h|
48
+
49
+ h.directions = "Please classify this photo by choosing the appropriate tickboxes."
50
+ h.image_url = "http://www.google.com/logo.png"
51
+ h.answer_type = "tags"
52
+ 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']
53
+ h.responses_required = 3
54
+
55
+ h.on_completion do |result|
56
+ puts "Complete"
57
+ end
58
+
59
+ h.on_failure do |result|
60
+ puts "Failed"
61
+ end
62
+
63
+ end
64
+
65
+ task_request = SharedWorkforce::TaskRequest::Http.new(task, {:callback_params=>{:resource_id=>'1234'}, :image_url=>"http://www.example.com/image.jpg"})
66
+
67
+ stub_request(:post, "api.sharedworkforce.com/tasks")
68
+ task_request.create
69
+ a_request(:post, "http://api.sharedworkforce.com/tasks").with(:body=>{'task'=>
70
+ {
71
+ 'name'=>"Approve photo",
72
+ 'directions'=>"Please classify this photo by choosing the appropriate tickboxes.",
73
+ 'image_url'=>"http://www.example.com/image.jpg",
74
+ 'answer_options'=> ['Obscenity', 'Nudity', 'Blurry', 'Upside down or sideways', 'Contains more than one person in the foreground', 'Has people in the background', 'Contains children'],
75
+ 'responses_required'=>3,
76
+ 'answer_type'=>'tags',
77
+ 'callback_url'=>"#{SharedWorkforce.configuration.callback_host}/hci_task_result",
78
+ 'callback_params'=>{'resource_id'=>'1234'},
79
+ 'replace'=>false,
80
+ }, :api_key=>'test-api-key'}).should have_been_made.once
81
+ end
82
+ end
83
+
84
+ describe "#cancel" do
85
+ it "should invoke a task cancellation" do
86
+
87
+ task = SharedWorkforce::Task.define "Approve photo" do |h|
88
+
89
+ h.directions = "Please classify this photo by choosing the appropriate tickboxes."
90
+ h.image_url = "http://www.google.com/logo.png"
91
+ h.answer_type = "tags"
92
+ 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']
93
+ h.responses_required = 3
94
+ h.replace = false
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::Http.new(task, :callback_params=>{:resource_id=>'1234'})
107
+
108
+ stub_request(:post, "api.sharedworkforce.com/tasks/cancel")
109
+ task_request.cancel
110
+ a_request(:post, "http://api.sharedworkforce.com/tasks/cancel").with(:body=>{'task'=>
111
+ {
112
+ 'name'=>"Approve photo",
113
+ 'directions'=>"Please classify this photo by choosing the appropriate tickboxes.",
114
+ 'image_url'=>"http://www.google.com/logo.png",
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.configuration.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
+
123
+ end
124
+ end
125
+ end
@@ -1,15 +1,17 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
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
4
+ describe ".create_collection_from_array" do
5
+ it "should create responses from an array" do
6
+ r = SharedWorkforce::TaskResponse.create_collection_from_array([{'answer'=>'answer 1'}, {'answer'=>'answer 2'}])
7
+ r[0].answer.should == "answer 1"
8
+ r[1].answer.should == "answer 2"
9
+ end
9
10
 
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"
11
+ it "should accept and store a username" do
12
+ r = SharedWorkforce::TaskResponse.create_collection_from_array([{'answer'=>'answer 1', 'username'=>'bilbo'}, {'answer'=>'answer 2', 'username'=>'frodo'}])
13
+ r[0].username.should == "bilbo"
14
+ r[1].username.should == "frodo"
15
+ end
14
16
  end
15
17
  end
@@ -1,40 +1,44 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
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|
4
+ describe "#process!" do
5
+ it "should invoke a tasks complete callback" do
13
6
 
14
- h.on_completion do |result|
15
- if result.responses.first.answer == 'yes'
16
- resources[result.callback_params['resource_id']].approved = true
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
17
18
  end
19
+
18
20
  end
19
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
+
20
28
  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
29
  end
29
30
 
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']
31
+ describe "#answers" do
32
+ it "should collect the answers" do
33
+ r = SharedWorkforce::TaskResult.new({'callback_params'=>{'resource_id' => '2'}, 'responses'=>[{'answer'=>'yes'}, {'answer'=>'no'}, {'answer'=>'yes'}], 'name'=>"Approve photo"})
34
+ r.answers.should == ['yes', 'no', 'yes']
35
+ end
33
36
  end
34
37
 
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
+ describe "#usernames" do
39
+ it "should collect the usernames" do
40
+ 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"})
41
+ r.usernames.should == ['bilbo', 'frodo', 'sam']
42
+ end
38
43
  end
39
-
40
- end
44
+ end
data/spec/task_spec.rb CHANGED
@@ -91,17 +91,23 @@ describe "Task" do
91
91
  end
92
92
 
93
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
94
+ SharedWorkforce::Task.define("Approve photo") {}
95
+ with_configuration do |config|
96
+ config.callback_host = nil
97
+ lambda {
98
+ SharedWorkforce::Task.request("Approve photo", {})
99
+ }.should raise_error SharedWorkforce::ConfigurationError
100
+ end
98
101
  end
99
102
 
100
103
  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
104
+ SharedWorkforce::Task.define("Approve photo") {}
105
+ with_configuration do |config|
106
+ config.api_key = nil
107
+ lambda {
108
+ SharedWorkforce::Task.request("Approve photo", {})
109
+ }.should raise_error SharedWorkforce::ConfigurationError
110
+ end
105
111
  end
106
112
  end
107
113
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: shared_workforce
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sam Oliver
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-13 00:00:00 +01:00
13
+ date: 2011-05-10 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -69,15 +69,18 @@ extra_rdoc_files: []
69
69
  files:
70
70
  - .gitignore
71
71
  - Gemfile
72
- - README.rdoc
72
+ - README.markdown
73
73
  - Rakefile
74
74
  - lib/shared_workforce.rb
75
75
  - lib/shared_workforce/client.rb
76
+ - lib/shared_workforce/configuration.rb
76
77
  - lib/shared_workforce/end_point.rb
77
78
  - lib/shared_workforce/exceptions.rb
78
79
  - lib/shared_workforce/frameworks/rails.rb
79
80
  - lib/shared_workforce/task.rb
80
- - lib/shared_workforce/task_request.rb
81
+ - lib/shared_workforce/task_request/black_hole.rb
82
+ - lib/shared_workforce/task_request/http.rb
83
+ - lib/shared_workforce/task_request/task_request.rb
81
84
  - lib/shared_workforce/task_response.rb
82
85
  - lib/shared_workforce/task_result.rb
83
86
  - lib/shared_workforce/version.rb
@@ -85,7 +88,9 @@ files:
85
88
  - spec/.rspec
86
89
  - spec/client_spec.rb
87
90
  - spec/spec_helper.rb
88
- - spec/task_request_spec.rb
91
+ - spec/support/configuration_helper.rb
92
+ - spec/task_request/black_hole_spec.rb
93
+ - spec/task_request/http_spec.rb
89
94
  - spec/task_response_spec.rb
90
95
  - spec/task_result_spec.rb
91
96
  - spec/task_spec.rb
@@ -121,7 +126,9 @@ summary: Shared Workforce Client
121
126
  test_files:
122
127
  - spec/client_spec.rb
123
128
  - spec/spec_helper.rb
124
- - spec/task_request_spec.rb
129
+ - spec/support/configuration_helper.rb
130
+ - spec/task_request/black_hole_spec.rb
131
+ - spec/task_request/http_spec.rb
125
132
  - spec/task_response_spec.rb
126
133
  - spec/task_result_spec.rb
127
134
  - spec/task_spec.rb
data/README.rdoc DELETED
File without changes
@@ -1,27 +0,0 @@
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
@@ -1,126 +0,0 @@
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
-