class CanvasCc::Canvas::Question
Constants
- META_ATTRIBUTES
- QUESTION_TYPE_ID_MAP
- QUESTION_TYPE_MAP
Attributes
answer_tolerance[RW]
answers[RW]
formula_decimal_places[RW]
formulas[RW]
general_feedback[RW]
length[RW]
matches[RW]
material[RW]
numericals[RW]
var_sets[RW]
vars[RW]
Public Class Methods
new(question, assessment=nil)
click to toggle source
Calls superclass method
CanvasCc::CC::Question::new
# File lib/canvas_cc/canvas/question.rb, line 33 def initialize(question, assessment=nil) super @question_type = question.type ? QUESTION_TYPE_MAP[question.type] : QUESTION_TYPE_ID_MAP[question.type_id] @points_possible = question.grade @general_feedback = question.general_feedback @length = question.length @answers = [] unless question.answers.empty? @answers = question.answers.map do |answer| CanvasCc::OpenStruct.new( :id => answer.id, :text => answer.text, :fraction => answer.fraction, :feedback => answer.feedback ) end end unless question.choices.nil? || question.choices.empty? @answers = question.choices.map do |answer| CanvasCc::OpenStruct.new( :id => answer.id, :text => answer.content ) end end calculation = question.calculations.first unless question.calculations.nil? if calculation @answer_tolerance = calculation.tolerance @formula_decimal_places = calculation.correct_answer_format == 1 ? calculation.correct_answer_length : 0 @formulas = question.answers.map { |a| a.text.gsub(/[\{\}\s]/, '') } @vars = calculation.dataset_definitions.map do |ds_def| name = ds_def.name type, min, max, scale = ds_def.options.split(':') {:name => name, :min => min, :max => max, :scale => scale} end @var_sets = [] calculation.dataset_definitions.each do |ds_def| ds_def.dataset_items.sort_by(&:number).each_with_index do |ds_item, index| var_set = @var_sets[index] || {} vars = var_set[:vars] || {} vars[ds_def.name] = ds_item.value var_set[:vars] = vars @var_sets[index] = var_set end end @var_sets.map do |var_set| answer = 0 var_set[:vars].each do |k, v| answer += v end var_set[:answer] = answer end end unless question.numericals.nil? @numericals = question.numericals.map do |n| CanvasCc::OpenStruct.new( :answer => @answers.find { |a| a.id == n.answer_id }, :tolerance => n.tolerance ) end end if !question.matches.nil? && question.matches.length > 0 answers = question.matches.inject({}) do |result, match| result[match.code] = match.answer_text result end @matches = question.matches.select do |match| match.question_text && match.question_text.strip.length > 0 end.map do |match| CanvasCc::OpenStruct.new( :question => match.question_text, :answers => answers, :answer => match.code ) end end material = question.text material = question.content || '' if material.nil? material = material.gsub(/\{(.*?)\}/, '[\1]') material = material + image_html(question.image) unless question.image.nil? || question.image.strip == '' material = RDiscount.new(material).to_html if question.format == 4 # markdown material = convert_file_path_tokens(material) if @answers @answers.each do |answer| answer.text = convert_file_path_tokens(answer.text) if answer.text end end @material = material if @question_type == 'multiple_dropdowns_question' && !@answers.empty? && @length choices = @answers[0..(@length-1)] if @length >= @answers.length || !choices.all?{|a| !!a.text.match(/^\d/)} # the choices don't seem to be present, so construct them choices = (1..@length).map do |i| CanvasCc::OpenStruct.new( :id => "#{i}", :text => "#{i}" ) end @responses = @answers else @responses = @answers[@length..-1] end @answers = choices @responses.each_with_index do |response, index| @material << "\n#{response.text} [response#{index + 1}]" end end if question.instance_id @assessment_question_identifierref = create_key(question.id, "#{@identifier_prefix}question_") end end
Public Instance Methods
create_additional_nodes(item_node)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 447 def create_additional_nodes(item_node) case @question_type when 'calculated_question' item_node.itemproc_extension do |extension_node| extension_node.calculated do |calculated_node| calculated_node.answer_tolerance @answer_tolerance calculated_node.formulas(:decimal_places => @formula_decimal_places) do |formulas_node| @formulas.each do |formula| formulas_node.formula formula end end calculated_node.vars do |vars_node| @vars.each do |var| vars_node.var(:name => var[:name], :scale => var[:scale]) do |var_node| var_node.min var[:min] var_node.max var[:max] end end end calculated_node.var_sets do |var_sets_node| @var_sets.each do |var_set| ident = var_set[:vars].sort.map { |k,v| v.to_s.split('.').join }.flatten.join var_sets_node.var_set(:ident => ident) do |var_set_node| var_set[:vars].each do |k, v| var_set_node.var(v, :name => k) end var_set_node.answer var_set[:answer] end end end end end end end
create_feedback_nodes(item_node)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 420 def create_feedback_nodes(item_node) # Feeback if @general_feedback item_node.itemfeedback(:ident => 'general_fb') do |fb_node| fb_node.flow_mat do |flow_node| flow_node.material do |material_node| material_node.mattext(@general_feedback, :texttype => 'text/html') end end end end case @question_type when 'multiple_choice_question', 'numerical_question', 'short_answer_question', 'true_false_question' @answers.each do |answer| next unless answer.feedback && answer.feedback.strip.length > 0 item_node.itemfeedback(:ident => "#{answer.id}_fb") do |feedback_node| feedback_node.flow_mat do |flow_node| flow_node.material do |material_node| material_node.mattext answer.feedback, :texttype => 'text/html' end end end end end end
create_item_xml(section_node)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 154 def create_item_xml(section_node) section_node.item(:title => @title, :ident => @identifier) do |item_node| item_node.itemmetadata do |meta_node| meta_node.qtimetadata do |qtime_node| META_ATTRIBUTES.each do |attr| value = send(attr).to_s if value && value.length > 0 qtime_node.qtimetadatafield do |field_node| field_node.fieldlabel attr.to_s field_node.fieldentry value end end end end end item_node.presentation do |presentation_node| presentation_node.material do |material_node| material_node.mattext(@material, :texttype => 'text/html') end create_responses(presentation_node) end item_node.resprocessing do |processing_node| processing_node.outcomes do |outcomes_node| outcomes_node.decvar(:maxvalue => '100', :minvalue => '0', :varname => 'SCORE', :vartype => 'Decimal') end if @general_feedback processing_node.respcondition(:continue => 'Yes') do |condition_node| condition_node.conditionvar do |var_node| var_node.other end condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => 'general_fb') end end create_response_conditions(processing_node) end create_feedback_nodes(item_node) create_additional_nodes(item_node) end end
create_response_conditions(processing_node)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 291 def create_response_conditions(processing_node) case @question_type when 'calculated_question' processing_node.respcondition(:title => 'correct') do |condition| condition.conditionvar do |var_node| var_node.other end condition.setvar('100', :varname => 'SCORE', :action => 'Set') end processing_node.respcondition(:title => 'incorrect') do |condition| condition.conditionvar do |var_node| var_node.other end condition.setvar('0', :varname => 'SCORE', :action => 'Set') end when 'essay_question', 'embedded_answers_question' processing_node.respcondition(:continue => 'No') do |condition| condition.conditionvar do |var_node| var_node.other end end when 'matching_question' score = 100.0 / @matches.length.to_f @matches.each do |match| processing_node.respcondition do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal match.answer, :respident => "response_#{match.answer}" end condition_node.setvar "%.2f" % score, :varname => 'SCORE', :action => 'Add' end end when 'multiple_choice_question' # Feeback @answers.each do |answer| next unless answer.feedback && answer.feedback.strip.length > 0 processing_node.respcondition(:continue => 'Yes') do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal answer.id, :respident => 'response1' end condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb") end end # Scores @answers.each do |answer| processing_node.respcondition(:continue => 'No') do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal answer.id, :respident => 'response1' end condition_node.setvar(get_score(answer.fraction), :varname => 'SCORE', :action => 'Set') end end when 'multiple_answers_question' processing_node.respcondition(:continue => 'No') do |condition_node| first = @answers.first rest = @answers[1..-1] condition_node.conditionvar do |var_node| var_node.and do |and_node| and_node.varequal first.id, :respident => 'response1' rest.each do |answer| and_node.not do |not_node| not_node.varequal answer.id, :respident => 'response1' end end end end condition_node.setvar('100', :varname => 'SCORE', :action => 'Set') end when 'multiple_dropdowns_question' score = 100.0 / @responses.length.to_f @responses.each_with_index do |response, index| response_id = index + 1 processing_node.respcondition do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal "#{response_id}#{@answers.first.id}", :respident => "response_response#{response_id}" end condition_node.setvar "%.2f" % score, :varname => 'SCORE', :action => 'Add' end end when 'numerical_question' @numericals.each do |numerical| processing_node.respcondition(:continue => 'No') do |condition_node| condition_node.conditionvar do |var_node| var_node.or do |or_node| or_node.varequal numerical.answer.text, :respident => 'response1' or_node.and do |and_node| and_node.vargte numerical.answer.text.to_f - numerical.tolerance.to_f, :respident => 'response1' and_node.varlte numerical.answer.text.to_f + numerical.tolerance.to_f, :respident => 'response1' end end end condition_node.setvar(get_score(numerical.answer.fraction), :varname => "SCORE", :action => 'Set') condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{numerical.answer.id}_fb") if numerical.answer.feedback && numerical.answer.feedback.strip.length > 0 end end when 'short_answer_question' # Feedback @answers.each do |answer| next unless answer.feedback && answer.feedback.strip.length > 0 processing_node.respcondition(:continue => 'Yes') do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal answer.text, :respident => 'response1' end condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb") end end # Conditions @answers.each do |answer| processing_node.respcondition(:continue => 'No') do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal answer.text, :respident => 'response1' end condition_node.setvar(get_score(answer.fraction), :varname => 'SCORE', :action => "Set") end end when 'true_false_question' @answers.each do |answer| processing_node.respcondition(:continue => 'No') do |condition_node| condition_node.conditionvar do |var_node| var_node.varequal answer.id, :respident => 'response1' end condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb") if answer.feedback && answer.feedback.strip.length > 0 condition_node.setvar(get_score(answer.fraction), :varname => 'SCORE', :action => "Set") end end end end
create_responses(presentation_node)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 197 def create_responses(presentation_node) case @question_type when 'calculated_question' presentation_node.response_str(:rcardinality => 'Single', :ident => 'response1') do |response_node| response_node.render_fib(:fibtype => 'Decimal') do |render_node| render_node.response_label(:ident => 'answer1') end end when 'essay_question', 'short_answer_question', 'embedded_answers_question' presentation_node.response_str(:rcardinality => 'Single', :ident => 'response1') do |response_node| response_node.render_fib do |render_node| render_node.response_label(:ident => 'answer1', :rshuffle => 'No') end end when 'matching_question' @matches.each do |match| presentation_node.response_lid(:ident => "response_#{match.answer}") do |response_node| response_node.material do |material_node| material_node.mattext(match.question, :texttype => 'text/html') end response_node.render_choice do |choice_node| match.answers.each do |ident, text| choice_node.response_label(:ident => ident) do |label_node| label_node.material do |material_node| material_node.mattext text end end end end end end when 'multiple_choice_question' presentation_node.response_lid(:ident => 'response1', :rcardinality => 'Single') do |response_node| response_node.render_choice do |choice_node| @answers.each do |answer| choice_node.response_label(:ident => answer.id) do |label_node| label_node.material do |material_node| material_node.mattext answer.text, :texttype => 'text/html' end end end end end when 'multiple_answers_question' presentation_node.response_lid(:ident => 'response1', :rcardinality => 'Multiple') do |response_node| response_node.render_choice do |choice_node| @answers.each do |answer| choice_node.response_label(:ident => answer.id) do |label_node| label_node.material do |material_node| material_node.mattext answer.text, :texttype => 'text/html' end end end end end when 'multiple_dropdowns_question' @responses.each_with_index do |response, index| response_id = index + 1 presentation_node.response_lid(:ident => "response_response#{response_id}") do |response_node| response_node.material do |material_node| material_node.mattext "response#{response_id}" end response_node.render_choice do |choice_node| @answers.each do |answer| choice_node.response_label(:ident => "#{response_id}#{answer.id}") do |label_node| label_node.material do |material_node| material_node.mattext answer.text, :texttype => 'text/html' end end end end end end when 'numerical_question' presentation_node.response_str(:rcardinality => 'Single', :ident => 'response1') do |response_node| response_node.render_fib(:fibtype => 'Decimal') do |render_fib_node| render_fib_node.response_label(:ident => 'answer1') end end when 'true_false_question' presentation_node.response_lid(:rcardinality => 'Single', :ident => 'response1') do |response_node| response_node.render_choice do |render_choice_node| @answers.each do |answer| render_choice_node.response_label(:ident => answer.id) do |response_label_node| response_label_node.material do |material_node| material_node.mattext(answer.text, :texttype => 'text/html') end end end end end end end
get_score(fraction)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 482 def get_score(fraction) return 100 if fraction.nil? (100 * fraction).to_i end
image_html(image)
click to toggle source
# File lib/canvas_cc/canvas/question.rb, line 487 def image_html(image) image = image.strip %{<p><img src="#{WEB_CONTENT_TOKEN}/#{image}" alt="#{image}"/></p>} end