crowdflower 0.4.5 → 0.5.3
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/HISTORY.md +9 -0
- data/VERSION +1 -1
- data/crowdflower.gemspec +23 -25
- data/lib/crowdflower.rb +1 -1
- data/lib/crowdflower/base.rb +155 -30
- data/lib/crowdflower/job.rb +35 -42
- data/lib/crowdflower/judgment.rb +27 -8
- data/lib/crowdflower/order.rb +4 -4
- data/lib/crowdflower/unit.rb +11 -11
- data/lib/crowdflower/worker.rb +54 -0
- data/test/integration_tests.rb +36 -1
- metadata +9 -9
- data/.gitignore +0 -8
data/HISTORY.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 0.5.1 (2011-02-03)
|
2
|
+
* Added individual judgment rejection to API.
|
3
|
+
|
4
|
+
## 0.5.0 (2011-02-01)
|
5
|
+
* Worker API added for managing workers (flagging, approving, etc.)
|
6
|
+
|
7
|
+
## 0.4.6 (2010-12-17)
|
8
|
+
* Multiple API keys can be used simultaneously
|
9
|
+
|
1
10
|
## 0.4.0 (2010-03-25)
|
2
11
|
* Allow key configuration from YAML
|
3
12
|
* ruby-crowdflower is now just 'crowdflower'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.2
|
data/crowdflower.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{crowdflower}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian P O'Rourke", "Chris Van Pelt"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-02-10}
|
13
13
|
s.description = %q{A toolkit for interacting with CrowdFlower via the REST API.
|
14
14
|
|
15
15
|
This is alpha software. Have fun!
|
@@ -18,40 +18,38 @@ This is alpha software. Have fun!
|
|
18
18
|
s.email = %q{brian@doloreslabs.com}
|
19
19
|
s.extra_rdoc_files = [
|
20
20
|
"LICENSE",
|
21
|
-
|
21
|
+
"README.md"
|
22
22
|
]
|
23
23
|
s.files = [
|
24
24
|
".document",
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
25
|
+
"CONTRIBUTORS",
|
26
|
+
"HISTORY.md",
|
27
|
+
"LICENSE",
|
28
|
+
"README.md",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"bindev/cl_skel.rb",
|
32
|
+
"bindev/crowdflower.rb",
|
33
|
+
"crowdflower.gemspec",
|
34
|
+
"lib/crowdflower.rb",
|
35
|
+
"lib/crowdflower/base.rb",
|
36
|
+
"lib/crowdflower/job.rb",
|
37
|
+
"lib/crowdflower/judgment.rb",
|
38
|
+
"lib/crowdflower/order.rb",
|
39
|
+
"lib/crowdflower/unit.rb",
|
40
|
+
"lib/crowdflower/worker.rb",
|
41
|
+
"test/integration_tests.rb",
|
42
|
+
"test/sample.csv"
|
43
43
|
]
|
44
44
|
s.homepage = %q{http://github.com/dolores/ruby-crowdflower}
|
45
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
46
45
|
s.require_paths = ["lib"]
|
47
|
-
s.rubygems_version = %q{1.
|
46
|
+
s.rubygems_version = %q{1.5.0}
|
48
47
|
s.summary = %q{a toolkit for the CrowdFlower API}
|
49
48
|
s.test_files = [
|
50
49
|
"test/integration_tests.rb"
|
51
50
|
]
|
52
51
|
|
53
52
|
if s.respond_to? :specification_version then
|
54
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
53
|
s.specification_version = 3
|
56
54
|
|
57
55
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
data/lib/crowdflower.rb
CHANGED
data/lib/crowdflower/base.rb
CHANGED
@@ -13,42 +13,167 @@ module CrowdFlower
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
16
|
+
# a convenience method for backward compatibility
|
17
|
+
def self.connect!(key, development = false, version = 1)
|
18
|
+
Base.connect!(key, development, version)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.connect_domain!(key, domain_base, version = 1)
|
22
|
+
Base.connect_domain!(key, domain_base, version)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.connect_config!(opts)
|
26
|
+
Base.connect_config!(opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
# an object that stores connection details; does actual http talking
|
30
|
+
class Connection
|
31
|
+
include HTTParty
|
32
|
+
headers "accept" => "application/json"
|
33
|
+
format :json
|
34
|
+
|
35
|
+
attr_reader :key, :domain, :version, :domain_base, :ssl_port, :public_port
|
36
|
+
|
37
|
+
def initialize(key, domain_base, version, ssl_port = 443, public_port = 80)
|
38
|
+
@domain_base = domain_base
|
39
|
+
@version = version
|
40
|
+
@domain = "#{@domain_base}/v#{version}"
|
41
|
+
@key = key
|
42
|
+
@ssl_port = ssl_port
|
43
|
+
@public_port = public_port
|
44
|
+
begin # pass yaml file
|
45
|
+
key = YAML.load_file(key)
|
46
|
+
@key = key[:key] || key["key"]
|
47
|
+
rescue # pass key
|
48
|
+
@key = key
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# get, post, put and delete methods
|
53
|
+
def method_missing(method_id, *args)
|
54
|
+
if [:get, :post, :put, :delete].include?(method_id)
|
55
|
+
path, options = *args
|
56
|
+
options ||= {}
|
57
|
+
options[:body] = default_params.merge(options[:body] || {})
|
58
|
+
options[:query] = (default_params.merge(options[:query] || {}))
|
59
|
+
options[:headers] = (self.class.default_options[:headers].merge(options[:headers] || {}))
|
60
|
+
|
61
|
+
self.class.send(method_id, url(path), options)
|
62
|
+
else
|
63
|
+
super
|
31
64
|
end
|
32
65
|
end
|
66
|
+
|
67
|
+
# Returns the base crowdflower domain from the api url's domain.
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
# @return [String] the base crowdflower domain
|
71
|
+
# @example
|
72
|
+
# CrowdFlower::Connection.new("asdf", "https://api.crowdflower.com").crowdflower_base #=> "crowdflower.com"
|
73
|
+
def crowdflower_base
|
74
|
+
uri = URI.parse(domain_base)
|
75
|
+
"#{uri.host.gsub("api.", "")}"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the url to reach crowdflower regularly through a browser
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
# @return [String] the url to reach crowdflower in a browser
|
82
|
+
# @example
|
83
|
+
# CrowdFlower::Connection.new("asdf", "https://api.crowdflower.com").public_url #=> "crowdflower.com:80"
|
84
|
+
def public_url
|
85
|
+
"#{crowdflower_base}:#{public_port}"
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def url(path)
|
90
|
+
"#{@domain}/#{path}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_params
|
94
|
+
{'key' => @key}
|
95
|
+
end
|
33
96
|
end
|
34
97
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
98
|
+
|
99
|
+
# Base class for Crowdflower api entities.
|
100
|
+
# Now instead of one global configuration, each instance could maintain its own connection.
|
101
|
+
# If no connection is available for an instance it will look for default class-level or global
|
102
|
+
# connection settings, see Base#connection method.
|
103
|
+
# You can set class-specific connection with Base.connect! call
|
104
|
+
# for example:
|
105
|
+
# Job.connect!(api_key, development, version).
|
106
|
+
# It is possible to use several api keys simultaneously either by providing each entity instance
|
107
|
+
# with a specific Connection object or by creating entity subclasses that have their own default connections
|
108
|
+
# for example:
|
109
|
+
# CrowdFlower.connect!(default_api_key, development, version)
|
110
|
+
# (JobSubclass = Class.new(Job)).connect!(custom_api_key, development, version)
|
111
|
+
# job1 = Job.create('created with default api key')
|
112
|
+
# job2 = JobSubclass.create('created with custom api key')
|
113
|
+
class Base
|
114
|
+
|
115
|
+
def initialize(new_connection = nil)
|
116
|
+
@connection = new_connection
|
117
|
+
end
|
118
|
+
|
119
|
+
def connection
|
120
|
+
@connection or self.class.connection
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.connection
|
124
|
+
default_connection or (self != Base and superclass.connection)
|
125
|
+
end
|
126
|
+
|
127
|
+
class << self
|
128
|
+
attr_accessor :default_connection
|
44
129
|
end
|
45
|
-
end
|
46
130
|
|
47
|
-
|
48
|
-
|
49
|
-
|
131
|
+
def self.connect!(key, development = false, version = 1)
|
132
|
+
domain_base = development ? "https://api.localdev.crowdflower.com:8443" : "https://api.crowdflower.com"
|
133
|
+
connect_domain!(key, domain_base, version)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.connect_domain!(key, domain_base, version = 1)
|
137
|
+
self.default_connection = Connection.new(key, domain_base, version)
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.connect_config!(opts)
|
141
|
+
extract_option = lambda do |arr|
|
142
|
+
arr.map { |k| opts[k] || opts[k.to_s] }.compact.first
|
143
|
+
end
|
144
|
+
key = extract_option.call([:key, :api_key])
|
145
|
+
domain_base = extract_option.call([:domain_base, :domain])
|
146
|
+
version = extract_option.call([:version]) || 1
|
147
|
+
ssl_port = extract_option.call([:ssl_port]) || 443
|
148
|
+
public_port = extract_option.call([:public_port]) || 80
|
149
|
+
self.default_connection = Connection.new(key, domain_base, version, ssl_port, public_port)
|
150
|
+
end
|
50
151
|
|
51
|
-
|
52
|
-
|
152
|
+
def self.get(*args); connection.get(*args); end
|
153
|
+
def self.post(*args); connection.post(*args); end
|
154
|
+
def self.put(*args); connection.put(*args); end
|
155
|
+
def self.delete(*args); connection.delete(*args); end
|
156
|
+
|
157
|
+
def connect
|
158
|
+
unless connection
|
159
|
+
raise UsageError, "Please establish a connection using 'CrowdFlower.connect!'"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.connect
|
164
|
+
unless connection
|
165
|
+
raise UsageError, "Please establish a connection using 'CrowdFlower.connect!'"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.verify_response(response)
|
170
|
+
if response["errors"]
|
171
|
+
raise CrowdFlower::APIError.new(response["errors"])
|
172
|
+
elsif response.response.kind_of? Net::HTTPUnauthorized
|
173
|
+
raise CrowdFlower::APIError.new('message' => response.to_s)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
53
177
|
end
|
178
|
+
|
54
179
|
end
|
data/lib/crowdflower/job.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module CrowdFlower
|
2
|
-
class Job
|
3
|
-
include Defaults
|
2
|
+
class Job < Base
|
4
3
|
attr_reader :id
|
5
4
|
|
6
|
-
def initialize(job_id)
|
5
|
+
def initialize(job_id, connection = nil)
|
6
|
+
super connection
|
7
7
|
@id = job_id
|
8
|
-
|
8
|
+
connect
|
9
9
|
end
|
10
10
|
|
11
11
|
def resource_uri
|
@@ -21,30 +21,30 @@ module CrowdFlower
|
|
21
21
|
get(resource_uri)
|
22
22
|
end
|
23
23
|
|
24
|
-
def self.upload(file, content_type,
|
24
|
+
def self.upload(file, content_type, job = nil)
|
25
25
|
connect
|
26
|
-
|
27
|
-
|
26
|
+
|
27
|
+
job_uri = job ? "/#{job.kind_of?(Job) ? job.id : job}" : ""
|
28
|
+
conn = job.kind_of?(Job) ? job.connection : self.connection
|
29
|
+
upload_uri = "#{resource_uri}/#{job_uri}/upload".squeeze("/")
|
30
|
+
res = conn.post(upload_uri,
|
28
31
|
:body => File.read(file),
|
29
|
-
:headers =>
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Job.new(res["id"])
|
32
|
+
:headers => {"content-type" => content_type})
|
33
|
+
|
34
|
+
verify_response res
|
35
|
+
job.kind_of?(Job) ? job : self.new(res["id"], conn)
|
34
36
|
end
|
35
37
|
|
36
38
|
# Creates a new empty Job in CrowdFlower.
|
37
39
|
def self.create(title)
|
38
40
|
connect
|
39
|
-
res = post("#{resource_uri}.json", :query => {:job => {:title => title } }, :headers => { "Content-Length" => "0" } )
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
Job.new(res["id"])
|
41
|
+
res = self.post("#{resource_uri}.json", :query => {:job => {:title => title } }, :headers => { "Content-Length" => "0" } )
|
42
|
+
verify_response res
|
43
|
+
self.new(res["id"])
|
44
44
|
end
|
45
45
|
|
46
46
|
def get(id = nil)
|
47
|
-
|
47
|
+
connection.get("#{resource_uri}/#{@id || id}")
|
48
48
|
end
|
49
49
|
|
50
50
|
# Returns an accessor for all the Units associated with this job.
|
@@ -63,28 +63,27 @@ module CrowdFlower
|
|
63
63
|
# gold: when set to true copies gold units
|
64
64
|
# all_units: when set to true copies all units
|
65
65
|
def copy(opts = {})
|
66
|
-
res =
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
Job.new(res["id"])
|
66
|
+
res = connection.get("#{resource_uri}/#{@id}/copy", {:query => opts})
|
67
|
+
self.class.verify_response res
|
68
|
+
self.class.new(res["id"])
|
71
69
|
end
|
72
70
|
|
73
71
|
def status
|
74
|
-
|
72
|
+
connection.get("#{resource_uri}/#{@id}/ping")
|
75
73
|
end
|
76
74
|
|
77
75
|
def upload(file, content_type)
|
78
|
-
|
76
|
+
self.class.upload(file, content_type, self)
|
79
77
|
end
|
80
78
|
|
81
79
|
def legend
|
82
|
-
|
80
|
+
connection.get("#{resource_uri}/#{@id}/legend")
|
83
81
|
end
|
84
82
|
|
85
83
|
def download_csv(type = :full, filename = nil)
|
86
84
|
filename ||= "#{type.to_s[0].chr}#{@id}.csv"
|
87
|
-
res =
|
85
|
+
res = connection.get("#{resource_uri}/#{@id}.csv", {:format => :csv, :query => {:type => type}})
|
86
|
+
self.class.verify_response res
|
88
87
|
puts "Status... #{res.code.inspect}"
|
89
88
|
if res.code == 202
|
90
89
|
puts "CSV Generating... Trying again in 10 seconds."
|
@@ -97,40 +96,34 @@ module CrowdFlower
|
|
97
96
|
end
|
98
97
|
|
99
98
|
def pause
|
100
|
-
|
99
|
+
connection.get("#{resource_uri}/#{@id}/pause")
|
101
100
|
end
|
102
101
|
|
103
102
|
def resume
|
104
|
-
|
103
|
+
connection.get("#{resource_uri}/#{@id}/resume")
|
105
104
|
end
|
106
105
|
|
107
106
|
def cancel
|
108
|
-
|
107
|
+
connection.get("#{resource_uri}/#{@id}/cancel")
|
109
108
|
end
|
110
109
|
|
111
110
|
def update(data)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
111
|
+
response = connection.put("#{resource_uri}/#{@id}.json", {:body => { :job => data }, :headers => { "Content-Length" => "0" } } )
|
112
|
+
self.class.verify_response(response)
|
113
|
+
response
|
116
114
|
end
|
117
115
|
|
118
116
|
def delete
|
119
|
-
|
117
|
+
connection.delete("#{resource_uri}/#{@id}.json")
|
120
118
|
end
|
121
119
|
|
122
120
|
def channels
|
123
|
-
|
121
|
+
connection.get("#{resource_uri}/#{@id}/channels")
|
124
122
|
end
|
125
123
|
|
126
124
|
def enable_channels(channels)
|
127
|
-
|
125
|
+
connection.post("#{resource_uri}/#{@id}/channels", {:body => { :channels => channels } } )
|
128
126
|
end
|
129
127
|
|
130
|
-
private
|
131
|
-
def self.custom_content_type(content_type)
|
132
|
-
#To preserve the accept header we are forced to merge the defaults back in...
|
133
|
-
Job.default_options[:headers].merge({"content-type" => content_type})
|
134
|
-
end
|
135
128
|
end
|
136
129
|
end
|
data/lib/crowdflower/judgment.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module CrowdFlower
|
2
|
-
class Judgment
|
3
|
-
include Defaults
|
2
|
+
class Judgment < Base
|
4
3
|
attr_reader :job
|
5
4
|
|
6
5
|
def initialize(job)
|
6
|
+
super job.connection
|
7
7
|
@job = job
|
8
|
-
|
8
|
+
connect
|
9
9
|
end
|
10
10
|
|
11
11
|
def resource_uri
|
@@ -13,13 +13,32 @@ module CrowdFlower
|
|
13
13
|
end
|
14
14
|
|
15
15
|
#Pull every judgment
|
16
|
-
def all(page = 1, limit = 100, latest = true)
|
17
|
-
opts =
|
18
|
-
|
16
|
+
def all(page = 1, limit = 100, latest = true)
|
17
|
+
opts = CrowdFlower.version == 2 ? {:unseen => latest} : {:latest => latest}
|
18
|
+
get(resource_uri, {:query => {:limit => limit, :page => page}.merge(opts)})
|
19
19
|
end
|
20
20
|
|
21
21
|
def get(id)
|
22
|
-
|
22
|
+
get("#{resource_uri}/#{id}")
|
23
|
+
end
|
24
|
+
|
25
|
+
# Reject an individual Judgment.
|
26
|
+
#
|
27
|
+
# *Admin-only && MTurk-only*
|
28
|
+
#
|
29
|
+
# @param [String,Integer] id The CrowdFlower id for the judgment to reject.
|
30
|
+
def reject( id )
|
31
|
+
put( "#{resource_uri}/#{id}/reject" )
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def put( *args )
|
37
|
+
connection.put *args
|
38
|
+
end
|
39
|
+
|
40
|
+
def get( *args )
|
41
|
+
connection.get *args
|
23
42
|
end
|
24
43
|
end
|
25
|
-
end
|
44
|
+
end
|
data/lib/crowdflower/order.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module CrowdFlower
|
2
|
-
class Order
|
3
|
-
include Defaults
|
2
|
+
class Order < Base
|
4
3
|
attr_reader :job
|
5
4
|
|
6
5
|
def initialize(job)
|
6
|
+
super job.connection
|
7
7
|
@job = job
|
8
|
-
|
8
|
+
connect
|
9
9
|
end
|
10
10
|
|
11
11
|
def resource_uri
|
@@ -13,7 +13,7 @@ module CrowdFlower
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def debit(units_count = 1, channels = ["amt"])
|
16
|
-
|
16
|
+
connection.post(resource_uri, {:query => {:debit => {:units_count => units_count}, :channels => channels}})
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/crowdflower/unit.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module CrowdFlower
|
2
|
-
class Unit
|
3
|
-
include Defaults
|
2
|
+
class Unit < Base
|
4
3
|
attr_reader :job
|
5
4
|
|
6
5
|
def initialize(job)
|
6
|
+
super job.connection
|
7
7
|
@job = job
|
8
|
-
|
8
|
+
connect
|
9
9
|
end
|
10
10
|
|
11
11
|
def resource_uri
|
@@ -13,35 +13,35 @@ module CrowdFlower
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def all(page = 1, limit = 1000)
|
16
|
-
|
16
|
+
connection.get(resource_uri, {:query => {:limit => limit, :page => page}})
|
17
17
|
end
|
18
18
|
|
19
19
|
def get(id)
|
20
|
-
|
20
|
+
connection.get("#{resource_uri}/#{id}")
|
21
21
|
end
|
22
22
|
|
23
23
|
def ping
|
24
|
-
|
24
|
+
connection.get("#{resource_uri}/ping")
|
25
25
|
end
|
26
26
|
|
27
27
|
def judgments(id)
|
28
|
-
|
28
|
+
connection.get("#{resource_uri}/#{id}/judgments")
|
29
29
|
end
|
30
30
|
|
31
31
|
def create(data, gold = false)
|
32
|
-
|
32
|
+
connection.post(resource_uri, {:query => {:unit => {:data => data.to_json, :golden => gold}}})
|
33
33
|
end
|
34
34
|
|
35
35
|
def copy(unit_id, job_id, data = {})
|
36
|
-
|
36
|
+
connection.get("#{resource_uri}/#{unit_id}/copy", {:query => {:unit => {:job_id => job_id, :data => data}}})
|
37
37
|
end
|
38
38
|
|
39
39
|
def split(on, with = " ")
|
40
|
-
|
40
|
+
connection.get("#{resource_uri}/split", {:query => {:on => on, :with => with}})
|
41
41
|
end
|
42
42
|
|
43
43
|
def cancel(unit_id)
|
44
|
-
|
44
|
+
connection.post("#{resource_uri}/#{unit_id}/cancel.json")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module CrowdFlower
|
2
|
+
class Worker < Base
|
3
|
+
attr_reader :job
|
4
|
+
|
5
|
+
def initialize( job )
|
6
|
+
super job.connection
|
7
|
+
@job = job
|
8
|
+
connect
|
9
|
+
end
|
10
|
+
|
11
|
+
def resource_uri
|
12
|
+
"/jobs/#{@job.id}/workers"
|
13
|
+
end
|
14
|
+
|
15
|
+
def bonus( worker_id, amount, reason=nil )
|
16
|
+
params = { :amount => amount }
|
17
|
+
params.merge!( :reason => reason ) if reason
|
18
|
+
connection.put( "#{resource_uri}/#{worker_id}/bonus", :body => params )
|
19
|
+
end
|
20
|
+
|
21
|
+
def approve( worker_id )
|
22
|
+
connection.put( "#{resource_uri}/#{worker_id}/approve" )
|
23
|
+
end
|
24
|
+
|
25
|
+
def reject( worker_id )
|
26
|
+
connection.put( "#{resource_uri}/#{worker_id}/reject" )
|
27
|
+
end
|
28
|
+
|
29
|
+
def ban( worker_id )
|
30
|
+
connection.put( "#{resource_uri}/#{worker_id}/ban" )
|
31
|
+
end
|
32
|
+
|
33
|
+
def deban( worker_id )
|
34
|
+
connection.put( "#{resource_uri}/#{worker_id}/deban" )
|
35
|
+
end
|
36
|
+
|
37
|
+
def notify( worker_id, subject, message )
|
38
|
+
params = {
|
39
|
+
:subject => subject,
|
40
|
+
:message => message
|
41
|
+
}
|
42
|
+
connection.put( "#{resource_uri}/#{worker_id}/notify", :body => params )
|
43
|
+
end
|
44
|
+
|
45
|
+
def flag( worker_id, reason )
|
46
|
+
params = reason ? { :reason => reason } : nil
|
47
|
+
connection.put( "#{resource_uri}/#{worker_id}/flag", :body => params )
|
48
|
+
end
|
49
|
+
|
50
|
+
def deflag( worker_id )
|
51
|
+
connection.put( "#{resource_uri}/#{worker_id}/deflag" )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/test/integration_tests.rb
CHANGED
@@ -36,7 +36,7 @@ def wait_until
|
|
36
36
|
if yield
|
37
37
|
return
|
38
38
|
end
|
39
|
-
sleep
|
39
|
+
sleep 5
|
40
40
|
end
|
41
41
|
raise "Condition not met in a reasonable time period"
|
42
42
|
end
|
@@ -47,13 +47,48 @@ def assert(truth)
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
def assert_exception_raised expected_exception_class
|
51
|
+
begin
|
52
|
+
yield
|
53
|
+
rescue expected_exception_class
|
54
|
+
return
|
55
|
+
end
|
56
|
+
raise "exception #{expected_ex} has not been raised"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
50
60
|
def say(msg)
|
51
61
|
$stdout.puts msg
|
52
62
|
end
|
53
63
|
|
64
|
+
|
65
|
+
say "defining multiple api keys"
|
66
|
+
(job_subclass_with_valid_custom_key = Class.new(CrowdFlower::Job)).connect! API_KEY, true
|
67
|
+
(job_subclass_with_invalid_custom_key = Class.new(CrowdFlower::Job)).connect! 'invalid api key', true
|
68
|
+
job_subclass_with_no_custom_key = Class.new(CrowdFlower::Job)
|
69
|
+
|
70
|
+
say "no default api key"
|
71
|
+
assert_exception_raised(CrowdFlower::UsageError) {CrowdFlower::Job.create("job creation should fail")}
|
72
|
+
assert_exception_raised(CrowdFlower::UsageError) {job_subclass_with_no_custom_key.create("job creation should fail")}
|
73
|
+
assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
|
74
|
+
assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
|
75
|
+
|
76
|
+
say "invalid default api key"
|
77
|
+
CrowdFlower.connect! "invalid default api key", true
|
78
|
+
assert_exception_raised(CrowdFlower::APIError) {CrowdFlower::Job.create("job creation should fail")}
|
79
|
+
assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_no_custom_key.create("job creation should fail")}
|
80
|
+
assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
|
81
|
+
assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
|
82
|
+
|
54
83
|
say "Connecting to the API"
|
55
84
|
CrowdFlower.connect! API_KEY, true
|
56
85
|
|
86
|
+
assert CrowdFlower::Job.create("should be ok").units.ping['count']
|
87
|
+
assert job_subclass_with_no_custom_key.create("should be ok").units.ping['count']
|
88
|
+
assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
|
89
|
+
assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
|
90
|
+
assert CrowdFlower::Base.connection.public_url == "localdev.crowdflower.com:80"
|
91
|
+
|
57
92
|
say "Uploading a test CSV"
|
58
93
|
job = CrowdFlower::Job.upload(File.dirname(__FILE__) + "/sample.csv", "text/csv")
|
59
94
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crowdflower
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 13
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 4
|
9
8
|
- 5
|
10
|
-
|
9
|
+
- 3
|
10
|
+
version: 0.5.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian P O'Rourke
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date:
|
19
|
+
date: 2011-02-10 00:00:00 -08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -50,7 +50,6 @@ extra_rdoc_files:
|
|
50
50
|
- README.md
|
51
51
|
files:
|
52
52
|
- .document
|
53
|
-
- .gitignore
|
54
53
|
- CONTRIBUTORS
|
55
54
|
- HISTORY.md
|
56
55
|
- LICENSE
|
@@ -66,6 +65,7 @@ files:
|
|
66
65
|
- lib/crowdflower/judgment.rb
|
67
66
|
- lib/crowdflower/order.rb
|
68
67
|
- lib/crowdflower/unit.rb
|
68
|
+
- lib/crowdflower/worker.rb
|
69
69
|
- test/integration_tests.rb
|
70
70
|
- test/sample.csv
|
71
71
|
has_rdoc: true
|
@@ -73,8 +73,8 @@ homepage: http://github.com/dolores/ruby-crowdflower
|
|
73
73
|
licenses: []
|
74
74
|
|
75
75
|
post_install_message:
|
76
|
-
rdoc_options:
|
77
|
-
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
78
|
require_paths:
|
79
79
|
- lib
|
80
80
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
98
|
requirements: []
|
99
99
|
|
100
100
|
rubyforge_project:
|
101
|
-
rubygems_version: 1.
|
101
|
+
rubygems_version: 1.4.2
|
102
102
|
signing_key:
|
103
103
|
specification_version: 3
|
104
104
|
summary: a toolkit for the CrowdFlower API
|