shared_workforce 0.2.12 → 0.2.13

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -27,121 +27,168 @@ Register for a beta invitation at [sharedworkforce.com](http://www.sharedworkfor
27
27
 
28
28
  Add shared_workforce to your Gemfile:
29
29
 
30
- gem "shared_workforce"
30
+ ```ruby
31
+ gem "shared_workforce"
32
+ ```
31
33
 
32
34
  Create config/initializers/shared_workforce.rb
33
35
 
34
- SharedWorkforce.configure do |config|
35
- config.api_key = "your-api-key"
36
- config.callback_host = "http://your-website-host"
37
- end
36
+ ```ruby
37
+ SharedWorkforce.configure do |config|
38
+ config.api_key = "your-api-key"
39
+ config.callback_host = "http://your-website-host"
40
+ end
41
+ ```
38
42
 
39
43
  If you're not using Rails, simply require the gem or include it in your Gemfile, set the client configuration settings as above.
40
44
 
41
45
  ### Step 3 - define tasks
42
46
 
43
- If, for example, you would like to approve a photo on upload, create your first task in a file called app/tasks/approve_photo.rb
44
-
45
- class ApprovePhotoTask
46
- include SharedWorkforce::Task
47
-
48
- title 'Approve Photo'
47
+ A class defines the content (for example, an image url) and instructions that the human worker will see when they work on your task, and the methods to be run once the task has been completed.
49
48
 
50
- instruction 'Look at this photo. Please tick all that apply.'
51
- responses_required 1
49
+ If, for example, you would like to approve a photo on upload, create a task class file in an `app/tasks` directory (or anywhere in the load path).
52
50
 
53
- answer_options ['Offensive', 'Contains Nudity', 'Blurry or low quality', 'Upside down or sideways']
54
- answer_type :tags
55
- image_url "http://www.google.com/logo.png"
56
51
 
57
- on_success :moderate_photo
52
+ `app/tasks/tag_photo_task.rb`:
58
53
 
59
- def moderate_photo(photo, responses)
60
- if responses.map { |r| r[:answer] }.include?('Offensive')
61
- photo.hide!
62
- photo.add_comment("Photo is offensive")
63
- end
64
- puts "Photo Moderated"
65
- end
66
-
54
+ ```ruby
55
+ class TagPhotoTask
56
+ include SharedWorkforce::Task
57
+
58
+ title 'Please tag our photo'
59
+
60
+ instruction 'Please look at the photo and tick all that apply.'
61
+
62
+ answer_type :tags
63
+ answer_options ['Offensive', 'Contains Nudity', 'Blurry or low quality', 'Upside down or sideways']
64
+
65
+ responses_required 1
66
+
67
+ on_success :moderate_photo
68
+
69
+ def setup(photo)
70
+ self.image_url = photo.url
71
+ end
72
+
73
+ def moderate_photo(photo, responses)
74
+ # responses => [{:answer=>['Offensive', 'Contains Nudity']}]
75
+ if responses.map {|r| r[:answer]}.flatten.include?('Offensive')
76
+ photo.delete
77
+ photo.user.quarantine("Uploded offensive photo")
67
78
  end
68
-
79
+ end
80
+ end
81
+ ```
82
+ _**Note:** the task definition includes a `setup` method which is called automatically whenever the task is initialized. In the example, the task's `image_url` (the image shown to the worker) is set from the photo model's url attribute. Any of the task's attributes can be set this way._
83
+
84
+ Once you have created a task definition, you can request real human responses for a model instance by calling its `create` method. This can be done in an `after_create` callback in one of your Active Record models. This will be covered in more detail in the next section.
69
85
 
70
86
  ### Step 4 - request tasks
71
87
 
72
- Publishing tasks is simply a case of calling `TaskClass.create()`. If you are using Rails, this could be done in an after save callback on a model:
88
+ When you publish a task it will be queued for a human worker to complete. You can publish a task in an `after_create` callback on a typical Active Record model:
73
89
 
74
- class Photo < ActiveRecord::Base
75
-
76
- after_create :approve_photo
77
-
78
- def approve_photo
79
- ApprovePhotoTask.create(self)
80
- end
81
- end
90
+ ```ruby
91
+ class Photo < ActiveRecord::Base
92
+
93
+ after_create :request_tags
94
+
95
+ def request_tags
96
+ TagPhotoTask.create(self)
97
+ end
98
+ end
99
+ ```
100
+
101
+ _**Note:** In the example, the photo model instance (self) is used an argument to the TagPhotoTask.create method. This argument will be available in the setup method and the callback method as shown in the example of a Task Definition in step 3._
102
+
103
+ When the response(s) from the human workers are collected, the method specified in the `on_success` attribute in your task definition will be called. Typically this will take about 15 minutes. You can check the [Shared Workforce web site](http://www.sharedworkforce.com) for an up to date status on the current response time.
82
104
 
105
+ ### Unit testing
106
+
107
+ You can test your task definition by calling its methods directly.
108
+
109
+ ```ruby
110
+ it "should quarantine the user" do
111
+ photo = Factory(:photo)
112
+ task = ClassifyPhotoTask.new(photo)
113
+ task.moderate_photo(photo, [{:answer=>['Offensive']}])
114
+ photo.user.should be_quarantined
115
+ end
116
+ ```
83
117
 
84
118
  Advanced definition options
85
119
  ----------------------------------------
86
120
 
87
121
  ### Task types
88
122
 
89
- SharedWorkforce currently supports 3 types of task. `:tags` (multiple select), `:choice` (single answer from a list of options), or `:edit` (edit text).
123
+ SharedWorkforce currently supports 5 types of task. Possible options are:
124
+
125
+ * `"choice"`: choose one option from a list
126
+ * `"tags"`: choose any number of options from a list
127
+ * `"edit"`: edit the text in the 'text' attribute
128
+ * `"crop"`: crop the photo (see image_crop_ratio)
129
+ * `"rotate"`: rotate the photo
90
130
 
91
- ###Multiple responses
131
+ ### Multiple responses
92
132
 
93
133
  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.
94
134
 
95
- class ApprovePhotoTask
96
- include SharedWorkforce::Task
135
+ ```ruby
136
+ class ApprovePhotoTask
137
+ include SharedWorkforce::Task
97
138
 
98
- title 'Approve Photo'
139
+ title 'Approve Photo'
99
140
 
100
- instruction 'Look at this photo. Please tick all that apply.'
101
- responses_required 3
141
+ instruction 'Look at this photo. Please tick all that apply.'
142
+ responses_required 3
102
143
 
103
- answer_options ['Offensive', 'Contains Nudity', 'Blurry or low quality', 'Upside down or sideways']
104
- answer_type :tags
144
+ answer_options ['Offensive', 'Contains Nudity', 'Blurry or low quality', 'Upside down or sideways']
145
+ answer_type :tags
105
146
 
106
- on_complete :moderate_photo
147
+ on_complete :moderate_photo
107
148
 
108
- def moderate_photo(photo, responses)
109
- photo.hide! if responses.map { |r| r[:answer] }.all? { |a| a.include?('Contains Nudity') }
110
- end
149
+ def moderate_photo(photo, responses)
150
+ photo.hide! if responses.map { |r| r[:answer] }.all? { |a| a.include?('Contains Nudity') }
151
+ end
111
152
 
112
- end
113
-
153
+ end
154
+ ```
114
155
 
115
- ###Replacing tasks
156
+ ### Replacing tasks
116
157
 
117
158
  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.
118
159
 
119
- class ApprovePhotoTask
120
- include SharedWorkforce::Task
121
- ...
122
- replace true
123
- ...
124
- end
160
+ ```ruby
161
+ class ApprovePhotoTask
162
+ include SharedWorkforce::Task
163
+ ...
164
+ replace true
165
+ ...
166
+ end
167
+ ```
125
168
 
126
- ###Cancelling tasks
169
+ ### Cancelling tasks
127
170
 
128
171
  You can cancel tasks when they are no longer relevant.
129
-
130
- class Photo
131
- after_destroy :cancel_tagging_request
132
172
 
133
- def cancel_tagging_request
134
- ApprovePhotoTask.cancel(self)
135
- end
136
- end
173
+ ```ruby
174
+ class Photo
175
+ after_destroy :cancel_tagging_request
137
176
 
138
- ###Testing and development
177
+ def cancel_tagging_request
178
+ ApprovePhotoTask.cancel(self)
179
+ end
180
+ end
181
+ ```
139
182
 
140
- You can black-hole requests to SharedWorkforce for testing and development by adding the following configuration option in your initializer:
183
+ ### Disabling requests during development
141
184
 
142
- SharedWorkforce.configure do |config|
143
- config.request_class = SharedWorkforce::TaskRequest::BlackHole
144
- end
185
+ You can black-hole requests to Shared Workforce for testing and development by adding the following configuration option in your initializer:
186
+
187
+ ```ruby
188
+ SharedWorkforce.configure do |config|
189
+ config.request_class = SharedWorkforce::TaskRequest::BlackHole
190
+ end
191
+ ```
145
192
 
146
193
  License
147
194
  -----------
@@ -14,6 +14,7 @@ require 'shared_workforce/response_poller'
14
14
  require 'shared_workforce/frameworks/rails' if defined?(Rails)
15
15
  require 'active_support/inflector'
16
16
  require 'active_support/core_ext/hash/indifferent_access'
17
+ require 'active_support/core_ext/object/blank'
17
18
 
18
19
  module SharedWorkforce
19
20
 
@@ -34,6 +34,10 @@ module SharedWorkforce
34
34
  @logger ||= (rails_logger || default_logger)
35
35
  end
36
36
 
37
+ def valid?
38
+ @api_key.present?
39
+ end
40
+
37
41
  private
38
42
 
39
43
  def default_request_class
@@ -2,10 +2,16 @@ if defined?(ActionController::Metal)
2
2
  class Railtie < Rails::Railtie
3
3
  initializer 'shared_workforce' do |app|
4
4
  app.config.middleware.use SharedWorkforce::EndPoint
5
- if Rails.env.development?
6
- # Stop log buffering when using Foreman in development
7
- $stdout.sync = true
8
- SharedWorkforce::ResponsePoller.start
5
+ app.config.after_initialize do
6
+ if Rails.env.development?
7
+ if SharedWorkforce.configuration.valid?
8
+ # Stop log buffering when using Foreman in development
9
+ $stdout.sync = true
10
+ SharedWorkforce::ResponsePoller.start
11
+ else
12
+ puts 'Shared Workforce: API key not configured.'
13
+ end
14
+ end
9
15
  end
10
16
  end
11
17
  end
@@ -1,4 +1,4 @@
1
1
  module SharedWorkforce
2
- VERSION = "0.2.12"
2
+ VERSION = "0.2.13"
3
3
 
4
4
  end
@@ -69,5 +69,12 @@ describe "Configuration" do
69
69
  configuration.logger.should == logger_double
70
70
  end
71
71
  end
72
+
73
+ describe "#valid" do
74
+ it "should be false if no api key is set" do
75
+ configuration.api_key = nil
76
+ configuration.should_not be_valid
77
+ end
78
+ end
72
79
 
73
80
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shared_workforce
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.12
4
+ version: 0.2.13
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-23 00:00:00.000000000 Z
12
+ date: 2012-08-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
16
- requirement: &70340575489280 !ruby/object:Gem::Requirement
16
+ requirement: &70323744943380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70340575489280
24
+ version_requirements: *70323744943380
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &70340575503560 !ruby/object:Gem::Requirement
27
+ requirement: &70323744942960 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70340575503560
35
+ version_requirements: *70323744942960
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activesupport
38
- requirement: &70340575502400 !ruby/object:Gem::Requirement
38
+ requirement: &70323744942540 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70340575502400
46
+ version_requirements: *70323744942540
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &70340575498220 !ruby/object:Gem::Requirement
49
+ requirement: &70323744942040 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.2.9
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70340575498220
57
+ version_requirements: *70323744942040
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: webmock
60
- requirement: &70340575527180 !ruby/object:Gem::Requirement
60
+ requirement: &70323744941620 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70340575527180
68
+ version_requirements: *70323744941620
69
69
  description: Shared Workforce is a service and simple API for human intelligence tasks
70
70
  email:
71
71
  - sam@samoliver.com