Permalink
Browse files

HTML5 basic renderer is now working

Command-line driver with option parsing is working
  • Loading branch information...
1 parent befdc87 commit 04a22e45427d1889248b0b33e3c4b50c5be54f87 @armandofox armandofox committed Jan 27, 2012
Showing with 140 additions and 27 deletions.
  1. +1 −0 Gemfile
  2. +69 −0 lib/html5_renderer.rb
  3. +3 −4 lib/question.rb
  4. +15 −7 lib/quiz.rb
  5. +7 −7 lib/xml_renderer.rb
  6. +2 −2 spec/fixtures/example_quiz.rb
  7. +38 −0 spec/html5_renderer_spec.rb
  8. +4 −5 spec/quiz_spec.rb
  9. +1 −2 spec/xml_renderer_spec.rb
View
1 Gemfile
@@ -1,6 +1,7 @@
source :rubygems
gem 'builder'
+gem 'getopt'
group :development, :test do
gem 'ruby-debug19'
View
69 lib/html5_renderer.rb
@@ -0,0 +1,69 @@
+class Html5Renderer
+ require 'builder'
+
+ attr_reader :output
+
+ def initialize(quiz,options={})
+ @css = options.delete(:c) || options.delete(:css)
+ @output = ''
+ @quiz = quiz
+ @h = Builder::XmlMarkup.new(:target => @output, :indent => 2)
+ end
+
+ def render_quiz
+ @h.html
+ @h.head do
+ @h.title @quiz.title
+ @h.link(:rel => 'stylesheet', :type =>'text/css', :href=>@css) if @css
+ end
+ @h.body do
+ quiz_header
+ @quiz.questions.each_with_index do |q,i|
+ case q
+ when MultipleChoice then render_multiple_choice(q,i)
+ else
+ raise "Unknown question type: #{q}"
+ end
+ end
+ end
+ self
+ end
+
+ def render_multiple_choice(q,index)
+ render_question_text(q, index) do
+ answers = (q.randomize ? q.answers.sort_by { rand } : q.answers)
+ @h.ol :class => 'answers' do
+ answers.each do |answer|
+ @h.li answer.answer_text
+ end
+ end
+ end
+ self
+ end
+
+ def render_question_text(question,index)
+ @h.div :class => 'question', :id => "question-#{index}" do
+ @h.div :class => 'text' do
+ question.question_text.each_line do |p|
+ @h.p p
+ end
+ end
+ yield # render answers
+ end
+ self
+ end
+
+ def quiz_header
+ @h.div(:id => 'student-name') do
+ @h.p 'Name:'
+ @h.p 'Student ID:'
+ end
+ if @quiz.options[:instructions]
+ @h.div :id => 'instructions' do
+ @quiz.options[:instructions].each_line { |p| @h.p p }
+ end
+ end
+ self
+ end
+
+end
View
7 lib/question.rb
@@ -1,12 +1,11 @@
class Question
require 'builder'
attr_accessor :question_text, :answers, :randomize, :points
- attr_reader :builder, :string
def initialize(*args)
- @answers = []
- @string = ''
- @points = args[-1].kind_of?(Hash) ? args[-1][:points].to_i : 1
+ options = if args[-1].kind_of?(Hash) then args[-1] else {} end
+ @answers = options[:answers] || []
+ @points = [options[:points].to_i, 1].max
end
def text(s) ; @question_text = s ; end
View
22 lib/quiz.rb
@@ -5,6 +5,7 @@
# renderers
require 'xml_renderer'
+require 'html5_renderer'
# question types
require 'question'
@@ -32,19 +33,27 @@ class Quiz
:maximum_score => 1,
}
- attr_reader :renderer, :questions, :options, :output
+ attr_reader :renderer
+ attr_reader :questions
+ attr_reader :options
+ attr_reader :output
attr_accessor :title
- def initialize(title, renderer, options={})
+ def initialize(title, options={})
@output = ''
@questions = []
@title = title
@options = @@default_options.merge(options)
- @renderer = Object.const_get(renderer.to_s.capitalize + 'Renderer').send(:new,self)
end
- def render
- @output = @renderer.render_quiz(self)
+ def self.get_renderer(renderer)
+ Object.const_get(renderer.to_s.capitalize + 'Renderer') rescue nil
+ end
+
+ def render_with(renderer,options={})
+ @renderer = Quiz.get_renderer(renderer).send(:new,self,options)
+ @renderer.render_quiz
+ @output = @renderer.output
end
# this should really be done using mixins.
@@ -57,7 +66,6 @@ def choice_answer(opts={}, &block)
def self.quiz(*args,&block)
quiz = Quiz.new(*args)
quiz.instance_eval(&block)
- quiz.render
- puts quiz.output
+ quiz
end
end
View
14 lib/xml_renderer.rb
@@ -1,8 +1,8 @@
class XmlRenderer
require 'builder'
- attr_reader :output, :quiz
- def initialize(quiz=nil)
+ attr_reader :output
+ def initialize(quiz,options={})
@output = ''
@b = Builder::XmlMarkup.new(:target => @output, :indent => 2)
@quiz = quiz
@@ -13,14 +13,14 @@ def render(thing)
m.call(thing)
end
- def render_quiz(quiz)
+ def render_quiz
# entire quiz can be in one question group, as long as we specify
# that ALL question from the group must be used to make the quiz.
xml_quiz do
# after preamble...
@b.question_groups do
- @b.question_group(:select => quiz.questions.length) do
- quiz.questions.each do |question|
+ @b.question_group(:select => @quiz.questions.length) do
+ @quiz.questions.each do |question|
self.render(question)
end
end
@@ -86,8 +86,8 @@ def xml_quiz
@b.quiz do
@b.metadata do
@b.type 'quiz'
- @b.title quiz.title
- options_to_xml quiz.options
+ @b.title @quiz.title
+ options_to_xml @quiz.options
end
@b.preamble
@b.data do
View
4 spec/fixtures/example_quiz.rb
@@ -1,5 +1,5 @@
-Quiz.quiz "I. Introduction", :xml, :time_limit => 60 do
- choice_answer do
+quiz "I. Introduction", :time_limit => 60 do
+ choice_answer :randomize => true do
text 'question 1'
distractor 'wrong answer a'
distractor 'wrong answer b', :explanation => 'b is wrong'
View
38 spec/html5_renderer_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Html5Renderer do
+ describe 'when created' do
+ subject { Html5Renderer.new(:fake_quiz) }
+ its(:output) { should == '' }
+ end
+ describe 'with options' do
+ def rendering_with(opts)
+ Html5Renderer.new(Quiz.new(''), opts).render_quiz.output
+ end
+ it 'should include CSS stylesheet link with -c option' do
+ rendering_with(:c => 'foo.html').
+ should match /<link rel="stylesheet" type="text\/css" href="foo.html"/
+ end
+ it 'should include CSS stylesheet link with --css option' do
+ rendering_with(:css => 'foo.html').
+ should match /<link rel="stylesheet" type="text\/css" href="foo.html"/
+ end
+ end
+ describe 'rendering multiple-choice question' do
+ before :each do
+ @a = [Answer.new('aa',true),Answer.new('bb',false), Answer.new('cc',false)]
+ @q = MultipleChoice.new('question', :answers => @a)
+ end
+ it 'should randomize option order if :randomize true' do
+ @q.randomize = true
+ runs = Array.new(10) { Html5Renderer.new(:fake).render_multiple_choice(@q,1).output }
+ runs.any? { |run| runs[0] != run }.should be_true
+ end
+ it 'should preserve option order if :randomize false' do
+ @q.randomize = false
+ runs = Array.new(10) { Html5Renderer.new(:fake).render_multiple_choice(@q,1).output }
+ runs[0].should match /.*aa.*bb.*cc/m
+ runs.all? { |run| runs[0] == run }.should be_true
+ end
+ end
+end
View
9 spec/quiz_spec.rb
@@ -1,15 +1,14 @@
require 'spec_helper'
describe Quiz do
- describe 'when created with XML renderer' do
- subject { Quiz.new('Foo', 'xml') }
+ describe 'when created' do
+ subject { Quiz.new('Foo') }
its(:title) { should == 'Foo' }
- its(:renderer) { should be_an_instance_of XmlRenderer }
its(:questions) { should be_empty }
end
- describe 'should include XML elements' do
- subject { Quiz.new('Foo', 'xml', :maximum_submissions => 2, :start => '2011-01-01 00:00', :time_limit => 60).render }
+ describe 'should include required XML elements when XML renderer used' do
+ subject { Quiz.new('Foo', :maximum_submissions => 2, :start => '2011-01-01 00:00', :time_limit => 60).render_with(:xml) }
{'title' => 'Foo',
'maximum_submissions' => '2',
'type' => 'quiz' }.each_pair do |element, value|
View
3 spec/xml_renderer_spec.rb
@@ -7,7 +7,6 @@ def c(str)
end
describe 'when created' do
subject { XmlRenderer.new(:fake_quiz) }
- its(:quiz) { should == :fake_quiz }
its(:output) { should == '' }
end
describe 'calling renderers' do
@@ -26,7 +25,7 @@ def c(str)
it { should_not have_xml_element 'option/explanation' }
end
describe 'distractor with explanation' do
- subject { XmlRenderer.new.render_multiple_choice_answer(Question::Answer.new('wrong', false, 'why')) }
+ subject { XmlRenderer.new(:fake).render_multiple_choice_answer(Question::Answer.new('wrong', false, 'why')) }
it { should have_xml_element 'option/explanation', :value => c('why') }
end
describe 'multiple choice question with answers' do

0 comments on commit 04a22e4

Please sign in to comment.