crowdflower 0.4.5 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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.4.5
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 the gemspec command
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.4.5"
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{2010-12-03}
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
- "README.md"
21
+ "README.md"
22
22
  ]
23
23
  s.files = [
24
24
  ".document",
25
- ".gitignore",
26
- "CONTRIBUTORS",
27
- "HISTORY.md",
28
- "LICENSE",
29
- "README.md",
30
- "Rakefile",
31
- "VERSION",
32
- "bindev/cl_skel.rb",
33
- "bindev/crowdflower.rb",
34
- "crowdflower.gemspec",
35
- "lib/crowdflower.rb",
36
- "lib/crowdflower/base.rb",
37
- "lib/crowdflower/job.rb",
38
- "lib/crowdflower/judgment.rb",
39
- "lib/crowdflower/order.rb",
40
- "lib/crowdflower/unit.rb",
41
- "test/integration_tests.rb",
42
- "test/sample.csv"
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.3.7}
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
@@ -1,5 +1,5 @@
1
1
  require 'httparty'
2
2
 
3
- %w{base job unit judgment order}.each do |file|
3
+ %w{base job unit judgment order worker}.each do |file|
4
4
  require File.dirname(__FILE__) +"/crowdflower/" + file
5
5
  end
@@ -13,42 +13,167 @@ module CrowdFlower
13
13
  end
14
14
  end
15
15
 
16
- module Defaults
17
- def self.included(base)
18
- base.send :include, HTTParty
19
- base.send :headers, "accept" => "application/json"
20
- base.send :format, :json
21
- base.extend ClassMethods
22
- end
23
-
24
- module ClassMethods
25
- def connect
26
- unless CrowdFlower.key
27
- raise UsageError, "Please establish a connection using 'CrowdFlower.connect!'"
28
- end
29
- self.base_uri CrowdFlower.domain
30
- self.default_params :key => CrowdFlower.key
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
- def self.connect!(key, development = false, version = 1)
36
- @@version = version
37
- @@domain = development ? "http://api.localhost.com:4000/v#{version}" : "https://api.crowdflower.com/v#{version}"
38
- @@key = key
39
- begin # pass yaml file
40
- key = YAML.load_file(key)
41
- @@key = key[:key] || key["key"]
42
- rescue # pass key
43
- @@key = key
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
- def self.key
48
- @@key
49
- end
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
- def self.domain
52
- @@domain
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
@@ -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
- Job.connect
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, job_id = nil)
24
+ def self.upload(file, content_type, job = nil)
25
25
  connect
26
- job_uri = job_id ? "/#{job_id}" : ""
27
- res = post("#{resource_uri}/#{job_uri}/upload",
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 => custom_content_type(content_type))
30
- if res["error"]
31
- raise CrowdFlower::APIError.new(res["error"])
32
- end
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
- if res["error"]
41
- raise CrowdFlower::APIError.new(res["error"])
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
- Job.get("#{resource_uri}/#{@id || id}")
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 = Job.get("#{resource_uri}/#{@id}/copy", {:query => opts})
67
- if res["error"]
68
- raise CrowdFlower::APIError.new(res["error"])
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
- Job.get("#{resource_uri}/#{@id}/ping")
72
+ connection.get("#{resource_uri}/#{@id}/ping")
75
73
  end
76
74
 
77
75
  def upload(file, content_type)
78
- Job.upload(file, content_type, @id)
76
+ self.class.upload(file, content_type, self)
79
77
  end
80
78
 
81
79
  def legend
82
- Job.get("#{resource_uri}/#{@id}/legend")
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 = Job.get("#{resource_uri}/#{@id}.csv", {:format => :csv, :query => {:type => type}})
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
- Job.get("#{resource_uri}/#{@id}/pause")
99
+ connection.get("#{resource_uri}/#{@id}/pause")
101
100
  end
102
101
 
103
102
  def resume
104
- Job.get("#{resource_uri}/#{@id}/resume")
103
+ connection.get("#{resource_uri}/#{@id}/resume")
105
104
  end
106
105
 
107
106
  def cancel
108
- Job.get("#{resource_uri}/#{@id}/cancel")
107
+ connection.get("#{resource_uri}/#{@id}/cancel")
109
108
  end
110
109
 
111
110
  def update(data)
112
- res = Job.put("#{resource_uri}/#{@id}.json", {:body => { :job => data }, :headers => { "Content-Length" => "0" } } )
113
- if res["error"]
114
- raise CrowdFlower::APIError.new(res["error"])
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
- Job.delete("#{resource_uri}/#{@id}.json")
117
+ connection.delete("#{resource_uri}/#{@id}.json")
120
118
  end
121
119
 
122
120
  def channels
123
- Job.get("#{resource_uri}/#{@id}/channels")
121
+ connection.get("#{resource_uri}/#{@id}/channels")
124
122
  end
125
123
 
126
124
  def enable_channels(channels)
127
- Job.post("#{resource_uri}/#{@id}/channels", {:body => { :channels => channels } } )
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
@@ -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
- Judgment.connect
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)#full = true
17
- opts = @@version == 2 ? {:unseen => latest} : {:latest => latest}
18
- Judgment.get(resource_uri, {:query => {:limit => limit, :page => page}.merge(opts)})
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
- Judgment.get("/#{id}")
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
@@ -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
- Order.connect
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
- Order.post(resource_uri, {:query => {:debit => {:units_count => units_count}, :channels => channels}})
16
+ connection.post(resource_uri, {:query => {:debit => {:units_count => units_count}, :channels => channels}})
17
17
  end
18
18
  end
19
19
  end
@@ -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
- Unit.connect
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
- Unit.get(resource_uri, {:query => {:limit => limit, :page => page}})
16
+ connection.get(resource_uri, {:query => {:limit => limit, :page => page}})
17
17
  end
18
18
 
19
19
  def get(id)
20
- Unit.get("#{resource_uri}/#{id}")
20
+ connection.get("#{resource_uri}/#{id}")
21
21
  end
22
22
 
23
23
  def ping
24
- Unit.get("#{resource_uri}/ping")
24
+ connection.get("#{resource_uri}/ping")
25
25
  end
26
26
 
27
27
  def judgments(id)
28
- Unit.get("#{resource_uri}/#{id}/judgments")
28
+ connection.get("#{resource_uri}/#{id}/judgments")
29
29
  end
30
30
 
31
31
  def create(data, gold = false)
32
- Unit.post(resource_uri, {:query => {:unit => {:data => data.to_json, :golden => gold}}})
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
- Unit.get("#{resource_uri}/#{unit_id}/copy", {:query => {:unit => {:job_id => job_id, :data => data}}})
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
- Unit.get("#{resource_uri}/split", {:query => {:on => on, :with => with}})
40
+ connection.get("#{resource_uri}/split", {:query => {:on => on, :with => with}})
41
41
  end
42
42
 
43
43
  def cancel(unit_id)
44
- Unit.post("#{resource_uri}/#{unit_id}/cancel.json")
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
@@ -36,7 +36,7 @@ def wait_until
36
36
  if yield
37
37
  return
38
38
  end
39
- sleep 1
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
5
- prerelease: false
4
+ hash: 13
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
- - 4
9
8
  - 5
10
- version: 0.4.5
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: 2010-12-03 00:00:00 -08:00
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
- - --charset=UTF-8
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.3.7
101
+ rubygems_version: 1.4.2
102
102
  signing_key:
103
103
  specification_version: 3
104
104
  summary: a toolkit for the CrowdFlower API
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- *.sw?
2
- .DS_Store
3
- coverage
4
- rdoc
5
- pkg
6
- tags/.loadpath
7
- /.project
8
- /.loadpath