Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Mark Percival
committed
Oct 15, 2009
1 parent
88d1c86
commit cf4b266
Showing
16 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Fakeweb all requests, should be able to turn off | ||
Better error handling and checking | ||
Operations should include request? |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
module RTurk | ||
|
||
class Qualifications | ||
|
||
# For more information about qualification requirements see: | ||
# http://docs.amazonwebservices.com/AWSMturkAPI/2008-08-02/index.html?ApiReference_QualificationRequirementDataStructureArticle.html | ||
# | ||
|
||
COMPARATORS = {:gt => 'GreaterThan', :lt => 'LessThan', :gte => 'GreaterThanOrEqualTo', | ||
:lte => 'LessThanOrEqualTo', :eql => 'EqualTo', :not => 'NotEqualTo', :exists => 'Exists'} | ||
|
||
TYPES = {:approval_rate => '000000000000000000L0', :submission_rate => '00000000000000000000', | ||
:abandoned_rate => '0000000000000000007', :return_rate => '000000000000000000E0', | ||
:rejection_rate => '000000000000000000S0', :hits_approved => '00000000000000000040', | ||
:adult => '00000000000000000060', :country => '00000000000000000071'} | ||
|
||
attr_accessor :requirements, :types | ||
|
||
def initialize | ||
@requirements = [] | ||
@types = {} | ||
end | ||
|
||
|
||
# Builds the basic requirements for a qualification | ||
# needs at the minimum | ||
# :type_id, :comparator => :value | ||
# | ||
def build (opts) | ||
# If the value is a string, we can assume it's the country since, | ||
# Amazon states that there can be only integer values and countries | ||
operation = opts.reject{|k,v| !COMPARATORS.include?(k)} | ||
comparator = COMPARATORS[operation.keys.first] | ||
value = operation.values.first | ||
params = {} | ||
value = 1 if value == true # For boolean types eg. Adult | ||
if value.to_s.match(/[A-Z]./) | ||
params[:Country] = value | ||
else | ||
params[:IntegerValue] = value | ||
end | ||
params = params.merge({:QualificationTypeId => opts[:type_id], | ||
:Comparator => comparator, :RequiredToPreview => opts[:required_to_preview]}) | ||
end | ||
|
||
def to_aws_params | ||
params = {} | ||
@requirements.each_with_index do |qualifier, i| | ||
params["QualificationRequirement.#{i+1}.QualificationTypeId"] = qualifier[:QualificationTypeId] | ||
params["QualificationRequirement.#{i+1}.Comparator"] = qualifier[:Comparator] | ||
params["QualificationRequirement.#{i+1}.IntegerValue"] = qualifier[:IntegerValue] if qualifier[:IntegerValue] | ||
params["QualificationRequirement.#{i+1}.LocaleValue.Country"] = qualifier[:Country] if qualifier[:Country] | ||
params["QualificationRequirement.#{i+1}.RequiredToPreview"] = qualifier[:RequiredToPreview] || 'true' | ||
end | ||
params | ||
end | ||
|
||
# Can use this to manually add custom requirement types | ||
# Needs a type name(you can reference this later) | ||
# and the operation as a hash: ':gt => 85' | ||
# Example | ||
# qualifications.add('EnglishSkillsRequirement', :gt => 66, :type_id => '1234567890123456789ABC') | ||
# | ||
def add(opts) | ||
@requirements << self.build(opts) | ||
end | ||
|
||
# This lets you add a custom named type to the list | ||
# Example | ||
# qualifications.add_type(:custom_requirement, '1234567890123456789ABC') | ||
# qualifications.custom_requirement(:gte => 55) | ||
# | ||
def add_type(name, type_id) | ||
@types[name.to_sym] = type_id | ||
end | ||
|
||
def method_missing(method, opts) | ||
if opts == true || opts == false | ||
# allows us to call booleans on a method | ||
# e.g. qualifications.adult(true) | ||
opts = {:eql => opts} | ||
end | ||
if types.include?(method) | ||
opts.merge!({:type_id => types[method]}) | ||
self.add(opts) | ||
end | ||
end | ||
|
||
def types | ||
TYPES.merge(@types) | ||
end | ||
|
||
end | ||
|
||
|
||
end | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
require 'cgi' | ||
|
||
module RTurk | ||
class Question | ||
|
||
attr_accessor :url, :url_params, :frame_height | ||
|
||
def initialize(url = nil, opts = {}) | ||
@url = url | ||
self.frame_height = opts.delete(:frame_height) || 400 | ||
self.url_params = opts | ||
end | ||
|
||
def querystring | ||
@url_params.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&') | ||
end | ||
|
||
def url | ||
unless querystring.empty? | ||
# slam the params onto url, if url already has params, add 'em with a & | ||
@url.index('?') ? "#{@url}&#{querystring}" : "#{@url}?#{querystring}" | ||
else | ||
@url | ||
end | ||
end | ||
|
||
def params | ||
@url_params | ||
end | ||
|
||
def params=(param_set) | ||
@url_params = param_set | ||
end | ||
|
||
def to_aws_params | ||
raise MissingURL, "needs a url to build an external question" unless @url | ||
# TODO: update the xmlns schema... maybe | ||
xml = <<-XML | ||
<ExternalQuestion xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2006-07-14/ExternalQuestion.xsd"> | ||
<ExternalURL>#{url}</ExternalURL> | ||
<FrameHeight>#{frame_height}</FrameHeight> | ||
</ExternalQuestion> | ||
XML | ||
xml | ||
end | ||
|
||
end | ||
|
||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module RTurk | ||
module Credentials | ||
|
||
SANDBOX = 'http://mechanicalturk.sandbox.amazonaws.com/' | ||
PRODUCTION = 'http://mechanicalturk.amazonaws.com/' | ||
|
||
attr_reader :access_key, :secret_key, :host | ||
|
||
def initialize(access_key, secret_key, opts ={}) | ||
@access_key = access_key | ||
@secret_key = secret_key | ||
@host = opts[:sandbox] ? SANDBOX : PRODUCTION | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
require 'logger' | ||
|
||
module RTurk | ||
module Logging | ||
def logger=(logger_obj) | ||
@logger = logger_obj | ||
end | ||
|
||
def logger | ||
unless @logger | ||
@logger = Logger.new(STDOUT) | ||
@logger.level = Logger::INFO | ||
end | ||
@logger | ||
end | ||
|
||
def log_level=(level=Logger::INFO) | ||
logger.level = level | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
module RTurk | ||
class CreateHit < Operation | ||
# | ||
# We perform the magic here to create a HIT with the minimum amount of fuss. | ||
# You should be able to pass in a hash with all the setting(ala YAML) or | ||
# do all the config in a block. | ||
# | ||
|
||
attr_accessor :title, :keywords, :description, :reward, :currency, :assignments | ||
attr_accessor :lifetime, :duration, :auto_approval, :note, :qualifications | ||
|
||
|
||
def initialize(opts = {}) | ||
opts.each_pair do |k,v| | ||
if v.is_a? Hash | ||
obj = self.send k.to_sym | ||
v.each_pair do |key,val| | ||
obj.send key.to_sym, val | ||
end | ||
elsif self.respond_to?("#{k.to_sym}=") | ||
self.send "#{k}=".to_sym, v | ||
elsif self.respond_to?(k.to_sym) | ||
self.send k.to_sym, v | ||
end | ||
end | ||
yield(self) if block_given? | ||
end | ||
|
||
def qualification | ||
@qualifications ||= RTurk::Qualifications.new | ||
end | ||
|
||
def question | ||
@question ||= RTurk::Question.new | ||
end | ||
|
||
def to_aws_params | ||
hit_params.merge(qualification.to_aws_params) | ||
end | ||
|
||
def response(xml) | ||
RTurk::CreateHitResponse.parse(xml) | ||
end | ||
|
||
private | ||
|
||
def hit_params | ||
{'Title'=>self.title, | ||
'MaxAssignments' => self.assignments, | ||
'LifetimeInSeconds'=> self.lifetime, | ||
'Reward.Amount' => self.reward, | ||
'Reward.CurrencyCode' => (self.currency || 'USD'), | ||
'Keywords' => self.keywords, | ||
'Description' => self.description, | ||
'RequesterAnnotation' => note} | ||
end | ||
|
||
RTurk::Operation.register('create_hit', self) | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module RTurk | ||
class GetAnswer < Operation | ||
def get_it | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module RTurk | ||
class AnswerParser | ||
|
||
def self.parse(xml) | ||
answer = XmlSimple.xml_in(xml, {'ForceArray' => false}) | ||
response = {} | ||
answers = answer['Answer'] | ||
answers = Array.new(1) { answers } unless answers.instance_of? Array | ||
answers.each do |a| | ||
question = a['QuestionIdentifier'] | ||
a.delete('QuestionIdentifier') | ||
a.each_value do |v| | ||
response[question] = v | ||
end | ||
end | ||
response | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module RTurk | ||
|
||
class BasicResponse < Response | ||
|
||
def parsed_xml | ||
@parsed_xml ||= XmlSimple.xml_in(@xml.to_s, {'ForceArray' => false}) | ||
end | ||
|
||
def success? | ||
!parsed_xml['HIT']['Request'].include?('Errors') | ||
end | ||
|
||
def [](key) | ||
parsed_xml[key] | ||
end | ||
|
||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module RTurk | ||
class HitResponse < Response | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<CreateHITResponse> | ||
<OperationRequest> | ||
<RequestId>ece2785b-6292-4b12-a60e-4c34847a7916</RequestId> | ||
</OperationRequest> | ||
<HIT> | ||
<Request> | ||
<IsValid>True</IsValid> | ||
</Request> | ||
<HITId>GBHZVQX3EHXZ2AYDY2T0</HITId> | ||
<HITTypeId>NYVZTQ1QVKJZXCYZCZVZ</HITTypeId> | ||
</HIT> | ||
</CreateHITResponse> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
require File.dirname(__FILE__) + '/spec_helper' | ||
|
||
describe "The creation of a HIT operation" do | ||
|
||
before(:all) do | ||
aws = YAML.load(File.open(File.join(SPEC_ROOT, 'mturk.yml'))) | ||
@turk = RTurk::Requester.new(aws['AWSAccessKeyId'], aws['AWSAccessKey'], :sandbox => true) | ||
end | ||
|
||
it "should allow us to create HIT's in a ruby'esque way" do | ||
|
||
hit = RTurk::Hit.new(:assignments => 5) do |hit| | ||
hit.qualification.approval :gt => 90 | ||
hit.qualification.country :not => 'PH' | ||
hit.qualification.adult true | ||
hit.title = "Look at some dirty pictures from 4Chan" | ||
hit.question('http://mpercival.com', :chapter => 1) | ||
hit.question.params[:chapter] = 2 #change the parameters | ||
end | ||
|
||
hit.assignments.should eql 5 | ||
hit.title.should eql "Look at some dirty pictures from 4Chan" | ||
hit.question.url.should == "http://mpercival.com?chapter=2" | ||
end | ||
|
||
it "should allow us to create HIT's with a hash from yaml" do | ||
|
||
hit = RTurk::Hit.new(:assignments => 5, :title => "Look at some dirty pictures from 4Chan", | ||
:question => 'http://mpercival.com', :assignments => 5, | ||
:qualification => | ||
{ | ||
:approval => {:gt => 90}, | ||
:adult => true, | ||
:country => {:not => 'PH'} | ||
}, | ||
:description => "Get paid in nickels!") | ||
hit.assignments.should eql 5 | ||
hit.title.should eql "Look at some dirty pictures from 4Chan" | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
:Description: Simply write a twitter update for me | ||
:LifetimeInSeconds: 3600 | ||
:RequesterAnnotation: OptionalNote | ||
:Reward: | ||
:Amount: 0.1 | ||
:CurrencyCode: USD | ||
:AssignmentDurationInSeconds: 3600 | ||
:AutoApprovalDelayInSeconds: 3600 | ||
:QualificationRequirement: | ||
- :IntegerValue: 90 | ||
:Comparator: GreaterThan | ||
:RequiredToPreview: "false" | ||
:QualificationTypeId: 000000000000000000L0 | ||
:Title: Write a twitter update | ||
:Keywords: twitter, blogging, writing, english | ||
:MaxAssignments: 1 |
Oops, something went wrong.