Thanks, Karl-Dieter.
I've made a little more progress:
1. Supports solutions now, including different instances of same problem.
2. No more \begin{sageprocesstext}{Problem}, just \begin{sagetext} now;
less clutter.
3. It's a single \include that you put right after \begin{document}, but
you still have to make the change to sagetex.sty.
I don't think I'm ready to submit a pull request until I know what I'm
doing better. I think I'll email Dan and we can discuss this offline. I
also don't feel the need to try to pressure him to add stuff to SageTeX
just for my pet project...it's up to him. I'll post here if he and I get
any important hurdles cleared.
I'll attach the files as they currently stand, in case you want to play
with this at all. It's been...extremely minimally tested. But there is a
working example! That's all anyone needs, right? :)
Nathan
On Friday, March 8, 2013 1:41:26 PM UTC-5, kcrisman wrote:
>
> Very impressive, Nathan.
>
>
>> So, here's some types of advice I'd love to receive on this:
>>
>> 1. Should I actually be suggesting changes to sagetex.sty? Or is there a
>> way to do that in my own .sty file? I couldn't call Dan's ST@stuff
>> commands from my own document, because I think TeX @ things are local or
>> something...*mumbles cluelessly*
>>
>> 2. Not sure if I can run sagesilent blocks when not inside a document,
>> which I'd need to do to move the class definition into a .sty file. Or
>> should I use something like \AtBeginDocument? Not sure if that will work
>> either. TeX is so touchy, and I'm rather new at this.
>>
>> 3. The goal is, of course, to get this nicely packaged into a single .sty
>> file that includes sagetex.sty, and then add the features mentioned above,
>> and then contribute it...someplace. When the time comes, what's the
>> appropriate "someplace"?
>>
>>>
>>>>
>
> Maybe a pull request at https://bitbucket.org/ddrake/sagetex/ ?
>
> I think you and Dan should talk a little about whether a new .sty file or
> adding a new block type is better - and what the name of the block should
> be, etc.
>
--
You received this message because you are subscribed to the Google Groups
"sage-edu" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-edu?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
%!TEX TS-program = sage
\documentclass{article}
\usepackage{sagetex}
\begin{document}
\include{sagetex_exam_include}
\begin{sagetext}
First Problem
a = randint(1,20)
b = randint(1,20)
What is $\sage{a}+\sage{b}$?
$\sage{a+b}$
\end{sagetext}
Problem 1: \insertproblem[one]{First Problem}
Problem 2: \insertproblem[two]{First Problem}
\hfill
Answer 2: \insertsolution[two]
Answer 1: \insertsolution[one]
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Include this file in any document that wishes to use Sage to create exams.
% Then define problems like this:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% \begin{sagetext}
% Problem type name
%
% initialization code
%
% Text of problem
%
% Text of solution
% \end{sagetext}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Example:
%
% \begin{sagetext}
% Simple addition
%
% a = randint(1,10)
% b = randint(1,10)
%
% What is the sum of $\sage{a}$ and $\sage{b}$?
%
% $\sage{a+b}$
% \end{sagetext}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Then to insert a problem, use \insertproblem{type name}, or \insertproblem[instance name]{type name}.
% Then to insert a solution, use \insertsolution (which inserts the next solution in the order in which the
% problems were defined) or \insertsolution[instance name] (to insert the solution that goes with a problem
% to which you've given a particular name).
%
% Examples:
%
% Problem 1: \insertproblem{Simple addition}
% Problem 2: \insertproblem{Simple addition}
% Answer 1: \insertsolution
% Answer 2: \insertsolution
%
% or
%
% Problem 1: \insertproblem[one]{Simple addition}
% Problem 2: \insertproblem[two]{Simple addition}
% The second problem's answer is \insertsolution[two], but the first's is \insertsolution[one].
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{sagesilent}
from string import *
def safepop ( ary ):
return ary.pop( 0 ) if len( ary ) > 0 else ''
class Problem:
allProblems = {}
allInstances = {}
lastSolutionIndex = -1
def __init__ ( self, text ):
text = text.split( '\n\n' )
self._name = safepop( text )
self._setup = safepop( text )
self._text = safepop( text )
self._soln = safepop( text )
Problem.allProblems[self._name] = self
def instantiate ( self ):
vars = {}
sage_eval( 'None', cmds=self._setup, locals=vars )
copy = self._text
while copy.find( '\\sage{' ) > -1:
start = copy.find( '\\sage{' )
stop = copy.find( '}', start )
inside = copy[start+6:stop]
copy = copy[:start] + str( sage_eval( inside, locals=vars ) ) + copy[stop+1:]
result = { 'text' : copy }
copy = self._soln
while copy.find( '\\sage{' ) > -1:
start = copy.find( '\\sage{' )
stop = copy.find( '}', start )
inside = copy[start+6:stop]
copy = copy[:start] + str( sage_eval( inside, locals=vars ) ) + copy[stop+1:]
result['soln'] = copy
return result
@staticmethod
def insert ( name, key ):
newprob = Problem.allProblems[name].instantiate()
if key in Problem.allInstances:
Problem.allInstances[key] += [ newprob ]
else:
Problem.allInstances[key] = [ newprob ]
return newprob['text']
@staticmethod
def insertSolution ( key ):
if ( key in Problem.allInstances ) and ( len( Problem.allInstances[key] ) > 0 ):
return Problem.allInstances[key].pop( 0 )['soln']
else:
return ''
\end{sagesilent}
\newcommand\insertproblem[2][ ]{\sagestr{Problem.insert(r"""#2""",r"""#1""")}}
\newcommand\insertsolution[1][ ]{\sagestr{Problem.insertSolution(r"""#1""")}}
\sagetextprocessor{Problem}
%%
%% This is file `sagetex.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% sagetex.dtx (with options: `latex')
%% py-and-sty.dtx (with options: `latex')
%%
%% This is a generated file. It is part of the SageTeX package.
%%
%% Copyright (C) 2008--2012 by Dan Drake <[email protected]>
%%
%% This program is free software: you can redistribute it and/or modify it
%% under the terms of the GNU General Public License as published by the
%% Free Software Foundation, either version 2 of the License, or (at your
%% option) any later version.
%%
%% This program is distributed in the hope that it will be useful, but
%% WITHOUT ANY WARRANTY; without even the implied warranty of
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
%% Public License for more details.
%%
%% You should have received a copy of the GNU General Public License along
%% with this program. If not, see <http://www.gnu.org/licenses/>.
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{sagetex}
[2012/01/16 v2.3.3-69dcb0eb93de embedding Sage into LaTeX documents]
\newcommand{\ST@ver}{2012/01/16 v2.3.3-69dcb0eb93de}
\RequirePackage{verbatim}
\RequirePackage{fancyvrb}
\RequirePackage{listings}
\RequirePackage{color}
\lstdefinelanguage{Sage}[]{Python}
{morekeywords={False,sage,True},sensitive=true}
\lstdefinelanguage{SageOutput}[]{}
{morekeywords={False,True},sensitive=true}
\lstdefinestyle{DefaultSageInputOutput}{
nolol,
identifierstyle=,
name=sagecommandline,
xleftmargin=5pt,
numbersep=5pt,
aboveskip=0pt,
belowskip=0pt,
breaklines=true,
numberstyle=\footnotesize,
numbers=right
}
\lstdefinestyle{DefaultSageInput}{
language=Sage,
style=DefaultSageInputOutput,
basicstyle={\ttfamily\bfseries},
commentstyle={\ttfamily\color{dgreencolor}},
keywordstyle={\ttfamily\color{dbluecolor}\bfseries},
stringstyle={\ttfamily\color{dgraycolor}\bfseries},
}
\lstdefinestyle{DefaultSageOutput}{
language=SageOutput,
style=DefaultSageInputOutput,
basicstyle={\ttfamily},
commentstyle={\ttfamily\color{dgreencolor}},
keywordstyle={\ttfamily\color{dbluecolor}},
stringstyle={\ttfamily\color{dgraycolor}},
}
\lstdefinestyle{SageInput}{
style=DefaultSageInput,
}
\lstdefinestyle{SageOutput}{
style=DefaultSageOutput,
}
\definecolor{dbluecolor}{rgb}{0.01,0.02,0.7}
\definecolor{dgreencolor}{rgb}{0.2,0.4,0.0}
\definecolor{dgraycolor}{rgb}{0.30,0.3,0.30}
\RequirePackage{graphicx}
\RequirePackage{makecmds}
\RequirePackage{ifpdf}
\RequirePackage{ifthen}
\IfFileExists{ifxetex.sty}{
\RequirePackage{ifxetex}
}{
\newboolean{xetex}
\setboolean{xetex}{false}}
\newcounter{ST@inline}
\newcounter{ST@plot}
\newcounter{ST@cmdline}
\setcounter{ST@inline}{0}
\setcounter{ST@plot}{0}
\setcounter{ST@cmdline}{0}
\newlength{\sagetexindent}
\setlength{\sagetexindent}{5ex}
\newif\ifST@paused
\ST@pausedfalse
\AtBeginDocument{\@ifundefined{ST@final}{%
\newwrite\ST@sf%
\immediate\openout\ST@sf=\jobname.sagetex.sage%
\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}}%
\ST@wsf{%
# -*- encoding: utf-8 -*-^^J%
# This file (\jobname.sagetex.sage) was *autogenerated* from \jobname.tex with
sagetex.sty version \ST@ver.^^J%
import sagetex^^J%
_st_ = sagetex.SageTeXProcessor('\jobname', version='\ST@ver', version_check=\ST@versioncheck)}}%
{\newcommand{\ST@wsf}[1]{\relax}}}
\newcommand{\ST@dodfsetup}{%
\@ifundefined{ST@diddfsetup}{%
\newwrite\ST@df%
\immediate\openout\ST@df=\jobname_doctest.sage%
\immediate\write\ST@df{r"""^^J%
This file was *autogenerated* from \jobname.tex with sagetex.sty^^J%
version \ST@ver. It contains the contents of all the^^J%
sageexample environments from \jobname.tex. You should be able to^^J%
doctest this file with "sage -t \jobname_doctest.sage".^^J%
^^J%
It is always safe to delete this file; it is not used in typesetting your^^J%
document.^^J}%
\AtEndDocument{\immediate\write\ST@df{"""}}%
\gdef\ST@diddfsetup{x}}%
{\relax}}
\newcommand{\ST@wdf}[1]{\immediate\write\ST@df{#1}}
\DeclareOption{final}{%
\newcommand{\ST@final}{x}%
\IfFileExists{\jobname.sagetex.sout}{}{\AtEndDocument{\PackageWarningNoLine{sagetex}%
{`final' option provided, but \jobname.sagetex.sout^^Jdoesn't exist! No Sage
input will appear in your document. Remove the `final'^^Joption and
rerun LaTeX on your document}}}}
\DeclareOption{imagemagick}{%
\newcommand{\ST@useimagemagick}{x}%
\AtBeginDocument{%
\@ifundefined{ST@final}{%
\ST@wsf{_st_.useimagemagick = True}}{}}}
\DeclareOption{epstopdf}{%
\AtBeginDocument{%
\@ifundefined{ST@final}{%
\ST@wsf{_st_.useepstopdf = True}}{}}}
\newcommand{\ST@versioncheck}{True}
\DeclareOption{noversioncheck}{%
\renewcommand{\ST@versioncheck}{False}}
\ProcessOptions\relax
\InputIfFileExists{\jobname.sagetex.sout}{}
{\typeout{No file \jobname.sagetex.sout.}}
\AtBeginDocument{\provideenvironment{NoHyper}{}{}}
\newcommand{\ST@sage}[1]{\ST@wsf{%
try:^^J
_st_.inline(\theST@inline, #1)^^J%
except:^^J
_st_.goboom(\the\inputlineno)}%
\ifST@paused
\mbox{(Sage\TeX{} is paused)}%
\else
\begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper}%
\@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{}%
\fi
\stepcounter{ST@inline}}
\newcommand{\sage}[1]{\ST@sage{latex(#1)}}
\newcommand{\sagestr}[1]{\ST@sage{#1}}
\catcode`\%=12
\newcommand{\percent}{%}
\catcode`\%=14
\newcommand{\ST@plotdir}{sage-plots-for-\jobname.tex}
\newcommand{\ST@missingfilebox}{\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}}
\newcommand{\sageplot}[1][]{%
\@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}}
\def\ST@sageplot[#1][#2]#3{\ST@wsf{try:^^J
_st_.plot(\theST@plot, format='#2', _p_=#3)^^Jexcept:^^J
_st_.goboom(\the\inputlineno)}%
\ifthenelse{\boolean{pdf} \or \boolean{xetex}}{
\ifthenelse{\equal{#2}{notprovided}}%
{\ST@inclgrfx{#1}{pdf}}%
{\ST@inclgrfx{#1}{#2}}}
{ \ifthenelse{\equal{#2}{notprovided}}%
{\ST@inclgrfx{#1}{eps}}%
{\@ifundefined{ST@useimagemagick}%
{\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}%
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space
cannot be used with DVI output. Use pdflatex or create an EPS
file. Plot command is}}%
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space
does not exist. Plot command is}%
\gdef\ST@rerun{x}}}%
{\ST@inclgrfx{#1}{eps}}}}
\stepcounter{ST@plot}}
\newcommand{\ST@inclgrfx}[2]{\ifST@paused
\fbox{\rule[-1cm]{0cm}{2cm}Sage\TeX{} is paused; no graphic}
\else
\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}%
{\includegraphics[#1]{\ST@plotdir/plot-\theST@plot.#2}}%
{\IfFileExists{\ST@plotdir/plot-\[email protected]}%
{\ifpdf
\ST@inclgrfx{#1}{png}
\else
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\[email protected] on page \thepage\space not
supported; try using pdflatex. Plot command is}%
\fi}%
{\ST@missingfilebox%
\PackageWarning{sagetex}{Graphics file
\ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space does not
exist. Plot command is}%
\gdef\ST@rerun{x}}}
\fi}
\newcommand{\ST@beginsfbl}{%
\@bsphack\ST@wsf{%
_st_.blockbegin()^^Jtry:}%
\let\do\@makeother\dospecials\catcode`\^^M\active}
\newcommand{\ST@endsfbl}{%
\ST@wsf{except:^^J
_st_.goboom(\the\inputlineno)^^J_st_.blockend()}}
\newenvironment{sageblock}{\ST@beginsfbl%
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}%
\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
{\ST@endsfbl\endverbatim}
\newenvironment{sagesilent}{\ST@beginsfbl%
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}}%
\verbatim@start}%
{\ST@endsfbl\@esphack}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Begin modifications made by Nathan Carter in May 2013
\newcommand\sagetextprocessor[1]{\ST@wsf{try:^^J
_st_._processor = #1^^J%
except:^^J
_st_.goboom(\the\inputlineno)}}
\newenvironment{sagetext}{\ST@beginsfbl%
\ST@wsf{ _st_._processor(r"""}%
\def\verbatim@processline{\ST@wsf{\the\verbatim@line}}%
\verbatim@start}%
{\ST@wsf{""".strip())}\ST@endsfbl\@esphack}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End modifications
\newenvironment{sageverbatim}{%
\def\verbatim@processline{\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
{\endverbatim}
\newcommand{\sageexampleincludetextoutput}{False}
\newenvironment{sageexample}{%
\ST@wsf{%
try:^^J
_st_.doctest(\theST@inline, r"""}%
\ST@dodfsetup%
\ST@wdf{Sage example, line \the\inputlineno::^^J}%
\begingroup%
\@bsphack%
\let\do\@makeother\dospecials%
\catcode`\^^M\active%
\def\verbatim@processline{%
\ST@wsf{\the\verbatim@line}%
\ST@wdf{\the\verbatim@line}%
}%
\verbatim@start%
}
{
\@esphack%
\endgroup%
\ST@wsf{%
""", globals(), locals(), \sageexampleincludetextoutput)^^Jexcept:^^J
_st_.goboom(\the\inputlineno)}%
\ifST@paused%
\mbox{(Sage\TeX{} is paused)}%
\else%
\begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper}%
\@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{}%
\fi%
\ST@wdf{}%
\stepcounter{ST@inline}}
\newcommand{\sagecommandlinetextoutput}{True}
\newlength{\sagecommandlineskip}
\setlength{\sagecommandlineskip}{8pt}
\newenvironment{sagecommandline}{%
\ST@wsf{%
try:^^J
_st_.commandline(\theST@cmdline, r"""}%
\ST@dodfsetup%
\ST@wdf{Sage commandline, line \the\inputlineno::^^J}%
\begingroup%
\@bsphack%
\let\do\@makeother\dospecials%
\catcode`\^^M\active%
\def\verbatim@processline{%
\ST@wsf{\the\verbatim@line}%
\ST@wdf{\the\verbatim@line}%
}%
\verbatim@start%
}
{
\@esphack%
\endgroup%
\ST@wsf{%
""", globals(), locals(), \sagecommandlinetextoutput)^^Jexcept:^^J
_st_.goboom(\the\inputlineno)}%
\ifST@paused%
\mbox{(Sage\TeX{} is paused)}%
\else%
\begin{NoHyper}\ref{@sagecmdline\theST@cmdline}\end{NoHyper}%
\@ifundefined{r@@sagecmdline\theST@cmdline}{\gdef\ST@rerun{x}}{}%
\fi%
\ST@wdf{}%
\stepcounter{ST@cmdline}}
\newcommand{\sagetexpause}{\ifST@paused\relax\else
\ST@wsf{print 'SageTeX paused on \jobname.tex line \the\inputlineno'^^J"""}
\ST@pausedtrue
\fi}
\newcommand{\sagetexunpause}{\ifST@paused
\ST@wsf{"""^^Jprint 'SageTeX unpaused on \jobname.tex line \the\inputlineno'}
\ST@pausedfalse
\fi}
\AtEndDocument{\ifST@paused
\ST@wsf{"""^^Jprint 'SageTeX unpaused at end of \jobname.tex'}
\fi
\ST@wsf{_st_.endofdoc()}%
\@ifundefined{ST@rerun}{}%
{\typeout{*********************************************************************}
\PackageWarningNoLine{sagetex}{there were undefined Sage formulas and/or
plots.^^JRun Sage on \jobname.sagetex.sage, and then run LaTeX on \jobname.tex
again}}
\typeout{*********************************************************************}}
\endinput
%%
%% End of file `sagetex.sty'.