ruqlcqb 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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