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 sage-edu+unsubscr...@googlegroups.com.
To post to this group, send email to sage-edu@googlegroups.com.
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 <ddr...@member.ams.org>
%% 
%% 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-\th...@plot.png}%
       {\ifpdf
           \ST@inclgrfx{#1}{png}
         \else
           \PackageWarning{sagetex}{Graphics file
           \ST@plotdir/plot-\th...@plot.png 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'.

Reply via email to