Skip to content

Commit

Permalink
use Erector for QuestionForm and AnswerKey builders
Browse files Browse the repository at this point in the history
  • Loading branch information
alexch committed Jul 24, 2011
1 parent 84f8847 commit b675511
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 105 deletions.
1 change: 1 addition & 0 deletions .rspec
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
--color
17 changes: 13 additions & 4 deletions Gemfile
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,16 @@
source "http://rubygems.org" source "http://rubygems.org"

gem 'nokogiri' gem 'nokogiri'
gem 'jeweler'
gem 'webmock'
gem 'rest-client' gem 'rest-client'
gem 'rspec', "~>2" gem "erector", ">= 0.9.0.pre"
gem 'fakeweb'
group :development do
gem 'jeweler'
end

group :development, :test do
gem 'webmock'
gem 'rspec', "~>2"
gem 'fakeweb'
gem "wrong"
end
39 changes: 39 additions & 0 deletions lib/rturk/builders/answer_key_builder.rb
Original file line number Original file line Diff line number Diff line change
@@ -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

83 changes: 68 additions & 15 deletions lib/rturk/builders/question_form_builder.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,33 +1,86 @@
require 'cgi' require 'cgi'
require 'uri' require 'uri'
require "erector/xml_widget"


module RTurk 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" 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 needs :xml => nil
# http://docs.amazonwebservices.com/AWSMechTurk/2008-08-02/AWSMturkAPI/ApiReference_QuestionFormDataStructureArticle.html


attr_accessor :text def to_params
to_xml # create a new output string and call 'content' via Erector
end


def initialize(text) # todo: fill out Application subelements
@text = text # 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 end


def to_params tag "Text", "text_element" # very sticky since 'text' is a core Erector method
if text =~ /^<QuestionForm/
text def content
if @xml and @xml.strip =~ /^<QuestionForm/
rawtext @xml
else else
<<-XML question_form :xmlns => XMLNS do
<QuestionForm xmlns="#{XMLNS}"> question_form_content
#{text} end
</QuestionForm>
XML
end end
end end


end def question_form_content
rawtext @xml # by default, use the parameter
end


end


end end
8 changes: 6 additions & 2 deletions lib/rturk/operations/create_hit.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ def question(*args)
end end
end end


def question_form(text) def question_form(text_or_widget)
@question = RTurk::QuestionForm.new(text) if text_or_widget.is_a? Erector::XMLWidget
@question = text_or_widget
else
@question = RTurk::QuestionForm.new(:xml => text)
end
end end


def to_params def to_params
Expand Down
26 changes: 26 additions & 0 deletions spec/builders/answer_key_builder_spec.rb
Original file line number Original file line Diff line number Diff line change
@@ -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
81 changes: 69 additions & 12 deletions spec/builders/question_form_builder_spec.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,18 +1,75 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) 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 before(:all) do
end end


it "should build a question" do it "should build a question, using its xml param as the full QuestionForm since it starts with <QuestionForm" do
question = RTurk::QuestionForm.new("[...]") xml = <<-XML
question.text.should == "[...]" <QuestionForm xmlns="#{RTurk::QuestionForm::XMLNS}">
question.to_params.should == <<-XML [...]
<QuestionForm xmlns="#{RTurk::QuestionForm::XMLNS}"> </QuestionForm>
[...] XML
</QuestionForm> question = RTurk::QuestionForm.new(:xml => xml)
XML question.to_params.should == xml
end 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 end
Loading

0 comments on commit b675511

Please sign in to comment.