lib/spirit/render/templates/table.rb
# ~*~ encoding: utf-8 ~*~
module Spirit
module Render
# Renders table problems marked up in YAML as HTML.
#
# The grid should be given as a 2-dimensional array that represents the
# table to be filled in. +"?"+ is a special token used in the grid to
# indicate cells that require student input.
#
# The answer should also be given as a 2-dimensional array. However, a
# dummy token may be used in cells that do not require student input to
# cut redundancy. In the example below, the +"-"+ token is used.
#
# @example
# {
# "format": "table",
# "question": "fill me in",
# "grid": [[0, "?", 2], [3, "?", 5]],
# "answer": [["-", 1, "-"], ["-", 4, "-"]
# }
class Table < Problem
# Name of template file for rendering table problems.
self.template = 'table.haml'
# Optional headings key.
HEADINGS = 'headings'
# Required grid key.
GRID = 'grid'
# Special token indicating that the cell should be filled in.
FILL_ME_IN = '?'
accessor HEADINGS, GRID
# Ensures that the +headings+ key exists.
def initialize(yaml, digest)
yaml[HEADINGS] ||= nil
super
end
# Checks if the given yaml contains a valid table.
# @return [Boolean] true iff the yaml contains a valid table.
def valid?
super and
valid_grid? and
valid_answer?
end
# Gets the expected answer, in www-form-urlencoded format.
# @return [Hash] answers, as expected from student's form submission
def answer
return @answer unless @answer.nil?
@answer = encode_answer
end
# @return [Boolean] true iff the given cell is an input cell
def self.input?(cell)
cell == FILL_ME_IN
end
private
# Iterates through each cell in the provided grid to look for answers
# cells that require input and takes the answer from the answers array.
# For example, if the answer for a cell at [0][1] is 6, the returned
# hash will contain
#
# {'0' => {'1' => 6}}
#
# @return [Hash] answers
def encode_answer
encoded, ans = {}, @yaml[ANSWER]
grid.each_with_index do |row, i|
row.each_with_index do |cell, j|
next unless Table.input? cell
encoded[i.to_s] ||= {}
encoded[i.to_s][j.to_s] = serialize ans[i][j]
end
end
encoded
end
# @return [Boolean] true iff the yaml contains a valid grid.
def valid_grid?
@yaml.has_key? GRID and is_2d_array? grid
end
# @return [Boolean] true iff +answer+ is a valid 2D array and has the
# same number of rows as +grid+.
def valid_answer?
ans = @yaml[ANSWER]
is_2d_array? ans and ans.size == grid.size
end
# @return [Boolean] true iff +t+ is a 2-dimensional array.
def is_2d_array?(t)
t.is_a? Array and t.all? { |row| row.is_a? Array }
end
end
end
end