Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 6b6a1e1

Browse files
committed
Parsons converted to PTX
1 parent d966e86 commit 6b6a1e1

File tree

1 file changed

+79
-3
lines changed

1 file changed

+79
-3
lines changed

runestone/parsons/parsons.py

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
#
1616
__author__ = "isaiahmayerchak"
17-
17+
from textwrap import dedent
18+
import pdb
19+
import random
1820
from docutils import nodes
1921
from docutils.parsers.rst import directives
2022
from runestone.mchoice import Assessment
@@ -53,13 +55,87 @@ class ParsonsNode(nodes.General, nodes.Element, RunestoneIdNode):
5355
pass
5456

5557

58+
def wrap_with_tag(text: str, tag: str, **kwargs) -> str:
59+
start = f"<{tag}"
60+
for k, v in kwargs.items():
61+
start += f" {k}='{v}'"
62+
start += ">"
63+
end = f"</{tag}>\n"
64+
return start + text + end
65+
66+
5667
def visit_parsons_xml(self, node):
57-
res = TEMPLATE_START % node["runestone_options"]
68+
if node["runestone_options"]["numbered"]:
69+
node["runestone_options"]["numbered"] = "numbered='yes'"
70+
71+
if node["runestone_options"]["adaptive"]:
72+
node["runestone_options"]["adaptive"] = "adaptive='yes'"
73+
74+
if not node["runestone_options"]["noindent"]:
75+
node["runestone_options"]["noindent"] = "indent='yes'"
76+
77+
if node["runestone_options"]["language"]:
78+
node["runestone_options"]["language"] = node["runestone_options"]["language"].replace(
79+
"data-", "")
80+
else:
81+
node["runestone_options"]["language"] = "language='python'"
82+
83+
res = "<exercise xml:id='{divid}' {numbered} {adaptive} {noindent} {language}>".format(
84+
**node["runestone_options"])
85+
res += "<statement>\n"
5886
self.output.append(res)
5987

6088

89+
def process_one_block(block, choice=False, correct=False, natural=False):
90+
code_list = block.split("\n")
91+
if choice:
92+
attrs = "correct='yes'" if correct else ""
93+
res = f"<choice {attrs}>"
94+
else:
95+
res = ""
96+
for line in code_list:
97+
if line:
98+
line = line.replace("#paired", "")
99+
line = line.replace("#distractor", "")
100+
if natural:
101+
res += wrap_with_tag(line, "p")
102+
else:
103+
res += wrap_with_tag(line, "cline")
104+
if choice:
105+
res += "</choice>"
106+
return res
107+
108+
61109
def depart_parsons_xml(self, node):
62-
res = TEMPLATE_END % node["runestone_options"]
110+
res = "</statement>\n<blocks>"
111+
if "natural" in node["runestone_options"]["language"]:
112+
natural = True
113+
else:
114+
natural = False
115+
# first split into blocks based on --- then process each block...
116+
block_list = dedent(node["runestone_options"]["code"]).split("---")
117+
order = list(range(1, len(block_list) + 1))
118+
random.shuffle(order)
119+
block = block_list.pop(0)
120+
while block:
121+
attr = f"order='{order.pop()}' "
122+
attr += "correct='no'" if "#distractor" in block else ""
123+
res += f"<block {attr}>\n"
124+
# check to see if the next block is a distractor
125+
if block_list and "#paired" in block_list[0]:
126+
choice = True
127+
res += process_one_block(block, choice, True, natural)
128+
res += process_one_block(block_list.pop(0), choice, False, natural)
129+
else:
130+
choice = False
131+
res += process_one_block(block, choice, True, natural)
132+
res += "</block>"
133+
if block_list:
134+
block = block_list.pop(0)
135+
else:
136+
block = None
137+
138+
res += "</blocks></exercise>"
63139
self.output.append(res)
64140

65141

0 commit comments

Comments
 (0)