ruqlcqb 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ class EdXmlRenderer
2
+ require 'builder'
3
+
4
+ attr_reader :output
5
+ def initialize(quiz,options={})
6
+ @only_question = options.delete('n') || options.delete('name')
7
+ @output = ''
8
+ @b = Builder::XmlMarkup.new(:target => @output, :indent => 2)
9
+ @quiz = quiz
10
+ end
11
+
12
+ def render(thing)
13
+ case thing
14
+ when MultipleChoice,SelectMultiple,TrueFalse then render_multiple_choice(thing)
15
+ when FillIn then render_fill_in(thing)
16
+ else
17
+ raise "Unknown question type: #{thing}"
18
+ end
19
+ end
20
+
21
+ def render_quiz
22
+ # entire quiz can be in one question group, as long as we specify
23
+ # that ALL question from the group must be used to make the quiz.
24
+ question_list = if @only_question
25
+ then @quiz.questions.select { |q| q.name == @only_question }
26
+ else @quiz.questions
27
+ end
28
+ question_list.each { |question| render(question) }
29
+ @output
30
+ end
31
+
32
+ def render_fill_in(question)
33
+ raise "Not yet implemented for edXML"
34
+ end
35
+
36
+ def render_multiple_choice(question)
37
+ @b.problem do
38
+ # if question text has explicit newlines, use them to separate <p>'s
39
+ if question.raw?
40
+ @b.p { |p| p << question.question_text }
41
+ else
42
+ question.question_text.lines.map(&:chomp).each do |line|
43
+ if question.raw? then @b.p { |p| p << line } else @b.p(line) end
44
+ end
45
+ end
46
+ @b.multiplechoiceresponse do
47
+ @b.choicegroup :type => 'MultipleChoice' do
48
+ question.answers.each do |answer|
49
+ if question.raw?
50
+ @b.choice(:correct => answer.correct?) do |choice|
51
+ choice << answer.answer_text
52
+ choice << "\n"
53
+ end
54
+ else
55
+ @b.choice answer.answer_text, :correct => answer.correct?
56
+ end
57
+ end
58
+ end
59
+ end
60
+ @b.solution do
61
+ @b.div :class => 'detailed_solution' do
62
+ @b.p 'Explanation'
63
+ if question.raw?
64
+ @b.p { |p| p << question.correct_answer.explanation }
65
+ else
66
+ @b.p question.correct_answer.explanation
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+
@@ -0,0 +1,166 @@
1
+ class Html5Renderer
2
+ require 'builder'
3
+ require 'erb'
4
+
5
+ attr_reader :output
6
+
7
+ def initialize(quiz,options={})
8
+ @css = options.delete('c') || options.delete('css')
9
+ @show_solutions = options.delete('s') || options.delete('solutions')
10
+ @template = options.delete('t') ||
11
+ options.delete('template') ||
12
+ File.join(Gem.loaded_specs['ruql'].full_gem_path, 'templates/html5.html.erb')
13
+ @output = ''
14
+ @quiz = quiz
15
+ @h = Builder::XmlMarkup.new(:target => @output, :indent => 2)
16
+ end
17
+
18
+ def render_quiz
19
+ if @template
20
+ render_with_template do
21
+ render_questions
22
+ @output
23
+ end
24
+ else
25
+ @h.html do
26
+ @h.head do
27
+ @h.title @quiz.title
28
+ @h.link(:rel => 'stylesheet', :type =>'text/css', :href=>@css) if @css
29
+ end
30
+ @h.body do
31
+ render_questions
32
+ end
33
+ end
34
+ end
35
+ self
36
+ end
37
+
38
+ def render_with_template
39
+ # local variables that should be in scope in the template
40
+ quiz = @quiz
41
+ # the ERB template includes 'yield' where questions should go:
42
+ output = ERB.new(IO.read(File.expand_path @template)).result(binding)
43
+ @output = output
44
+ end
45
+
46
+ def render_questions
47
+ render_random_seed
48
+ @h.ol :class => 'questions' do
49
+ @quiz.questions.each_with_index do |q,i|
50
+ case q
51
+ when MultipleChoice, SelectMultiple, TrueFalse then render_multiple_choice(q,i)
52
+ when FillIn then render_fill_in(q, i)
53
+ else
54
+ raise "Unknown question type: #{q}"
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ def render_multiple_choice(q,index)
62
+ render_question_text(q, index) do
63
+ answers =
64
+ if q.class == TrueFalse then q.answers.sort.reverse # True always first
65
+ elsif q.randomize then q.answers.sort_by { rand }
66
+ else q.answers
67
+ end
68
+ @h.ol :class => 'answers' do
69
+ answers.each do |answer|
70
+ if @show_solutions
71
+ render_answer_for_solutions(answer, q.raw?, q.class == TrueFalse)
72
+ else
73
+ if q.raw? then @h.li { |l| l << answer.answer_text } else @h.li answer.answer_text end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ self
79
+ end
80
+
81
+ def render_fill_in(q, idx)
82
+ render_question_text(q, idx) do
83
+ if @show_solutions
84
+ answer = q.answers[0]
85
+ if answer.has_explanation?
86
+ if q.raw? then @h.p(:class => 'explanation') { |p| p << answer.explanation }
87
+ else @h.p(answer.explanation, :class => 'explanation') end
88
+ end
89
+ answers = (answer.answer_text.kind_of?(Array) ? answer.answer_text : [answer.answer_text])
90
+ @h.ol :class => 'answers' do
91
+ answers.each do |answer|
92
+ if answer.kind_of?(Regexp)
93
+ answer = answer.inspect
94
+ if !q.case_sensitive
95
+ answer += 'i'
96
+ end
97
+ end
98
+ @h.li do
99
+ if q.raw? then @h.p { |p| p << answer } else @h.p answer end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ def render_answer_for_solutions(answer,raw,is_true_false = nil)
108
+ args = {:class => (answer.correct? ? 'correct' : 'incorrect')}
109
+ if is_true_false
110
+ answer.answer_text.prepend(
111
+ answer.correct? ? "CORRECT: " : "INCORRECT: ")
112
+ end
113
+ @h.li(args) do
114
+ if raw then @h.p { |p| p << answer.answer_text } else @h.p answer.answer_text end
115
+ if answer.has_explanation?
116
+ if raw then @h.p(:class => 'explanation') { |p| p << answer.explanation }
117
+ else @h.p(answer.explanation, :class => 'explanation') end
118
+ end
119
+ end
120
+ end
121
+
122
+ def render_question_text(question,index)
123
+ html_args = {
124
+ :id => "question-#{index}",
125
+ :class => ['question', question.class.to_s.downcase, (question.multiple ? 'multiple' : '')]
126
+ .join(' ')
127
+ }
128
+ @h.li html_args do
129
+ @h.div :class => 'text' do
130
+ qtext = "[#{question.points} point#{'s' if question.points>1}] " <<
131
+ ('Select ALL that apply: ' if question.multiple).to_s <<
132
+ if question.class == FillIn then question.question_text.gsub(/\-+/, '_____________________________')
133
+ else question.question_text
134
+ end
135
+ if question.raw?
136
+ @h.p { |p| p << qtext }
137
+ else
138
+ qtext.each_line do |p|
139
+ @h.p do |par|
140
+ par << p # preserves HTML markup
141
+ end
142
+ end
143
+ end
144
+ end
145
+ yield # render answers
146
+ end
147
+ self
148
+ end
149
+
150
+ def quiz_header
151
+ @h.div(:id => 'student-name') do
152
+ @h.p 'Name:'
153
+ @h.p 'Student ID:'
154
+ end
155
+ if @quiz.options[:instructions]
156
+ @h.div :id => 'instructions' do
157
+ @quiz.options[:instructions].each_line { |p| @h.p p }
158
+ end
159
+ end
160
+ self
161
+ end
162
+
163
+ def render_random_seed
164
+ @h.comment! "Seed: #{@quiz.seed}"
165
+ end
166
+ end
@@ -0,0 +1,198 @@
1
+ class HtmlFormRenderer
2
+ require 'builder'
3
+ require 'erb'
4
+
5
+ attr_reader :output
6
+
7
+ def initialize(quiz,options={})
8
+ @css = options.delete('c') || options.delete('css')
9
+ @js = options.delete('j') || options.delete('js')
10
+ @show_solutions = options.delete('s') || options.delete('solutions')
11
+ @template = options.delete('t') ||
12
+ options.delete('template') #||
13
+ #File.join(Gem.loaded_specs['ruql'].full_gem_path, 'templates/htmlform.html.erb')
14
+ @output = ''
15
+ @quiz = quiz
16
+ @h = Builder::XmlMarkup.new(:target => @output, :indent => 2)
17
+ end
18
+
19
+ def render_quiz
20
+ if @template
21
+ render_with_template do
22
+ render_questions
23
+ @output
24
+ end
25
+ else
26
+ @h.html do
27
+ @h.head do
28
+ @h.title @quiz.title
29
+ @h.link(:rel => 'stylesheet', :type =>'text/css', :href =>@css) if @css
30
+ @h.script(:type => 'text/javascript', :src => @js) do
31
+ end if @js
32
+ end
33
+ @h.body do
34
+ render_questions
35
+ end
36
+ end
37
+ end
38
+ self
39
+ end
40
+
41
+ def render_with_template
42
+ # local variables that should be in scope in the template
43
+ quiz = @quiz
44
+ title = "Quiz" unless @title
45
+ # the ERB template includes 'yield' where questions should go:
46
+ output = ERB.new(IO.read(File.expand_path @template)).result(binding)
47
+ @output = output
48
+ end
49
+
50
+ def render_questions
51
+ render_random_seed
52
+ @h.form do
53
+ @h.ol :class => 'questions' do
54
+ @quiz.questions.each_with_index do |q,i|
55
+ case q
56
+ when SelectMultiple then render_select_multiple(q,i)
57
+ when MultipleChoice, TrueFalse then render_multiple_choice(q,i)
58
+ when FillIn then render_fill_in(q, i)
59
+ else
60
+ raise "Unknown question type: #{q}"
61
+ end
62
+ end
63
+ end
64
+ @h.input(:type => 'submit', :value => 'Enviar')
65
+ end
66
+ end
67
+
68
+
69
+ def render_multiple_choice(q,index)
70
+ render_question_text(q, index) do
71
+ answers =
72
+ if q.class == TrueFalse then q.answers.sort.reverse # True always first
73
+ elsif q.randomize then q.answers.sort_by { rand }
74
+ else q.answers
75
+ end
76
+ @h.ol :class => 'answers' do
77
+ answers.each do |answer|
78
+ if @show_solutions
79
+ render_answer_for_solutions(answer, q.raw?)
80
+ else
81
+ #if q.raw? then @h.li { |l| l << answer.answer_text } else @h.li answer.answer_text end
82
+ @h.input(:type => 'radio', :name => 'a', :class => 'select') { |p|
83
+ p << answer.answer_text
84
+ p << '</br>'
85
+ }
86
+ end
87
+ end
88
+ end
89
+ end
90
+ self
91
+ end
92
+
93
+ def render_select_multiple(q,index)
94
+ render_question_text(q, index) do
95
+ answers =
96
+ if q.randomize then q.answers.sort_by { rand }
97
+ else q.answers
98
+ end
99
+ @h.ol :class => 'answers' do
100
+ answers.each do |answer|
101
+ if @show_solutions
102
+ render_answer_for_solutions(answer, q.raw?)
103
+ else
104
+ #if q.raw? then @h.li { |l| l << answer.answer_text } else @h.li answer.answer_text end
105
+ @h.input(:type => 'checkbox', :name => 'b', :class => 'check') { |p|
106
+ p << answer.answer_text
107
+ p << '</br>'
108
+ }
109
+ end
110
+ end
111
+ end
112
+ end
113
+ self
114
+ end
115
+
116
+ def render_fill_in(q, idx)
117
+ render_question_text(q, idx) do
118
+ if @show_solutions
119
+ answer = q.answers[0]
120
+ if answer.has_explanation?
121
+ if q.raw? then @h.p(:class => 'explanation') { |p| p << answer.explanation }
122
+ else @h.p(answer.explanation, :class => 'explanation') end
123
+ end
124
+ answers = (answer.answer_text.kind_of?(Array) ? answer.answer_text : [answer.answer_text])
125
+ @h.ol :class => 'answers' do
126
+ answers.each do |answer|
127
+ if answer.kind_of?(Regexp)
128
+ answer = answer.inspect
129
+ if !q.case_sensitive
130
+ answer += 'i'
131
+ end
132
+ end
133
+ @h.li do
134
+ if q.raw? then @h.p { |p| p << answer } else @h.p answer end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ def render_answer_for_solutions(answer,raw)
143
+ args = {:class => (answer.correct? ? 'correct' : 'incorrect')}
144
+ @h.li(args) do
145
+ if raw then @h.p { |p| p << answer.answer_text } else @h.p answer.answer_text end
146
+ if answer.has_explanation?
147
+ if raw then @h.p(:class => 'explanation') { |p| p << answer.explanation }
148
+ else @h.p(answer.explanation, :class => 'explanation') end
149
+ end
150
+ end
151
+ end
152
+
153
+ def render_question_text(question,index)
154
+ html_args = {
155
+ :id => "question-#{index}",
156
+ :class => ['question', question.class.to_s.downcase, (question.multiple ? 'multiple' : '')]
157
+ .join(' ')
158
+ }
159
+ @h.li html_args do
160
+ @h.div :class => 'text' do
161
+ qtext = "[#{question.points} point#{'s' if question.points>1}] " <<
162
+ ('Select ALL that apply: ' if question.multiple).to_s <<
163
+ if question.class == FillIn then question.question_text.gsub(/\-+/, '')
164
+ else question.question_text
165
+ end
166
+ #if question.raw?
167
+ # @h.p { |p| p << qtext }
168
+ #else
169
+ qtext.each_line do |p|
170
+ @h.p do |par|
171
+ par << p # preserves HTML markup
172
+ @h.input(:type => 'text', :class => 'fillin') if (question.class == FillIn)
173
+ end
174
+ end
175
+ #end
176
+ end
177
+ yield # render answers
178
+ end
179
+ self
180
+ end
181
+
182
+ def quiz_header
183
+ @h.div(:id => 'student-name') do
184
+ @h.p 'Name:'
185
+ @h.p 'Student ID:'
186
+ end
187
+ if @quiz.options[:instructions]
188
+ @h.div :id => 'instructions' do
189
+ @quiz.options[:instructions].each_line { |p| @h.p p }
190
+ end
191
+ end
192
+ self
193
+ end
194
+
195
+ def render_random_seed
196
+ @h.comment! "Seed: #{@quiz.seed}"
197
+ end
198
+ end
@@ -0,0 +1,15 @@
1
+ class JSONRenderer
2
+ require 'json'
3
+
4
+ attr_reader :output
5
+
6
+ def initialize(quiz,options={})
7
+ @output = ''
8
+ @json_array = []
9
+ @quiz = quiz
10
+ end
11
+
12
+ def render_quiz
13
+ @output = @quiz.questions.map {|question| JSON.pretty_generate(question.to_JSON)}
14
+ end
15
+ end