Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

use Erector for QuestionForm and AnswerKey builders

  • Loading branch information...
commit b67551127e44c10b8a9ab188cdd2822fa4fe532d 1 parent 84f8847
@alexch authored
View
1  .rspec
@@ -0,0 +1 @@
+--color
View
17 Gemfile
@@ -1,7 +1,16 @@
source "http://rubygems.org"
+
gem 'nokogiri'
-gem 'jeweler'
-gem 'webmock'
gem 'rest-client'
-gem 'rspec', "~>2"
-gem 'fakeweb'
+gem "erector", ">= 0.9.0.pre"
+
+group :development do
+ gem 'jeweler'
+end
+
+group :development, :test do
+ gem 'webmock'
+ gem 'rspec', "~>2"
+ gem 'fakeweb'
+ gem "wrong"
+end
View
39 lib/rturk/builders/answer_key_builder.rb
@@ -0,0 +1,39 @@
+require "erector/xml_widget"
+
+# see http://docs.amazonwebservices.com/AWSMechTurk/2008-08-02/AWSMturkAPI/index.html?ApiReference_CreateQualificationTypeOperation.html
+class RTurk::AnswerKey < Erector::XMLWidget
+
+ XMLNS = "http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/AnswerKey.xsd"
+
+ %w{
+ AnswerKey
+ Question
+ QuestionIdentifier
+ AnswerOption
+ SelectionIdentifier
+ AnswerScore
+ DefaultScore
+ QualificationValueMapping
+ PercentageMapping
+ MaximumSummedScore
+ ScaleMapping
+ SummedScoreMultiplier
+ RangeMapping
+ SummedScoreRange
+ InclusiveLowerBound
+ InclusiveUpperBound
+ QualificationValue
+ OutOfRangeQualificationValue
+ }.uniq.each do |element_name|
+ tag element_name
+ tag element_name, :snake_case
+ end
+
+ def content
+ answer_key :xmlns => XMLNS do
+ answer_key_content
+ end
+ end
+
+end
+
View
83 lib/rturk/builders/question_form_builder.rb
@@ -1,33 +1,86 @@
require 'cgi'
require 'uri'
+require "erector/xml_widget"
module RTurk
- class QuestionForm
+ # see http://docs.amazonwebservices.com/AWSMechTurk/2008-08-02/AWSMturkAPI/ApiReference_QuestionFormDataStructureArticle.html
+ # @param options hash (optional)
+ # ::xml:: raw xml (optional). If it starts with \&lt;QuestionForm then it's used as the full QuestionForm value. Otherwise it is wrapped in a \&lt;QuestionForm\&gt; element. If it is nil then we use Erector to call its subclass' #question_form_content method.
+ class QuestionForm < Erector::XMLWidget
XMLNS = "http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionForm.xsd"
- # The QuestionForm data structure is hella complicated, so we're just treating it as a string for now. See
- # http://docs.amazonwebservices.com/AWSMechTurk/2008-08-02/AWSMturkAPI/ApiReference_QuestionFormDataStructureArticle.html
+ needs :xml => nil
- attr_accessor :text
+ def to_params
+ to_xml # create a new output string and call 'content' via Erector
+ end
- def initialize(text)
- @text = text
+ # todo: fill out Application subelements
+ # todo: fill out EmbeddedBinary subelements
+ %w{
+ QuestionForm
+ Overview
+ Title
+ List
+ Binary
+ MimeType
+ Type
+ SubType
+ DataURL
+ AltText
+ Application
+ EmbeddedBinary
+ FormattedContent
+
+ Question
+ QuestionIdentifier
+ DisplayName
+ IsRequired
+ QuestionContent
+ AnswerSpecification
+ FreeTextAnswer
+ Constraints
+ IsNumeric
+ Length
+ AnswerFormatRegex
+ DefaultText
+ NumberOfLinesSuggestion
+ SelectionAnswer
+ MinSelectionCount
+ MaxSelectionCount
+ StyleSuggestion
+ Selections
+ Selection
+ SelectionIdentifier
+ Text
+ FormattedContent
+ Binary
+ OtherSelection
+ FileUploadAnswer
+ MaxFileSizeInBytes
+ MinFileSizeInBytes
+ }.uniq.each do |element_name|
+ tag element_name
+ tag element_name, :snake_case unless element_name == 'Text'
end
- def to_params
- if text =~ /^<QuestionForm/
- text
+ tag "Text", "text_element" # very sticky since 'text' is a core Erector method
+
+ def content
+ if @xml and @xml.strip =~ /^<QuestionForm/
+ rawtext @xml
else
- <<-XML
-<QuestionForm xmlns="#{XMLNS}">
-#{text}
-</QuestionForm>
- XML
+ question_form :xmlns => XMLNS do
+ question_form_content
+ end
end
end
- end
+ def question_form_content
+ rawtext @xml # by default, use the parameter
+ end
+ end
end
View
8 lib/rturk/operations/create_hit.rb
@@ -20,8 +20,12 @@ def question(*args)
end
end
- def question_form(text)
- @question = RTurk::QuestionForm.new(text)
+ def question_form(text_or_widget)
+ if text_or_widget.is_a? Erector::XMLWidget
+ @question = text_or_widget
+ else
+ @question = RTurk::QuestionForm.new(:xml => text)
+ end
end
def to_params
View
26 spec/builders/answer_key_builder_spec.rb
@@ -0,0 +1,26 @@
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
+require 'rturk/builders/answer_key_builder'
+
+module RTurk
+ describe AnswerKey do
+
+ before(:all) do
+ end
+
+ class SillyAnswerKey < AnswerKey
+ def answer_key_content
+ Question "Why did the chicken cross the road?"
+ end
+ end
+
+ it "is an abstract base class that calls down to 'answer_key_content' in its concrete subclasses" do
+ RTurk::SillyAnswerKey.new.to_xml.should ==
+ "<AnswerKey xmlns=\"#{RTurk::AnswerKey::XMLNS}\">" +
+ "<Question>Why did the chicken cross the road?</Question>" +
+ "</AnswerKey>"
+ end
+
+ # todo: test more
+
+ end
+end
View
81 spec/builders/question_form_builder_spec.rb
@@ -1,18 +1,75 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
+require 'rturk/builders/question_form_builder'
-describe RTurk::QuestionForm do
+module RTurk
+ describe QuestionForm do
- before(:all) do
- end
+ before(:all) do
+ end
- it "should build a question" do
- question = RTurk::QuestionForm.new("[...]")
- question.text.should == "[...]"
- question.to_params.should == <<-XML
-<QuestionForm xmlns="#{RTurk::QuestionForm::XMLNS}">
-[...]
-</QuestionForm>
- XML
- end
+ it "should build a question, using its xml param as the full QuestionForm since it starts with <QuestionForm" do
+ xml = <<-XML
+ <QuestionForm xmlns="#{RTurk::QuestionForm::XMLNS}">
+ [...]
+ </QuestionForm>
+ XML
+ question = RTurk::QuestionForm.new(:xml => xml)
+ question.to_params.should == xml
+ end
+
+ it "should build a question, using its xml param as the QuestionForm content" do
+ question = RTurk::QuestionForm.new(:xml => "[...]")
+ question.to_params.should ==
+ "<QuestionForm xmlns=\"#{RTurk::QuestionForm::XMLNS}\">[...]</QuestionForm>"
+ end
+
+ class SillyQuestionForm < QuestionForm
+ def question_form_content
+ Question "Why did the chicken cross the road?"
+ end
+ end
+ it "is an abstract base class that calls down to 'question_form_content' in its concrete subclasses" do
+ RTurk::SillyQuestionForm.new.to_xml.should ==
+ "<QuestionForm xmlns=\"#{RTurk::QuestionForm::XMLNS}\">" +
+ "<Question>Why did the chicken cross the road?</Question>" +
+ "</QuestionForm>"
+ end
+
+ class AnotherSillyQuestionForm < QuestionForm
+ def question_form_content
+ question {
+ question_content {
+ Text "How many licks?" # note: Text vs text vs text_element gotcha
+ }
+ answer_specification {
+ free_text_answer {
+ constraints {
+ is_numeric true
+ }
+ }
+ }
+ }
+ end
+ end
+
+ it "allows snake_case element names" do
+ RTurk::AnotherSillyQuestionForm.new.to_xml.should ==
+ "<QuestionForm xmlns=\"#{RTurk::QuestionForm::XMLNS}\">" +
+ "<Question>" +
+ "<QuestionContent>" +
+ "<Text>How many licks?</Text>" +
+ "</QuestionContent>" +
+ "<AnswerSpecification>" +
+ "<FreeTextAnswer>" +
+ "<Constraints>" +
+ "<IsNumeric>true</IsNumeric>" +
+ "</Constraints>" +
+ "</FreeTextAnswer>" +
+ "</AnswerSpecification>" +
+ "</Question>" +
+ "</QuestionForm>"
+ end
+
+ end
end
View
106 spec/example_question_form.rb
@@ -0,0 +1,106 @@
+class ExampleQuestionForm < RTurk::QuestionForm
+ def question_form_content
+ Overview do
+ Title do
+ text 'Game 01523, "X" to play'
+ end
+ Text do
+ text 'You are helping to decide the next move in a game of Tic-Tac-Toe. The board looks like this:'
+ end
+ Binary do
+ MimeType do
+ Type do
+ text 'image'
+ end
+ SubType do
+ text 'gif'
+ end
+ end
+ DataURL do
+ text 'http://tictactoe.amazon.com/game/01523/board.gif'
+ end
+ AltText do
+ text 'The game board, with "X" to move.'
+ end
+ end
+ Text do
+ text 'Player "X" has the next move.'
+ end
+ end
+ Question do
+ QuestionIdentifier do
+ text 'nextmove'
+ end
+ DisplayName do
+ text 'The Next Move'
+ end
+ IsRequired do
+ text 'true'
+ end
+ QuestionContent do
+ Text do
+ text 'What are the coordinates of the best move for player "X" in this game?'
+ end
+ end
+ AnswerSpecification do
+ FreeTextAnswer do
+ Constraints do
+ Length :minLength => '2', :maxLength => '2'
+ end
+ DefaultText do
+ text 'C1'
+ end
+ end
+ end
+ end
+ Question do
+ QuestionIdentifier do
+ text 'likelytowin'
+ end
+ DisplayName do
+ text 'The Next Move'
+ end
+ IsRequired do
+ text 'true'
+ end
+ QuestionContent do
+ Text do
+ text 'How likely is it that player "X" will win this game?'
+ end
+ end
+ AnswerSpecification do
+ SelectionAnswer do
+ StyleSuggestion do
+ text 'radiobutton'
+ end
+ Selections do
+ Selection do
+ SelectionIdentifier do
+ text 'notlikely'
+ end
+ Text do
+ text 'Not likely'
+ end
+ end
+ Selection do
+ SelectionIdentifier do
+ text 'unsure'
+ end
+ Text do
+ text 'It could go either way'
+ end
+ end
+ Selection do
+ SelectionIdentifier do
+ text 'likely'
+ end
+ Text do
+ text 'Likely'
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
View
64 spec/example_question_form.xml
@@ -0,0 +1,64 @@
+ <Overview>
+ <Title>Game 01523, "X" to play</Title>
+ <Text>
+ You are helping to decide the next move in a game of Tic-Tac-Toe. The board looks like this:
+ </Text>
+ <Binary>
+ <MimeType>
+ <Type>image</Type>
+ <SubType>gif</SubType>
+ </MimeType>
+ <DataURL>http://tictactoe.amazon.com/game/01523/board.gif</DataURL>
+ <AltText>The game board, with "X" to move.</AltText>
+ </Binary>
+ <Text>
+ Player "X" has the next move.
+ </Text>
+ </Overview>
+ <Question>
+ <QuestionIdentifier>nextmove</QuestionIdentifier>
+ <DisplayName>The Next Move</DisplayName>
+ <IsRequired>true</IsRequired>
+ <QuestionContent>
+ <Text>
+ What are the coordinates of the best move for player "X" in this game?
+ </Text>
+ </QuestionContent>
+ <AnswerSpecification>
+ <FreeTextAnswer>
+ <Constraints>
+ <Length minLength="2" maxLength="2" />
+ </Constraints>
+ <DefaultText>C1</DefaultText>
+ </FreeTextAnswer>
+ </AnswerSpecification>
+ </Question>
+ <Question>
+ <QuestionIdentifier>likelytowin</QuestionIdentifier>
+ <DisplayName>The Next Move</DisplayName>
+ <IsRequired>true</IsRequired>
+ <QuestionContent>
+ <Text>
+ How likely is it that player "X" will win this game?
+ </Text>
+ </QuestionContent>
+ <AnswerSpecification>
+ <SelectionAnswer>
+ <StyleSuggestion>radiobutton</StyleSuggestion>
+ <Selections>
+ <Selection>
+ <SelectionIdentifier>notlikely</SelectionIdentifier>
+ <Text>Not likely</Text>
+ </Selection>
+ <Selection>
+ <SelectionIdentifier>unsure</SelectionIdentifier>
+ <Text>It could go either way</Text>
+ </Selection>
+ <Selection>
+ <SelectionIdentifier>likely</SelectionIdentifier>
+ <Text>Likely</Text>
+ </Selection>
+ </Selections>
+ </SelectionAnswer>
+ </AnswerSpecification>
+ </Question>
View
2  spec/operations/create_hit_spec.rb
@@ -84,7 +84,7 @@
hit = RTurk::CreateHIT.new(:title => "Who is your favorite Beatle?") do |hit|
hit.description = 'blah'
hit.reward = 0.05
- hit.question_form example_question_form
+ hit.question_form ExampleQuestionForm.new
end
response = hit.request
response.hit_id.should_not be_nil
View
76 spec/spec_helper.rb
@@ -1,12 +1,15 @@
SPEC_ROOT = File.expand_path(File.dirname(__FILE__)) unless defined? SPEC_ROOT
$: << SPEC_ROOT
-$: << File.join(File.dirname(__FILE__), '..', 'lib')
+$: << File.join(SPEC_ROOT, '..', 'lib')
+
require 'rubygems'
require 'rspec'
require 'fakeweb'
require 'yaml'
require 'webmock'
include WebMock::API
+require 'wrong'
+include Wrong::D
require 'rturk'
# RTurk.log.level = Logger::DEBUG
@@ -31,73 +34,4 @@ def fake_response(xml)
end
-# The QuestionForm data structure is hella complicated, so we're just treating it as a string for now. This is
-# from http://docs.amazonwebservices.com/AWSMechTurk/2008-08-02/AWSMturkAPI/ApiReference_QuestionFormDataStructureArticle.html#d0e18794
-def example_question_form
- <<-XML
- <Overview>
- <Title>Game 01523, "X" to play</Title>
- <Text>
- You are helping to decide the next move in a game of Tic-Tac-Toe. The board looks like this:
- </Text>
- <Binary>
- <MimeType>
- <Type>image</Type>
- <SubType>gif</SubType>
- </MimeType>
- <DataURL>http://tictactoe.amazon.com/game/01523/board.gif</DataURL>
- <AltText>The game board, with "X" to move.</AltText>
- </Binary>
- <Text>
- Player "X" has the next move.
- </Text>
- </Overview>
- <Question>
- <QuestionIdentifier>nextmove</QuestionIdentifier>
- <DisplayName>The Next Move</DisplayName>
- <IsRequired>true</IsRequired>
- <QuestionContent>
- <Text>
- What are the coordinates of the best move for player "X" in this game?
- </Text>
- </QuestionContent>
- <AnswerSpecification>
- <FreeTextAnswer>
- <Constraints>
- <Length minLength="2" maxLength="2" />
- </Constraints>
- <DefaultText>C1</DefaultText>
- </FreeTextAnswer>
- </AnswerSpecification>
- </Question>
- <Question>
- <QuestionIdentifier>likelytowin</QuestionIdentifier>
- <DisplayName>The Next Move</DisplayName>
- <IsRequired>true</IsRequired>
- <QuestionContent>
- <Text>
- How likely is it that player "X" will win this game?
- </Text>
- </QuestionContent>
- <AnswerSpecification>
- <SelectionAnswer>
- <StyleSuggestion>radiobutton</StyleSuggestion>
- <Selections>
- <Selection>
- <SelectionIdentifier>notlikely</SelectionIdentifier>
- <Text>Not likely</Text>
- </Selection>
- <Selection>
- <SelectionIdentifier>unsure</SelectionIdentifier>
- <Text>It could go either way</Text>
- </Selection>
- <Selection>
- <SelectionIdentifier>likely</SelectionIdentifier>
- <Text>Likely</Text>
- </Selection>
- </Selections>
- </SelectionAnswer>
- </AnswerSpecification>
- </Question>
- XML
-end
+require 'example_question_form'
Please sign in to comment.
Something went wrong with that request. Please try again.