diff options
author | Karl Berry <karl@freefriends.org> | 2013-03-10 22:39:29 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2013-03-10 22:39:29 +0000 |
commit | ae5a201447b1cb04ab401b5145d92bf62f4cd1c5 (patch) | |
tree | a66487fcd170eaa803157e2da0500a41913d2348 /Master/texmf-dist/tex/latex/exsheets/exsheets.sty | |
parent | 89135e7e1b6a211b066867735c41e9a1a4310c5f (diff) |
exsheets (10mar13)
git-svn-id: svn://tug.org/texlive/trunk@29334 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/exsheets/exsheets.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/exsheets/exsheets.sty | 738 |
1 files changed, 424 insertions, 314 deletions
diff --git a/Master/texmf-dist/tex/latex/exsheets/exsheets.sty b/Master/texmf-dist/tex/latex/exsheets/exsheets.sty index 8ad8e86a9a7..e4b2856baf5 100644 --- a/Master/texmf-dist/tex/latex/exsheets/exsheets.sty +++ b/Master/texmf-dist/tex/latex/exsheets/exsheets.sty @@ -31,8 +31,8 @@ % If you have any ideas, questions, suggestions or bugs to report, please % feel free to contact me. % ---------------------------------------------------------------------------- -\def\exsheets@date{2013/02/17} -\def\exsheets@version{0.7b} +\def\exsheets@date{2013/03/10} +\def\exsheets@version{0.8} \RequirePackage { expl3 , xparse } \ProvidesExplPackage @@ -72,12 +72,18 @@ pretend~nothing~happened. } -\msg_new:nnn { exsheets } { random } +\msg_new:nnn { exsheets } { random-file } { - You~asked~me~to~select~#1~questions~from~file~#2~but~there~are~only~#3.~ + You~asked~me~to~select~#1~questions~from~file~#2~which~contains~#3~questions.~ I'll~select~all~of~them. } +\msg_new:nnn { exsheets } { random-selectable } + { + You~asked~me~to~select~#1~questions~from~file~#2~which~contains~#3~questions.~ + #4~of~these~are~selectable,~so~I'll~select~all~of~them. + } + \msg_new:nnn { exsheets } { only-inside-question } { The~command~\token_to_str:N #1 \c_space_tl can~only~be~used~inside~ @@ -532,7 +538,7 @@ % inspiration of the following features \int_zero_new:N \l__exsheets_variations_int -\cs_new:Npn \exsheets_set_variations:n #1 +\cs_new_protected:Npn \exsheets_set_variations:n #1 { \int_compare:nNnTF { #1 } < { 2 } { \msg_warning:nnn { exsheets } { variations } { #1 } } @@ -554,7 +560,7 @@ } } -\cs_new:Npn \exsheets_variant:n #1 +\cs_new_protected:Npn \exsheets_variant:n #1 { \bool_if:nTF { @@ -588,14 +594,14 @@ \cs_new:Npn \exsheets_last_variant: { } -\cs_new:Npn \__exsheets_generate_variation_auxiliary:n #1 +\cs_new_protected:Npn \__exsheets_generate_variation_auxiliary:n #1 { \cs_if_exist:cTF { __exsheets_variation_ \int_to_roman:n { #1 } :n } { \cs_set:cpn { __exsheets_variation_ \int_to_roman:n { #1 } :n } { } } { \cs_new:cpn { __exsheets_variation_ \int_to_roman:n { #1 } :n } { } } } -\cs_new:Npn \__exsheets_reset_variation_auxiliary:n #1 +\cs_new_protected:Npn \__exsheets_reset_variation_auxiliary:n #1 { \cs_set:cpn { __exsheets_variation_ \int_to_roman:n { #1 } :n } ##1 { \use:c { __exsheets_variation_ \int_to_roman:n { #1 + 1 } :n } } @@ -641,17 +647,17 @@ \cs_new:Npn \exsheets_strip_braces:N #1 { \exp_after:wN \__exsheets_strip_braces:w \exp_after:wN #1#1 \q_stop } -\cs_new:Npn \__exsheets_strip_braces:w #1#2 \q_stop +\cs_new_protected:Npn \__exsheets_strip_braces:w #1#2 \q_stop { \tl_set:Nn #1 { #2 } } -\cs_new:Npn \__exsheets_declare_relgrades:n #1 +\cs_new_protected:Npn \__exsheets_declare_relgrades:n #1 { \clist_set:Nn \l__exsheets_tmpa_clist { #1 } \clist_map_inline:Nn \l__exsheets_tmpa_clist { \__exsheets_declare_relgrade:w ##1 \q_stop } } -\cs_new:Npn \__exsheets_declare_relgrade:w #1 = #2 \q_stop +\cs_new_protected:Npn \__exsheets_declare_relgrade:w #1 = #2 \q_stop { \tl_set:Nn \l__exsheets_tmpa_tl { #1 } \tl_set:Nn \l__exsheets_tmpb_tl { #2 } @@ -666,7 +672,7 @@ \NewDocumentCommand \DeclareRelGrades { m } { \__exsheets_declare_relgrades:n { #1 } } -\@onlypreamble\DeclareRelGrades +\@onlypreamble \DeclareRelGrades \cs_new:Npn \__exsheets_grade:nn #1#2 { @@ -702,36 +708,15 @@ % ---------------------------------------------------------------------------- % Aufgaben und Lösungen - -% Einteilung in Klassen und Themen -\prop_new:N \g__exsheets_questions_class_prop -\prop_new:N \g__exsheets_classes_prop -\prop_new:N \g__exsheets_classes_active_prop -\prop_new:N \g__exsheets_questions_topic_prop -\prop_new:N \g__exsheets_topics_prop -\prop_new:N \g__exsheets_topics_active_prop - \bool_new:N \g__exsheets_questions_use_bool \bool_gset_true:N \g__exsheets_questions_use_bool \bool_new:N \l__exsheets_questions_use_bool \bool_set_true:N \l__exsheets_questions_use_bool \bool_new:N \l__exsheets_questions_deactivate_bool -\bool_new:N \l__exsheets_questions_class_bool -\bool_set_false:N \l__exsheets_questions_class_bool -\bool_new:N \g__exsheets_use_classes_bool -\bool_gset_false:N \g__exsheets_use_classes_bool -\bool_new:N \l__exsheets_class_active_bool -\bool_new:N \l__exsheets_questions_topic_bool -\bool_set_false:N \l__exsheets_questions_topic_bool -\bool_new:N \g__exsheets_use_topics_bool -\bool_gset_false:N \g__exsheets_use_topics_bool -\bool_new:N \l__exsheets_topic_active_bool + \bool_new:N \l__exsheets_solutions_use_bool \bool_set_true:N \l__exsheets_solutions_use_bool -\tl_new:N \l__exsheets_questions_class_tl -\tl_new:N \l__exsheets_questions_topic_tl - \dim_new:N \l__exsheets_questions_skip_below_dim \dim_set:Nn \l__exsheets_questions_skip_below_dim { .5\baselineskip } \dim_new:N \l__exsheets_solutions_skip_below_dim @@ -742,160 +727,122 @@ \keys_define:nn { exsheets } { - use-classes .code:n = - { - \bool_gset_true:N \g__exsheets_use_classes_bool - \__exsheets_activate_classes:n { #1 } - } , - use-topics .code:n = - { - \bool_gset_true:N \g__exsheets_use_topics_bool - \__exsheets_activate_topics:n { #1 } - } , skip-below .code:n = \dim_set:Nn \l__exsheets_questions_skip_below_dim { #1 } \dim_set:Nn \l__exsheets_solutions_skip_below_dim { #1 } } -\cs_new:Npn \__exsheets_activate_classes:n #1 - { - \prop_gclear:N \g__exsheets_classes_active_prop - \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } { #1 } - \seq_map_inline:Nn \l__exsheets_tmpa_seq - { - \prop_gput:Nnn \g__exsheets_classes_active_prop - { ##1 } { \__exsheets_dummy: } - } - } - -\cs_new:Npn \__exsheets_activate_topics:n #1 - { - \prop_gclear:N \g__exsheets_topics_active_prop - \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } { #1 } - \seq_map_inline:Nn \l__exsheets_tmpa_seq - { - \prop_gput:Nnn \g__exsheets_topics_active_prop - { ##1 } { \__exsheets_dummy: } - } - } +% Einteilung in Klassen, Themen und andere Gruppierungen: +\prop_new:N \l__exsheets_class_prop +\tl_new:N \l__exsheets_step_counter_tl +\bool_new:N \l__exsheets_use_this_question_bool -\cs_new_nopar:Npn \__exsheets_questions_use_classes: +\cs_new_protected:Npn \exsheets_new_question_class:nn #1#2 { - % is there a class provided? - \bool_if:NT \l__exsheets_questions_class_bool + \prop_put:Nnn \l__exsheets_class_prop { #2 } { #1 } + \prop_new:c { g__exsheets_questions_#1_prop } + \prop_new:c { g__exsheets_#2_prop } + \prop_new:c { g__exsheets_#2_active_prop } + \bool_new:c { l__exsheets_questions_#1_bool } + \bool_new:c { g__exsheets_use_#2_bool } + \bool_new:c { l__exsheets_#1_active_bool } + \tl_new:c { l__exsheets_questions_#1_tl } + \keys_define:nn { exsheets } { - % add class to questions property - \prop_gput:Nff \g__exsheets_questions_class_prop - { \int_to_arabic:n { \g__exsheets_questions_id_int } } - { \l__exsheets_questions_class_tl } - % add to classes list, if it's a new one - \prop_get:NoN \g__exsheets_classes_prop - { \l__exsheets_questions_class_tl } - \l__exsheets_tmpa_tl - \tl_if_eq:NNT \l__exsheets_tmpa_tl \q_no_value + use-#2 .code:n = { - \prop_gput:Nfn \g__exsheets_classes_prop - { \l__exsheets_questions_class_tl } - { \__exsheets_dummy: } + \bool_gset_true:c { g__exsheets_use_#2_bool } + \use:c { __exsheets_activate_#2:n } { ##1 } + } , + question / #1 .code:n = + \bool_set_true:c { l__exsheets_questions_#1_bool } + \tl_set:cn { l__exsheets_questions_#1_tl } { ##1 } +% \exsheets_set_question_properties:n { #1 = ##1 } + } + \cs_new_protected:cpn { __exsheets_activate_#2:n } ##1 + { + \prop_gclear:c { g__exsheets_#2_active_prop } + \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } { ##1 } + \seq_map_inline:Nn \l__exsheets_tmpa_seq + { + \prop_gput:cnn { g__exsheets_#2_active_prop } + { ####1 } { \__exsheets_dummy: } } } - % are we using classes? - \bool_if:NT \g__exsheets_use_classes_bool + \cs_new_protected:cpn { __exsheets_questions_use_#2: } { - % is this question an active one? - \prop_get:NoN \g__exsheets_classes_active_prop - { \l__exsheets_questions_class_tl } - \l__exsheets_tmpa_tl - \tl_if_eq:NNTF \l__exsheets_tmpa_tl \q_no_value + % is there a #1 provided? + \bool_if:cT { l__exsheets_questions_#1_bool } { - \bool_set_false:N \l__exsheets_class_active_bool - \bool_set_false:N \l__exsheets_questions_print_bool + % add #1 to questions property + \prop_gput:cff { g__exsheets_questions_#1_prop } + { \int_to_arabic:n { \g__exsheets_questions_id_int } } + { \tl_use:c { l__exsheets_questions_#1_tl } } + % add to #2 list, if it's a new one + \prop_get:cfN { g__exsheets_#2_prop } + { \tl_use:c { l__exsheets_questions_#1_tl } } + \l__exsheets_tmpa_tl + \tl_if_eq:NNT \l__exsheets_tmpa_tl \q_no_value + { + \prop_gput:cfn { g__exsheets_#2_prop } + { \tl_use:c { l__exsheets_questions_#1_tl } } + { \__exsheets_dummy: } + } } - { \bool_set_true:N \l__exsheets_class_active_bool } - } - } - -\cs_new_nopar:Npn \__exsheets_questions_use_topics: - { - % is there a topic provided? - \bool_if:NT \l__exsheets_questions_topic_bool - { - % add topic to questions property - \prop_gput:Nff \g__exsheets_questions_topic_prop - { \int_to_arabic:n { \g__exsheets_questions_id_int } } - { \l__exsheets_questions_topic_tl } - % add to topics list, if it's a new one - \prop_get:NoN \g__exsheets_topics_prop - { \l__exsheets_questions_topic_tl } - \l__exsheets_tmpa_tl - \tl_if_eq:NNT \l__exsheets_tmpa_tl \q_no_value + % are we using #2? + \bool_if:cT { g__exsheets_use_#2_bool } { - \prop_gput:Nfn \g__exsheets_topics_prop - { \l__exsheets_questions_topic_tl } - { \__exsheets_dummy: } + % is this question an active one? + \prop_get:cfN { g__exsheets_#2_active_prop } + { \tl_use:c { l__exsheets_questions_#1_tl } } + \l__exsheets_tmpa_tl + \tl_if_eq:NNTF \l__exsheets_tmpa_tl \q_no_value + { + \bool_set_false:c { l__exsheets_#1_active_bool } + \bool_set_false:N \l__exsheets_questions_print_bool + } + { + \bool_set_true:c { l__exsheets_#1_active_bool } + \bool_set_true:N \l__exsheets_use_this_question_bool + } } } - % are we using topics? - \bool_if:NT \g__exsheets_use_topics_bool + \cs_new_protected:cpn { __exsheets_solutions_use_#2: } { - % is this question an active one? - \prop_get:NoN \g__exsheets_topics_active_prop - { \l__exsheets_questions_topic_tl } - \l__exsheets_tmpa_tl - \tl_if_eq:NNTF \l__exsheets_tmpa_tl \q_no_value + % are we using #2? + \bool_if:cT { g__exsheets_use_#2_bool } { - \bool_set_false:N \l__exsheets_topic_active_bool - \bool_set_false:N \l__exsheets_questions_print_bool + % is the question to this solution an active one? + % get question number from ID + \prop_get:NoN \g__exsheets_questions_id_prop + { \g__exsheets_questions_current_id_tl } \l__exsheets_tmpa_tl + % get question #1 from number + \prop_get:coN { g__exsheets_questions_#1_prop } + { \l__exsheets_tmpa_tl } \l__exsheets_tmpb_tl + % test if #1 is active + \prop_get:coN { g__exsheets_#2_active_prop } + { \l__exsheets_tmpb_tl } \l__exsheets_tmpc_tl + \tl_if_eq:NNT \l__exsheets_tmpc_tl \q_no_value + { \bool_set_false:N \l__exsheets_solutions_use_bool } } - { \bool_set_true:N \l__exsheets_topic_active_bool } } - \int_set:Nn \l__exsheets_counter_qu_int { \arabic{question} } } +\cs_generate_variant:Nn \prop_get:NnN { cf } +\cs_generate_variant:Nn \prop_gput:Nnn { cf , cff } -\cs_new_nopar:Npn \__exsheets_solutions_use_classes: +\cs_new_protected:Npn \exsheets_declare_question_class:nn #1#2 { - % are we using classes? - \bool_if:NT \g__exsheets_use_classes_bool - { - % is the question to this solution an active one? - % get question number from ID - \prop_get:NoN \g__exsheets_questions_id_prop - { \g__exsheets_questions_current_id_tl } \l__exsheets_tmpa_tl - % get question class from number - \prop_get:NoN \g__exsheets_questions_class_prop - { \l__exsheets_tmpa_tl } \l__exsheets_tmpb_tl - % test if class is active - \prop_get:NoN \g__exsheets_classes_active_prop - { \l__exsheets_tmpb_tl } \l__exsheets_tmpc_tl - \tl_if_eq:NNTF \l__exsheets_tmpc_tl \q_no_value - { \bool_set_false:N \l__exsheets_solutions_use_bool } - { \bool_set_true:N \l__exsheets_solutions_use_bool } - } + \prop_if_in:NnTF \l__exsheets_class_prop { #2 } + {} + { \exsheets_new_question_class:nn { #1 } { #2 } } } -\cs_new_nopar:Npn \__exsheets_solutions_use_topics: +\NewDocumentCommand \DeclareQuestionClass { mm } { - % are we using topics? - \bool_if:NTF \g__exsheets_use_topics_bool - { - % is the question to this solution an active one? - % get question number from ID - \prop_get:NoN \g__exsheets_questions_id_prop - { \g__exsheets_questions_current_id_tl } \l__exsheets_tmpa_tl - % get question topic from number - \prop_get:NoN \g__exsheets_questions_topic_prop - { \l__exsheets_tmpa_tl } \l__exsheets_tmpb_tl - % test if topic is active - \prop_get:NoN \g__exsheets_topics_active_prop - { \l__exsheets_tmpb_tl } \l__exsheets_tmpc_tl - \tl_if_eq:NNT \l__exsheets_tmpc_tl \q_no_value - { \bool_set_false:N \l__exsheets_solutions_use_bool } - } - { - \bool_if:NF \g__exsheets_use_classes_bool - { \bool_set_true:N \l__exsheets_solutions_use_bool } - } + \exsheets_declare_question_class:nn { #1 } { #2 } +% \exsheets_declare_question_property:n { #1 } } +\@onlypreamble \DeclareQuestionClass % ---------------------------------------------------------------------------- % die 'question' Umgebung @@ -957,7 +904,7 @@ \bool_new:N \l__exsheets_points_not_given_bool -\cs_new:Npn \__exsheets_read_points:w #1+#2+#3 \q_stop +\cs_new_protected:Npn \__exsheets_read_points:w #1+#2+#3 \q_stop { \tl_if_blank:nTF { #1 } { \fp_zero:N \l__exsheets_question_points_fp } @@ -1071,21 +1018,37 @@ } % Auswahl der Frage: \__exsheets_select_question:V \g__exsheets_questions_current_id_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { + \use:c { __exsheets_questions_use_##1: } + } \bool_if:nT { \g__exsheets_questions_use_bool && !\l__exsheets_questions_deactivate_bool } { - \__exsheets_questions_use_classes: - \__exsheets_questions_use_topics: - \bool_if:nT + \tl_clear:N \l__exsheets_step_counter_tl + % das ist etwas mühsam: abhängig von der Nutzung der verschiedenen + % Gruppierungsmöglichkeiten muss der Counter erhöht werden: + \prop_map_inline:Nn \l__exsheets_class_prop { - ( \l__exsheets_class_active_bool && \l__exsheets_topic_active_bool ) || - ( \l__exsheets_class_active_bool && !\g__exsheets_use_topics_bool ) || - ( !\g__exsheets_use_classes_bool && \l__exsheets_topic_active_bool ) || - ( !\g__exsheets_use_classes_bool && !\g__exsheets_use_topics_bool ) + \use:c { __exsheets_questions_use_##1: } + \bool_if:nTF + { + ( + \l__exsheets_use_this_question_bool + && + \bool_if_p:c { l__exsheets_##2_active_bool } + ) + || + ! \bool_if_p:c { g__exsheets_use_##1_bool } + } + { \tl_put_right:Nn \l__exsheets_step_counter_tl { y } } + { \tl_put_right:Nn \l__exsheets_step_counter_tl { n } } } + % erhöhe jetzt, wenn kein Nein dabei war: + \tl_if_in:NnF \l__exsheets_step_counter_tl { n } { \refstepcounter{question} } \__exsheets_get_sectioning_numbers: \bool_if:nT @@ -1105,7 +1068,6 @@ } \bool_if:NT \l__exsheets_questions_print_bool { -% \exsheets_questions_debug: \bool_if:NTF \l__exsheets_exam_bool { \tl_set_eq:NN \l__exsheets_title_tl \l__exsheets_questions_name_tl } { \tl_set_eq:NN \l__exsheets_title_tl \l__exsheets_exsheets_name_tl } @@ -1127,57 +1089,40 @@ \cs_new_protected:Npn \exsheets@save@number #1#2 { \expandafter\global\expandafter\edef\csname exsheets@question@#1\endcsname{#2} } -\cs_new:Npn \__exsheets_save_number_in:N #1 +\cs_new_protected:Npn \__exsheets_save_number_in_aux_x:Nnn #1#2#3 + { + \prop_gput:Nfx #1 { #2 } { #3 } + \iow_now:Nx \@auxout { \exsheets@save@number { #2 } { #3 } } + } +\cs_generate_variant:Nn \prop_get:NnNTF { Nx } + +\cs_new_protected:Npn \__exsheets_save_number_in:N #1 { \bool_if:NTF \l__exsheets_print_number_bool { \cs_if_exist:NTF \thechapter { - \prop_gput:Nfx #1 + \__exsheets_save_number_in_aux_x:Nnn #1 { \int_use:N \g__exsheets_questions_id_int } { \arabic{chapter}-\arabic{section}-\arabic{question} } - \iow_now:Nx \@auxout - { - \exsheets@save@number - { \g__exsheets_questions_current_id_tl } - { \arabic{chapter}-\arabic{section}-\arabic{question} } - } } { - \prop_gput:Nfx #1 + \__exsheets_save_number_in_aux_x:Nnn #1 { \int_use:N \g__exsheets_questions_id_int } { -\arabic{section}-\arabic{question} } - \iow_now:Nx \@auxout - { - \exsheets@save@number - { \g__exsheets_questions_current_id_tl } - { -\arabic{section}-\arabic{question} } - } } } { \cs_if_exist:NTF \thechapter { - \prop_gput:Nfx #1 + \__exsheets_save_number_in_aux_x:Nnn #1 { \int_use:N \g__exsheets_questions_id_int } { @@@\arabic{chapter}-\arabic{section}-\arabic{question} } - \iow_now:Nx \@auxout - { - \exsheets@save@number - { \g__exsheets_questions_current_id_tl } - { @@@\arabic{chapter}-\arabic{section}-\arabic{question} } - } } { - \prop_gput:Nfx #1 + \__exsheets_save_number_in_aux_x:Nnn #1 { \int_use:N \g__exsheets_questions_id_int } { @@@-\arabic{section}-\arabic{question} } - \iow_now:Nx \@auxout - { - \exsheets@save@number - { \g__exsheets_questions_current_id_tl } - { @@@-\arabic{section}-\arabic{question} } - } } } } @@ -1197,9 +1142,16 @@ \cs_generate_variant:Nn \__exsheets_restore_number_from_and_do:Nnn { NV } \NewDocumentCommand \QuestionNumber { m } - { \exsheets_question_number:c { exsheets@question@#1 } } + { \exsheets_question_number:n { #1 } } -\cs_new:Npn \exsheets_question_number:N #1 +\cs_new_protected:Npn \exsheets_question_number:n #1 + { + \prop_get:NnNTF \g__exsheets_questions_id_prop { #1 } \l__exsheets_tmpa_tl + { \__exsheets_question_number:c { exsheets@question@\l__exsheets_tmpa_tl } } + { \textbf{??} } + } + +\cs_new:Npn \__exsheets_question_number:N #1 { \cs_if_exist:NTF #1 { @@ -1208,9 +1160,9 @@ } { \textbf{??} } } -\cs_generate_variant:Nn \exsheets_question_number:N { c } +\cs_generate_variant:Nn \__exsheets_question_number:N { c } -\cs_new:Npn \__exsheets_get_question_number:w #1-#2-#3 \q_stop +\cs_new_protected:Npn \__exsheets_get_question_number:w #1-#2-#3 \q_stop { \cs_if_exist:NT \thechapter { \int_set:Nn \l__exsheets_counter_ch_int { #1 } } @@ -1262,12 +1214,6 @@ print .default:n = true , ID .tl_set:N = \l__exsheets_questions_id_tl , label .tl_set:N = \l__exsheets_questions_label_tl , - class .code:n = - \bool_set_true:N \l__exsheets_questions_class_bool - \tl_set:Nn \l__exsheets_questions_class_tl { #1 } , - topic .code:n = - \bool_set_true:N \l__exsheets_questions_topic_bool - \tl_set:Nn \l__exsheets_questions_topic_tl { #1 } , use .choice: , use / true .code:n = \bool_gset_true:N \g__exsheets_questions_use_bool @@ -1281,31 +1227,18 @@ % ---------------------------------------------------------------------------- % using ``metadata'': -\cs_new:Npn \__exsheets_declare_question_property:n #1 +\cs_new_protected:Npn \exsheets_declare_question_property:n #1 { \prop_new:c { g__exsheets_question_property_#1_prop } \keys_define:nn { question / meta } { #1 .code:n = \__exsheets_question_set_property:nn { #1 } { ##1 } } } -\cs_new_eq:NN \exsheets_declare_question_property:n - \__exsheets_declare_question_property:n - \NewDocumentCommand \DeclareQuestionProperty { m } { \exsheets_declare_question_property:n { #1 } } -\@onlypreamble\DeclareQuestionProperty - -\DeclareQuestionProperty{points} -\bool_if:NT \l__exsheets_auto_label_bool - { - \DeclareQuestionProperty{ref} - \DeclareQuestionProperty{pageref} - } +\@onlypreamble \DeclareQuestionProperty -\NewDocumentCommand \SetQuestionProperties { m } - { \exsheets_set_question_properties:n { #1 } } - -\cs_new:Npn \__exsheets_set_question_properties:n #1 +\cs_new_protected:Npn \exsheets_set_question_properties:n #1 { \@bsphack \bool_if:NTF \l__exsheets_inside_question_bool @@ -1317,10 +1250,10 @@ \@esphack } -\cs_new_eq:NN \exsheets_set_question_properties:n - \__exsheets_set_question_properties:n +\NewDocumentCommand \SetQuestionProperties { m } + { \exsheets_set_question_properties:n { #1 } } -\cs_new:Npn \__exsheets_question_set_property:nn #1#2 +\cs_new_protected:Npn \__exsheets_question_set_property:nn #1#2 { \prop_gput:cVn { g__exsheets_question_property_#1_prop } \g__exsheets_questions_current_id_tl { #2 } @@ -1336,7 +1269,7 @@ } \int_new:N \g__exsheets_tmpa_int -\cs_new:Npn \ForEachQuestion #1 +\cs_new_protected:Npn \ForEachQuestion #1 { \int_gzero:N \g__exsheets_tmpa_int \prop_map_inline:Nn \g__exsheets_questions_used_prop @@ -1359,23 +1292,47 @@ \colorlet { exsheetsdebugcolor } { yellow } +\cs_new:Npn \exsheets_debug_box:nn #1#2 + { + \exsheets_par: + \noindent + \group_begin: + \normalfont\normalsize\normalcolor + \colorbox { exsheetsdebugcolor } + { \parbox { \dim_eval:n { #1 - 2 \fboxsep } } { #2 } } + \group_end: + \exsheets_par: + } + +\cs_new:Npn \__exsheets_list_comma: {} + \cs_new_nopar:Npn \exsheets_questions_debug: { - \bool_if:nT { \l__exsheets_questions_debug_bool && \l__exsheets_inside_question_bool } + \bool_if:nT + { \l__exsheets_questions_debug_bool && \l__exsheets_inside_question_bool } { - \colorbox { exsheetsdebugcolor } + \exsheets_debug_box:nn { \linewidth } { - \group_begin: - \normalfont\normalsize\normalcolor - ID:~ - \tl_if_blank:VTF \l__exsheets_questions_id_tl - { \int_use:N \g__exsheets_questions_id_int } - { \tl_use:N \l__exsheets_questions_id_tl } - \bool_if:NT \l__exsheets_questions_class_bool - { ,~CLASS:~ \tl_use:N \l__exsheets_questions_class_tl } - \bool_if:NT \l__exsheets_questions_topic_bool - { ,~TOPIC:~ \tl_use:N \l__exsheets_questions_topic_tl } - \group_end: + \fbox + { + ID:~ + \textit + { + \tl_if_blank:VTF \l__exsheets_questions_id_tl + { \int_use:N \g__exsheets_questions_id_int } + { \tl_use:N \l__exsheets_questions_id_tl } + } + } + \cs_set_protected:Npn \__exsheets_list_comma: + { ~ \cs_set:Npn \__exsheets_list_comma: { ,~ } } + \prop_map_inline:Nn \l__exsheets_class_prop + { + \bool_if:cT { l__exsheets_questions_##2_bool } + { + \__exsheets_list_comma: ##2:~ + \textit { \tl_use:c { l__exsheets_questions_##2_tl } } + } + } } } } @@ -1393,22 +1350,21 @@ \bool_set_true:N \l__exsheets_include_all_bool \prop_new:N \g__exsheets_selected_questions_prop \clist_new:N \l__exsheets_include_id_clist +\clist_new:N \l__exsheets_exclude_id_clist +\clist_new:N \questionsincludedlast \int_new:N \l__exsheets_include_random_int \int_zero:N \l__exsheets_include_random_int \cs_new:Npn \exsheets_file_input_if_exist:n #1 { \file_if_exist:nT { #1 } { \file_input:n { #1 } } } -\cs_if_exist:NF \prop_length:N +\cs_new_protected:Npn \exsheets_prop_count:N #1 { - \cs_new:Npn \prop_length:N #1 - { - \prop_length:NN #1 \l_tmpa_int - \int_use:N \l_tmpa_int - } + \__exsheets_prop_count:NN #1 \l_tmpa_int + \int_use:N \l_tmpa_int } -\cs_new:Npn \prop_length:NN #1#2 +\cs_new_protected:Npn \__exsheets_prop_count:NN #1#2 { \int_zero:N #2 \prop_map_inline:Nn #1 @@ -1424,37 +1380,57 @@ \group_end: } -\cs_new:Npn \exsheets_include_questions:n #1 +\cs_new_protected:Npn \exsheets_include_questions:n #1 { \bool_set_true:N \l__exsheets_select_questions_bool \seq_set_split:Nnn \l__exsheets_tmpa_seq { , } { #1 } \seq_map_inline:Nn \l__exsheets_tmpa_seq { \bool_set_true:N \l__exsheets_questions_deactivate_bool - \int_set_eq:NN \l__exsheets_tmpc_int \g__exsheets_questions_id_int + \int_set_eq:NN \l__exsheets_tmpc_int \g__exsheets_questions_id_int \exsheets_file_input_if_exist:n { ##1 } - \prop_length:NN + \__exsheets_prop_count:NN \g__exsheets_selected_questions_prop \l__exsheets_tmpa_int \bool_if:NT \l__exsheets_questions_debug_bool { - \colorbox { exsheetsdebugcolor } + \exsheets_debug_box:nn + { \linewidth } { The~file~ ` \texttt { \tl_to_str:n { ##1 } } ' ~contains~ - \prop_length:N \g__exsheets_selected_questions_prop \c_space_tl - questions. + \exsheets_prop_count:N \g__exsheets_selected_questions_prop + \c_space_tl questions~with~the~following~IDs:\par + \cs_set_protected:Npn \__exsheets_list_comma: + { \cs_set:Npn \__exsheets_list_comma: { ,~ } } + \prop_map_inline:Nn \g__exsheets_selected_questions_prop + { \__exsheets_list_comma: ####2 } } - \exsheets_par: } \bool_set_false:N \l__exsheets_questions_deactivate_bool - \int_set_eq:NN \l__exsheets_tmpd_int \g__exsheets_questions_id_int - \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpc_int + \int_set_eq:NN \l__exsheets_tmpd_int \g__exsheets_questions_id_int + \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpc_int \__exsheets_select_question_random:n { ##1 } + \clist_gclear:N \questionsincludedlast + \bool_if:nTF + { \l__exsheets_include_random_bool || \l__exsheets_include_by_id_bool } + { + \clist_gset_eq:NN + \questionsincludedlast + \l__exsheets_include_id_clist + } + { + \prop_map_inline:Nn \g__exsheets_selected_questions_prop + { + \clist_if_in:NnF \l__exsheets_exclude_id_clist { ####2 } + { \clist_gput_right:Nn \questionsincludedlast { ####2 } } + } + } \exsheets_file_input_if_exist:n { ##1 } - \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpd_int - \prop_gclear:N \g__exsheets_selected_questions_prop - \clist_clear:N \l__exsheets_include_id_clist - \int_gzero:N \g__exsheets_selection_number_int + \int_gset_eq:NN \g__exsheets_questions_id_int \l__exsheets_tmpd_int + \prop_gclear:N \g__exsheets_selected_questions_prop + \clist_clear:N \l__exsheets_include_id_clist + \clist_clear:N \l__exsheets_exclude_id_clist + \int_gzero:N \g__exsheets_selection_number_int } \bool_set_false:N \l__exsheets_select_questions_bool } @@ -1463,22 +1439,31 @@ % - IDs=<list of IDs> % - all=true|false % default when no option is given % - random=<num> +% - exclude=<list of IDs> \keys_define:nn { exsheets / include } { - all .bool_set:N = \l__exsheets_include_all_bool , - IDs .code:n = + all .bool_set:N = \l__exsheets_include_all_bool , + IDs .code:n = \bool_set_false:N \l__exsheets_include_all_bool \bool_set_false:N \l__exsheets_include_random_bool + \bool_set_true:N \l__exsheets_include_by_id_bool \clist_set:Nn \l__exsheets_include_id_clist { #1 } , - random .code:n = + % the following option does _not_ set \l__exsheets_include_random_bool + % so it can be combined with the `random' option: + exclude .code:n = + \bool_set_false:N \l__exsheets_include_all_bool + \bool_set_false:N \l__exsheets_include_by_id_bool + \clist_set:Nn \l__exsheets_exclude_id_clist { #1 } , + random .code:n = \bool_set_false:N \l__exsheets_include_all_bool \bool_set_true:N \l__exsheets_include_random_bool + \bool_set_false:N \l__exsheets_include_by_id_bool \int_set:Nn \l__exsheets_include_random_int { #1 } } \int_new:N \g__exsheets_selection_number_int -\cs_new:Npn \__exsheets_select_question:n #1 +\cs_new_protected:Npn \__exsheets_select_question:n #1 { \bool_if:NT \l__exsheets_select_questions_bool { @@ -1506,8 +1491,7 @@ \l__exsheets_tmpa_int \g__exsheets_selection_number_int } - \exp_args:NNx - \prop_get:NnN \g__exsheets_selected_questions_prop + \prop_get:NxN \g__exsheets_selected_questions_prop { \int_use:N \l__exsheets_tmpa_int } \l__exsheets_tmpa_tl \bool_if:NF \l__exsheets_include_all_bool @@ -1516,46 +1500,124 @@ } } \cs_generate_variant:Nn \__exsheets_select_question:n { V } +\cs_generate_variant:Nn \prop_get:NnN { Nx } -\cs_new:Npn \__exsheets_select_question_by_id:n #1 +\cs_new_protected:Npn \__exsheets_select_question_by_id:n #1 { - \clist_if_in:NnTF - \l__exsheets_include_id_clist - { #1 } - { \bool_gset_true:N \g__exsheets_questions_use_bool } - { \bool_gset_false:N \g__exsheets_questions_use_bool } + \bool_if:nTF + { \l__exsheets_include_by_id_bool || \l__exsheets_include_random_bool } + {% parsing list of included IDs + \clist_if_in:NnTF + \l__exsheets_include_id_clist + { #1 } + { \bool_gset_true:N \g__exsheets_questions_use_bool } + { \bool_gset_false:N \g__exsheets_questions_use_bool } + } + {% parsing list of excluded IDs + \clist_if_in:NnTF + \l__exsheets_exclude_id_clist + { #1 } + { \bool_gset_false:N \g__exsheets_questions_use_bool } + { \bool_gset_true:N \g__exsheets_questions_use_bool } + } } \cs_generate_variant:Nn \__exsheets_select_question_by_id:n { V } -% TODO: don't select questions whose topics or classes aren't chosen -\cs_new:Npn \__exsheets_select_question_random:n #1 +\tl_new:N \l__exsheets_include_id_tl +\bool_new:N \l__exsheets_use_selection_bool +% TODO: poor efficiency -- there should be no need to map through +% \l__exsheets_class_prop *two* times +\cs_new_protected:Npn \__exsheets_select_question_random:n #1 { \bool_if:NT \l__exsheets_include_random_bool { - \prop_length:NN \g__exsheets_selected_questions_prop \l__exsheets_tmpa_int - \int_compare:nTF { \l__exsheets_include_random_int > \l__exsheets_tmpa_int } + % number of question in file: + \__exsheets_prop_count:NN + \g__exsheets_selected_questions_prop + \l__exsheets_tmpa_int + % number of selectable questions in file: + \int_zero:N \l__exsheets_tmpb_int + \prop_map_inline:Nn \g__exsheets_selected_questions_prop + { + \prop_map_inline:Nn \l__exsheets_class_prop + { + \bool_if:cT { g__exsheets_use_####1_bool } + { + \bool_set_true:N \l__exsheets_use_selection_bool + \prop_get:cnNT { g__exsheets_questions_####2_prop } { ##1 } + \l__exsheets_tmpa_tl + { + \prop_if_in:cVT { g__exsheets_####1_active_prop } + \l__exsheets_tmpa_tl + { \int_incr:N \l__exsheets_tmpb_int } + } + } + } + } + \int_compare:nTF { \l__exsheets_include_random_int >= \l__exsheets_tmpa_int } { - \msg_warning:nnxxx { exsheets } { random } + % not enough questions available: + \msg_warning:nnxxx { exsheets } { random-file } { \int_use:N \l__exsheets_include_random_int } { #1 } { \int_use:N \l__exsheets_tmpa_int } \bool_set_true:N \l__exsheets_include_all_bool } { - \int_zero:N \l__exsheets_tmpb_int - \int_do_while:nn { \l__exsheets_tmpb_int < \l__exsheets_include_random_int } + \bool_if:nTF { - \pgfmathparse { random(\int_use:N \l__exsheets_tmpa_int) } - \tl_set_eq:NN \l__exsheets_tmpa_tl \pgfmathresult - \prop_get:NVN \g__exsheets_selected_questions_prop - \l__exsheets_tmpa_tl - \l__exsheets_tmpb_tl - \clist_if_in:NVF \l__exsheets_include_id_clist \l__exsheets_tmpb_tl + \int_compare_p:n + { \l__exsheets_include_random_int >= \l__exsheets_tmpb_int } + && + \l__exsheets_use_selection_bool + } + { + % not enough questions selectable: + \msg_warning:nnxxxx { exsheets } { random-selectable } + { \int_use:N \l__exsheets_include_random_int } + { #1 } + { \int_use:N \l__exsheets_tmpa_int } + { \int_use:N \l__exsheets_tmpb_int } + \bool_set_true:N \l__exsheets_include_all_bool + } + { + \int_zero:N \l__exsheets_tmpb_int + \int_do_while:nn + { \l__exsheets_tmpb_int < \l__exsheets_include_random_int } { - \clist_put_right:NV - \l__exsheets_include_id_clist + \pgfmathparse { random(\int_use:N \l__exsheets_tmpa_int) } + \tl_set_eq:NN \l__exsheets_tmpa_tl \pgfmathresult + \prop_get:NVN \g__exsheets_selected_questions_prop + \l__exsheets_tmpa_tl \l__exsheets_tmpb_tl - \int_incr:N \l__exsheets_tmpb_int + \clist_if_in:NVF \l__exsheets_include_id_clist \l__exsheets_tmpb_tl + { + \tl_clear:N \l__exsheets_include_id_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { + \prop_get:cVNT { g__exsheets_questions_##2_prop } + \l__exsheets_tmpa_tl \l__exsheets_tmpc_tl + { + \bool_if:cT { g__exsheets_use_##1_bool } + { + \prop_if_in:cVTF { g__exsheets_##1_active_prop } + \l__exsheets_tmpc_tl + { \tl_put_right:Nn \l__exsheets_include_id_tl { y } } + { \tl_put_right:Nn \l__exsheets_include_id_tl { n } } + } + } + } + \tl_if_in:NnF \l__exsheets_include_id_tl { n } + { + \clist_if_in:NVF \l__exsheets_exclude_id_clist \l__exsheets_tmpb_tl + { + \clist_put_right:NV + \l__exsheets_include_id_clist + \l__exsheets_tmpb_tl + \int_incr:N \l__exsheets_tmpb_int + } + } + } } } } @@ -1592,7 +1654,7 @@ \tl_new:N \l__exsheets_solutions_name_tl \tl_set:Nn \l__exsheets_solutions_name_tl { Solution } -\cs_new:Npn \__exsheets_save_solution:n #1 +\cs_new_protected:Npn \__exsheets_save_solution:n #1 { % save for later use \bool_if:NTF \l__exsheets_include_all_bool @@ -1630,20 +1692,38 @@ \NewEnviron { __exsheets_solution_internal: } { - \bool_if:nT { \g__exsheets_questions_use_bool && \l__exsheets_solutions_use_bool } - { -% \cspreto { BODY } { \ifhmode \fi }% what's that good for? - \__exsheets_save_solution:V \BODY - } + \bool_if:nT + { \g__exsheets_questions_use_bool && \l__exsheets_solutions_use_bool } + { \__exsheets_save_solution:V \BODY } } \bool_new:N \l__exsheets_inside_solution_bool \bool_set_false:N \l__exsheets_inside_solution_bool +\tl_new:N \l__exsheets_use_solution_tl + \NewDocumentEnvironment { __exsheets_solution: } { g } { - \__exsheets_solutions_use_classes: - \__exsheets_solutions_use_topics: + \tl_clear:N \l__exsheets_use_solution_tl + \prop_map_inline:Nn \l__exsheets_class_prop + { + \use:c { __exsheets_solutions_use_##1: } + \bool_if:nTF + { + ( + \l__exsheets_solutions_use_bool + && + \bool_if_p:c { l__exsheets_##2_active_bool } + ) + || + ! \bool_if_p:c { g__exsheets_use_##1_bool } + } + { \tl_put_right:Nn \l__exsheets_use_solution_tl { y } } + { \tl_put_right:Nn \l__exsheets_use_solution_tl { n } } + } + % verwende, wenn ein Ja dabei war: + \tl_if_in:NnT \l__exsheets_use_solution_tl { y } + { \bool_set_true:N \l__exsheets_solutions_use_bool } \bool_if:NT \l__exsheets_questions_deactivate_bool { \bool_set_false:N \l__exsheets_solutions_use_bool } \bool_if:NT \l__exsheets_solutions_use_bool @@ -1687,7 +1767,7 @@ % ---------------------------------------------------------------------------- % print solutions: % save section / chapter counter: -\cs_new:Npn \__exsheets_exlabel:n #1 +\cs_new_protected:Npn \__exsheets_exlabel:n #1 { \@bsphack \iow_now:Nx \@auxout @@ -1739,7 +1819,7 @@ { \exsheets_print_solutions:n { #1 } } % internal command: -\cs_new:Npn \exsheets_print_solutions:n #1 +\cs_new_protected:Npn \exsheets_print_solutions:n #1 { \group_begin: \bool_set_true:N \l__exsheets_solutions_print_bool @@ -1767,7 +1847,7 @@ \int_new:N \l__exsheets_counter_sec_int \int_new:N \l__exsheets_counter_qu_int -\cs_new:Npn \__exsheets_get_sectioning_numbers: +\cs_new_protected:Npn \__exsheets_get_sectioning_numbers: { \cs_if_exist:NT \chapter { \int_set:Nn \l__exsheets_counter_ch_int { \arabic{chapter} } } @@ -1821,7 +1901,7 @@ } } -\cs_new:Npn \__exsheets_print_solutions_by_section:w #1-#2-#3 \q_stop +\cs_new_protected:Npn \__exsheets_print_solutions_by_section:w #1-#2-#3 \q_stop { % wenn #3=-, dann range-Input \tl_if_eq:nnTF { #3 } { - } @@ -1879,7 +1959,7 @@ } } -\cs_new:Npn \__exsheets_print_solutions_by_chapter:w #1-#2-#3 \q_stop +\cs_new_protected:Npn \__exsheets_print_solutions_by_chapter:w #1-#2-#3 \q_stop { % wenn #3=-, dann range-Input \tl_if_eq:nnTF { #3 } { - } @@ -1924,7 +2004,7 @@ \__exsheets_print_solutions_all:nn } -\cs_new:Npn \__exsheets_print_solutions_all:nn #1#2 +\cs_new_protected:Npn \__exsheets_print_solutions_all:nn #1#2 { \__exsheets_read_number:w #2 \q_stop \prop_get:NnNT \g__exsheets_solutions_names_prop @@ -1953,7 +2033,7 @@ % print by ID: \seq_new:N \l__exsheets_solutions_byID_seq -\cs_new:Npn \exsheets_print_solutions_byID:n #1 +\cs_new_protected:Npn \exsheets_print_solutions_byID:n #1 { \seq_set_split:Nnn \l__exsheets_solutions_byID_seq { , } { #1 } \seq_clear:N \l__exsheets_tmpa_seq @@ -2089,13 +2169,11 @@ \NewDocumentCommand \NewQuSolPair { mO{}mO{} } { \__exsheets_new_qu_sol_pair:nnnn { #1 } { #2 } { #3 } { #4 } } -\@onlypreamble\NewQuSolPair +\@onlypreamble \NewQuSolPair \NewDocumentCommand \RenewQuSolPair { mO{}mO{} } { \__exsheets_renew_qu_sol_pair:nnnn { #1 } { #2 } { #3 } { #4 } } -\@onlypreamble\RenewQuSolPair - -\NewQuSolPair { question } { solution } +\@onlypreamble \RenewQuSolPair % ---------------------------------------------------------------------------- % the `tasks' list @@ -2163,7 +2241,7 @@ \group_end: } -\cs_new:Npn \exsheets_blank:n #1 +\cs_new_protected:Npn \exsheets_blank:n #1 { \box_clear:N \l__exsheets_blank_box \hbox_set:Nn \l__exsheets_blank_box { #1 } @@ -2179,7 +2257,7 @@ } } -\cs_new:Npn \__exsheets_blank_skip:N #1 +\cs_new_protected:Npn \__exsheets_blank_skip:N #1 { \bool_if:NTF \l__exsheets_blank_width_bool { \dim_set:Nn \l__exsheets_tmpa_dim { #1 } } @@ -2237,7 +2315,7 @@ % ---------------------------------------------------------------------------- % \examspace % insert space for a student to answer a question -\cs_new:Npn \__exsheets_examspace:nn #1#2 +\cs_new_protected:Npn \__exsheets_examspace:nn #1#2 { \par \tex_penalty:D -100 \scan_stop: \group_begin: @@ -2268,6 +2346,23 @@ } % ---------------------------------------------------------------------------- +% default definitions: +% question / solution pair: +\NewQuSolPair{question}{solution} + +% properties: +\DeclareQuestionProperty{points} +\bool_if:NT \l__exsheets_auto_label_bool + { + \DeclareQuestionProperty{ref} + \DeclareQuestionProperty{pageref} + } + +% classs: +\DeclareQuestionClass{class}{classes} +\DeclareQuestionClass{topic}{topics} + +% ---------------------------------------------------------------------------- % Sprachanpassungen \file_if_exist:nT { translations.sty } { @@ -2330,7 +2425,7 @@ \iow_now:Nx \@auxout { \exp_not:N \exsheets@sum@of@points - { \fp_eval:n { \g__exsheets_points_sum_fp } } + { \fp_eval:n { \g__exsheets_points_sum_fp } }^^J \exp_not:N \exsheets@sum@of@bonus { \fp_eval:n { \g__exsheets_bonus_sum_fp } } } @@ -2432,9 +2527,24 @@ HISTORY: 2013/01/21 v0.7a - added option `auto-label' and questions key `label', also added question properties `ref' and `pageref' 2013/02/17 v0.7b - bug fix: question selection by ID now works again - +2013/03/?? v0.8 - \prop_length => \exsheets_prop_count + - define unexpandable internal commands protected + - translations basic dictionaries for English, German, + French and Spanish + - translations: new command \DeclareDictTranslation + - new \includequestions option `exclude' + - new way of handling the `class' of questions: + instead of hard-coded `classes' and `topics' + individual groups like e.g. `difficulties' can be + chosen; `classes' and `topics' are still provided for + backwards compatibility; this introduces the new + command \DeclareQuestionClass + - minor changes to the debugging information layout + - bug fix in number saving mechanism + - \includequestions[random=<num>] now obeys class + as done with \SetupExSheets{use-topics={foo,bar}} + - new macro \questionsincludedlast %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TODO: - points/decimal-marker, points/frac (?), points/format (?,im interface) -- rewrite random selection |