Macro defining macro defining global macro (similar to `author` or `title` fields)












5















I have already seen these posts Macro defining macro and
Macros that define other macros, which also define other macros but unfortunately I didn't manege to figure it out how to correct my attempt to the problem.
I want to create a macro which will produce macro + global macro with @ in front of macro name, like in the following example:



 defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}
makeatletter
@Bob % it will display `My name is Bob'
Bob{Name: Bob}
@Bob % it will display `Name: Bob'
makeatother


So this works. However:



 defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


doesn't work. I got Undefined control sequence. with @Alice. I have checked Alice and Bob with show command:



> Bob=macro:
#1->gdef @Bob {#1}.
l.20 showBob
> Alice=macro:
#1->gdef @Alice {#1}.
l.21 showAlice


They have exactly the same structure. What did I miss?
MWE:



documentclass[preview]{standalone}
makeatletter

defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}

begin{document}
%@Alice % Undefined control sequence.
@Bob
Bob{No my name is Alice}

@Bob
showBob
showAlice
makeatother
end{document}









share|improve this question




















  • 1





    Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

    – moewe
    Jan 27 at 11:00













  • Thank you very much, I don't know why I missed it.

    – andywiecko
    Jan 27 at 11:05
















5















I have already seen these posts Macro defining macro and
Macros that define other macros, which also define other macros but unfortunately I didn't manege to figure it out how to correct my attempt to the problem.
I want to create a macro which will produce macro + global macro with @ in front of macro name, like in the following example:



 defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}
makeatletter
@Bob % it will display `My name is Bob'
Bob{Name: Bob}
@Bob % it will display `Name: Bob'
makeatother


So this works. However:



 defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


doesn't work. I got Undefined control sequence. with @Alice. I have checked Alice and Bob with show command:



> Bob=macro:
#1->gdef @Bob {#1}.
l.20 showBob
> Alice=macro:
#1->gdef @Alice {#1}.
l.21 showAlice


They have exactly the same structure. What did I miss?
MWE:



documentclass[preview]{standalone}
makeatletter

defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}

begin{document}
%@Alice % Undefined control sequence.
@Bob
Bob{No my name is Alice}

@Bob
showBob
showAlice
makeatother
end{document}









share|improve this question




















  • 1





    Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

    – moewe
    Jan 27 at 11:00













  • Thank you very much, I don't know why I missed it.

    – andywiecko
    Jan 27 at 11:05














5












5








5








I have already seen these posts Macro defining macro and
Macros that define other macros, which also define other macros but unfortunately I didn't manege to figure it out how to correct my attempt to the problem.
I want to create a macro which will produce macro + global macro with @ in front of macro name, like in the following example:



 defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}
makeatletter
@Bob % it will display `My name is Bob'
Bob{Name: Bob}
@Bob % it will display `Name: Bob'
makeatother


So this works. However:



 defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


doesn't work. I got Undefined control sequence. with @Alice. I have checked Alice and Bob with show command:



> Bob=macro:
#1->gdef @Bob {#1}.
l.20 showBob
> Alice=macro:
#1->gdef @Alice {#1}.
l.21 showAlice


They have exactly the same structure. What did I miss?
MWE:



documentclass[preview]{standalone}
makeatletter

defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}

begin{document}
%@Alice % Undefined control sequence.
@Bob
Bob{No my name is Alice}

@Bob
showBob
showAlice
makeatother
end{document}









share|improve this question
















I have already seen these posts Macro defining macro and
Macros that define other macros, which also define other macros but unfortunately I didn't manege to figure it out how to correct my attempt to the problem.
I want to create a macro which will produce macro + global macro with @ in front of macro name, like in the following example:



 defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}
makeatletter
@Bob % it will display `My name is Bob'
Bob{Name: Bob}
@Bob % it will display `Name: Bob'
makeatother


So this works. However:



 defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


doesn't work. I got Undefined control sequence. with @Alice. I have checked Alice and Bob with show command:



> Bob=macro:
#1->gdef @Bob {#1}.
l.20 showBob
> Alice=macro:
#1->gdef @Alice {#1}.
l.21 showAlice


They have exactly the same structure. What did I miss?
MWE:



documentclass[preview]{standalone}
makeatletter

defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1 endcsname{##1}%
}%
}
DefineField{Alice}
Alice{My name is Alice}


defBob#1{gdef@Bob{#1}}
Bob{My name is Bob}

begin{document}
%@Alice % Undefined control sequence.
@Bob
Bob{No my name is Alice}

@Bob
showBob
showAlice
makeatother
end{document}






macros undefined






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 27 at 16:36









Martin Scharrer

202k46643820




202k46643820










asked Jan 27 at 10:31









andywieckoandywiecko

628




628








  • 1





    Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

    – moewe
    Jan 27 at 11:00













  • Thank you very much, I don't know why I missed it.

    – andywiecko
    Jan 27 at 11:05














  • 1





    Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

    – moewe
    Jan 27 at 11:00













  • Thank you very much, I don't know why I missed it.

    – andywiecko
    Jan 27 at 11:05








1




1





Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

– moewe
Jan 27 at 11:00







Remove the space after the #1 in gdefcsname @#1 endcsname{##1}%, it should be gdefcsname @#1endcsname{##1}%

– moewe
Jan 27 at 11:00















Thank you very much, I don't know why I missed it.

– andywiecko
Jan 27 at 11:05





Thank you very much, I don't know why I missed it.

– andywiecko
Jan 27 at 11:05










4 Answers
4






active

oldest

votes


















8














The definition of DefineField has a superfluous space in gdefcsname @#1 endcsname{##1}%, it should be



defDefineField#1{%
expandafteredefcsname #1endcsname##1{%
gdefcsname @#1endcsname{##1}%
}%
}


With the space you would define the command @Alice␣ (where represents a space) as can be verified by checking @Alice␣'s definition with



expandaftershowcsname @Alice endcsname


If we want to define @Alice we need to get rid of the space.





Note that the use of edef in DefineField can have unintended consequences, so you may want to consider going for the solution presented in Martin Scharrer's answer or egreg's answer.






share|improve this answer

































    6














    I would not use edef here but work with a second expandafter.



    The main problem here is that you have a space between #1 and endcsname, so you actually define @Alice<space>, which is possible with csname.



    Correct code is:



    defDefineField#1{%
    expandafterdefcsname #1endcsname##1{%
    expandaftergdefcsname @#1endcsname{##1}%
    }%
    }





    share|improve this answer































      6














      You're defining csname @Alice endcsname which results in a control sequence token having a trailing space in its name. The space after csname doesn't find its way during tokenization, because it follows a control word, but the space between #1 and endcsname will not be removed.



      Your usage of edef is quite problematic as well: if you mistakenly use DefineField{Alice} twice,



      DefineField{Alice}
      Alice{My name is Alice}
      showAlice

      DefineField{Alice}
      showAlice


      you'll get



      > Alice=macro:
      #1->gdef @Alice {#1}.

      > Alice=macro:
      #1->gdef My name is Alice{#1}.


      This can be cured by checking first if Alice is defined:



      defDefineField#1{%
      @ifundefined{#1}
      {% go on, it's undefined
      expandafteredefcsname #1endcsname##1{%
      gdefcsname @#1endcsname{##1}%
      }%
      }
      {% ignore the redefinition
      PackageWarning{andywiecko}{%
      expandafternoexpandcsname #1endcsname already defined%
      }%
      }%
      }


      A simpler approach with xparse and expl3:



      documentclass{article}
      usepackage{xparse}

      ExplSyntaxOn

      NewDocumentCommand{DefineField}{m}
      {
      cs_new_protected:cpn { #1 } ##1
      {
      cs_new_protected:cpn { @#1 } { ##1 } % or `cs_new:cpn
      }
      }

      ExplSyntaxOff

      DefineField{Alice}
      Alice{My name is Alice}

      expandaftershowcsname @Aliceendcsname


      This will produce a standard error if DefineField{Alice} is used twice or if you try doing DefineField{box}; the code will show



      > @Alice=protectedlong macro:
      ->My name is Alice.


      You may want to use cs_new:cpn in the second instance, depending on what expansion context you will use the @Alice macro.





      A more proper expl3 interface, where instead of defining @foo macros you do UseField{foo} when needed. A way to override already existing fields is provided.



      documentclass{article}
      usepackage{xparse}

      ExplSyntaxOn

      prop_new:N g_andywiecko_fields_prop
      cs_new:Nn andywiecko_define_field:nn
      {
      prop_gput:Nnn g_andywiecko_fields_prop { #1 } { #2 }
      }

      NewDocumentCommand{DefineField}{sm}
      {
      cs_set_protected:Nn __andywiecko:n
      {
      andywiecko_define_field:nn { #2 } { ##1 }
      }
      IfBooleanTF { #1 }
      {% override an existing definition
      cs_gset_eq:cN { #2 } __andywiecko:n
      }
      {% new field
      cs_new_eq:cN { #2 } __andywiecko:n
      }
      }

      NewExpandableDocumentCommand{UseField}{m}
      {
      prop_item:Nn g_andywiecko_fields_prop { #1 }
      }

      ExplSyntaxOff

      DefineField{author} % gives error

      DefineField*{author} % no error, use new interface

      DefineField{Alice}
      Alice{My name is Alice}

      DefineField{Alice} % gives error





      share|improve this answer


























      • Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

        – andywiecko
        Jan 27 at 11:49



















      1














      In the other answers the spurious space within the csname..endcsname-expression is already pointed out.



      In case you wish to avoid typing so many csname..endcsname-expressions, I can offer a macro name.



      name takes following tokens that are not nested in braces for its first argument and following tokens nested in braces for its second argument and applies csname..endcsname to its second argument.

      The tokens that form the first argument can, e.g., be: globallongouterdef or newcommand or string or meaning or whatever.
      You can also leave the first argument empty.



      Examples:



      nameshow{foo} yields: showfoo



      namedef{foo}... yields: deffoo...



      namegloballongouterdef{foo}... yields: globallongouterdeffoo...



      namenewcommand{foo}... yields: newcommandfoo...



      name{foo}... yields: foo



      namenamegloballet{foo}={bar}

      yields:
      namegloballetfoo={bar}

      yields:
      globalletfoo=bar



      documentclass{article}

      newcommandUDExchange[2]{#2#1}
      newcommandname{}longdefname#1#{romannumeral0innername{#1}}%
      newcommandinnername[2]{%
      expandafterUDExchangeexpandafter{csname#2endcsname}{ #1}%
      }%

      makeatletter
      newcommandnovalueprovided{nfss@text{reset@fontbfseries??}}
      makeatother

      newcommandDefineField[2][novalueprovided]{%
      namenewcommand{#2}[1]{namegdef{@#2}{##1}}%
      namenewcommand{@#2}{}%
      name{#2}{#1}%
      }%

      newcommandUseField[1]{name{@#1}}%

      DefineField[initial value of field Alice]{Alice}

      DefineField{Bob}

      begin{document}

      {ttfrenchspacing
      namestring{Alice}: namemeaning{Alice}

      namestring{@Alice}: namemeaning{@Alice}

      namestring{Bob}: namemeaning{Bob}

      namestring{@Bob}: namemeaning{@Bob}

      verb|UseField{Alice}:| UseField{Alice}

      verb|UseField{Bob}:| UseField{Bob}
      }

      hrulefill

      Now the fields are changed:

      Alice{My name is Alice}

      Bob{My name is Bob}

      {ttfrenchspacing
      namestring{Alice}: namemeaning{Alice}

      namestring{@Alice}: namemeaning{@Alice}

      namestring{Bob}: namemeaning{Bob}

      namestring{@Bob}: namemeaning{@Bob}

      verb|UseField{Alice}:| UseField{Alice}

      verb|UseField{Bob}:| UseField{Bob}
      }

      end{document}


      If you provide more info about what you try to achieve in practice, an interface could be developed which also does better error-management.



      enter image description here






      share|improve this answer

























        Your Answer








        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "85"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f472068%2fmacro-defining-macro-defining-global-macro-similar-to-author-or-title-fie%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        8














        The definition of DefineField has a superfluous space in gdefcsname @#1 endcsname{##1}%, it should be



        defDefineField#1{%
        expandafteredefcsname #1endcsname##1{%
        gdefcsname @#1endcsname{##1}%
        }%
        }


        With the space you would define the command @Alice␣ (where represents a space) as can be verified by checking @Alice␣'s definition with



        expandaftershowcsname @Alice endcsname


        If we want to define @Alice we need to get rid of the space.





        Note that the use of edef in DefineField can have unintended consequences, so you may want to consider going for the solution presented in Martin Scharrer's answer or egreg's answer.






        share|improve this answer






























          8














          The definition of DefineField has a superfluous space in gdefcsname @#1 endcsname{##1}%, it should be



          defDefineField#1{%
          expandafteredefcsname #1endcsname##1{%
          gdefcsname @#1endcsname{##1}%
          }%
          }


          With the space you would define the command @Alice␣ (where represents a space) as can be verified by checking @Alice␣'s definition with



          expandaftershowcsname @Alice endcsname


          If we want to define @Alice we need to get rid of the space.





          Note that the use of edef in DefineField can have unintended consequences, so you may want to consider going for the solution presented in Martin Scharrer's answer or egreg's answer.






          share|improve this answer




























            8












            8








            8







            The definition of DefineField has a superfluous space in gdefcsname @#1 endcsname{##1}%, it should be



            defDefineField#1{%
            expandafteredefcsname #1endcsname##1{%
            gdefcsname @#1endcsname{##1}%
            }%
            }


            With the space you would define the command @Alice␣ (where represents a space) as can be verified by checking @Alice␣'s definition with



            expandaftershowcsname @Alice endcsname


            If we want to define @Alice we need to get rid of the space.





            Note that the use of edef in DefineField can have unintended consequences, so you may want to consider going for the solution presented in Martin Scharrer's answer or egreg's answer.






            share|improve this answer















            The definition of DefineField has a superfluous space in gdefcsname @#1 endcsname{##1}%, it should be



            defDefineField#1{%
            expandafteredefcsname #1endcsname##1{%
            gdefcsname @#1endcsname{##1}%
            }%
            }


            With the space you would define the command @Alice␣ (where represents a space) as can be verified by checking @Alice␣'s definition with



            expandaftershowcsname @Alice endcsname


            If we want to define @Alice we need to get rid of the space.





            Note that the use of edef in DefineField can have unintended consequences, so you may want to consider going for the solution presented in Martin Scharrer's answer or egreg's answer.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 27 at 11:56

























            answered Jan 27 at 11:04









            moewemoewe

            91.3k10114345




            91.3k10114345























                6














                I would not use edef here but work with a second expandafter.



                The main problem here is that you have a space between #1 and endcsname, so you actually define @Alice<space>, which is possible with csname.



                Correct code is:



                defDefineField#1{%
                expandafterdefcsname #1endcsname##1{%
                expandaftergdefcsname @#1endcsname{##1}%
                }%
                }





                share|improve this answer




























                  6














                  I would not use edef here but work with a second expandafter.



                  The main problem here is that you have a space between #1 and endcsname, so you actually define @Alice<space>, which is possible with csname.



                  Correct code is:



                  defDefineField#1{%
                  expandafterdefcsname #1endcsname##1{%
                  expandaftergdefcsname @#1endcsname{##1}%
                  }%
                  }





                  share|improve this answer


























                    6












                    6








                    6







                    I would not use edef here but work with a second expandafter.



                    The main problem here is that you have a space between #1 and endcsname, so you actually define @Alice<space>, which is possible with csname.



                    Correct code is:



                    defDefineField#1{%
                    expandafterdefcsname #1endcsname##1{%
                    expandaftergdefcsname @#1endcsname{##1}%
                    }%
                    }





                    share|improve this answer













                    I would not use edef here but work with a second expandafter.



                    The main problem here is that you have a space between #1 and endcsname, so you actually define @Alice<space>, which is possible with csname.



                    Correct code is:



                    defDefineField#1{%
                    expandafterdefcsname #1endcsname##1{%
                    expandaftergdefcsname @#1endcsname{##1}%
                    }%
                    }






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 27 at 11:05









                    Martin ScharrerMartin Scharrer

                    202k46643820




                    202k46643820























                        6














                        You're defining csname @Alice endcsname which results in a control sequence token having a trailing space in its name. The space after csname doesn't find its way during tokenization, because it follows a control word, but the space between #1 and endcsname will not be removed.



                        Your usage of edef is quite problematic as well: if you mistakenly use DefineField{Alice} twice,



                        DefineField{Alice}
                        Alice{My name is Alice}
                        showAlice

                        DefineField{Alice}
                        showAlice


                        you'll get



                        > Alice=macro:
                        #1->gdef @Alice {#1}.

                        > Alice=macro:
                        #1->gdef My name is Alice{#1}.


                        This can be cured by checking first if Alice is defined:



                        defDefineField#1{%
                        @ifundefined{#1}
                        {% go on, it's undefined
                        expandafteredefcsname #1endcsname##1{%
                        gdefcsname @#1endcsname{##1}%
                        }%
                        }
                        {% ignore the redefinition
                        PackageWarning{andywiecko}{%
                        expandafternoexpandcsname #1endcsname already defined%
                        }%
                        }%
                        }


                        A simpler approach with xparse and expl3:



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        NewDocumentCommand{DefineField}{m}
                        {
                        cs_new_protected:cpn { #1 } ##1
                        {
                        cs_new_protected:cpn { @#1 } { ##1 } % or `cs_new:cpn
                        }
                        }

                        ExplSyntaxOff

                        DefineField{Alice}
                        Alice{My name is Alice}

                        expandaftershowcsname @Aliceendcsname


                        This will produce a standard error if DefineField{Alice} is used twice or if you try doing DefineField{box}; the code will show



                        > @Alice=protectedlong macro:
                        ->My name is Alice.


                        You may want to use cs_new:cpn in the second instance, depending on what expansion context you will use the @Alice macro.





                        A more proper expl3 interface, where instead of defining @foo macros you do UseField{foo} when needed. A way to override already existing fields is provided.



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        prop_new:N g_andywiecko_fields_prop
                        cs_new:Nn andywiecko_define_field:nn
                        {
                        prop_gput:Nnn g_andywiecko_fields_prop { #1 } { #2 }
                        }

                        NewDocumentCommand{DefineField}{sm}
                        {
                        cs_set_protected:Nn __andywiecko:n
                        {
                        andywiecko_define_field:nn { #2 } { ##1 }
                        }
                        IfBooleanTF { #1 }
                        {% override an existing definition
                        cs_gset_eq:cN { #2 } __andywiecko:n
                        }
                        {% new field
                        cs_new_eq:cN { #2 } __andywiecko:n
                        }
                        }

                        NewExpandableDocumentCommand{UseField}{m}
                        {
                        prop_item:Nn g_andywiecko_fields_prop { #1 }
                        }

                        ExplSyntaxOff

                        DefineField{author} % gives error

                        DefineField*{author} % no error, use new interface

                        DefineField{Alice}
                        Alice{My name is Alice}

                        DefineField{Alice} % gives error





                        share|improve this answer


























                        • Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                          – andywiecko
                          Jan 27 at 11:49
















                        6














                        You're defining csname @Alice endcsname which results in a control sequence token having a trailing space in its name. The space after csname doesn't find its way during tokenization, because it follows a control word, but the space between #1 and endcsname will not be removed.



                        Your usage of edef is quite problematic as well: if you mistakenly use DefineField{Alice} twice,



                        DefineField{Alice}
                        Alice{My name is Alice}
                        showAlice

                        DefineField{Alice}
                        showAlice


                        you'll get



                        > Alice=macro:
                        #1->gdef @Alice {#1}.

                        > Alice=macro:
                        #1->gdef My name is Alice{#1}.


                        This can be cured by checking first if Alice is defined:



                        defDefineField#1{%
                        @ifundefined{#1}
                        {% go on, it's undefined
                        expandafteredefcsname #1endcsname##1{%
                        gdefcsname @#1endcsname{##1}%
                        }%
                        }
                        {% ignore the redefinition
                        PackageWarning{andywiecko}{%
                        expandafternoexpandcsname #1endcsname already defined%
                        }%
                        }%
                        }


                        A simpler approach with xparse and expl3:



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        NewDocumentCommand{DefineField}{m}
                        {
                        cs_new_protected:cpn { #1 } ##1
                        {
                        cs_new_protected:cpn { @#1 } { ##1 } % or `cs_new:cpn
                        }
                        }

                        ExplSyntaxOff

                        DefineField{Alice}
                        Alice{My name is Alice}

                        expandaftershowcsname @Aliceendcsname


                        This will produce a standard error if DefineField{Alice} is used twice or if you try doing DefineField{box}; the code will show



                        > @Alice=protectedlong macro:
                        ->My name is Alice.


                        You may want to use cs_new:cpn in the second instance, depending on what expansion context you will use the @Alice macro.





                        A more proper expl3 interface, where instead of defining @foo macros you do UseField{foo} when needed. A way to override already existing fields is provided.



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        prop_new:N g_andywiecko_fields_prop
                        cs_new:Nn andywiecko_define_field:nn
                        {
                        prop_gput:Nnn g_andywiecko_fields_prop { #1 } { #2 }
                        }

                        NewDocumentCommand{DefineField}{sm}
                        {
                        cs_set_protected:Nn __andywiecko:n
                        {
                        andywiecko_define_field:nn { #2 } { ##1 }
                        }
                        IfBooleanTF { #1 }
                        {% override an existing definition
                        cs_gset_eq:cN { #2 } __andywiecko:n
                        }
                        {% new field
                        cs_new_eq:cN { #2 } __andywiecko:n
                        }
                        }

                        NewExpandableDocumentCommand{UseField}{m}
                        {
                        prop_item:Nn g_andywiecko_fields_prop { #1 }
                        }

                        ExplSyntaxOff

                        DefineField{author} % gives error

                        DefineField*{author} % no error, use new interface

                        DefineField{Alice}
                        Alice{My name is Alice}

                        DefineField{Alice} % gives error





                        share|improve this answer


























                        • Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                          – andywiecko
                          Jan 27 at 11:49














                        6












                        6








                        6







                        You're defining csname @Alice endcsname which results in a control sequence token having a trailing space in its name. The space after csname doesn't find its way during tokenization, because it follows a control word, but the space between #1 and endcsname will not be removed.



                        Your usage of edef is quite problematic as well: if you mistakenly use DefineField{Alice} twice,



                        DefineField{Alice}
                        Alice{My name is Alice}
                        showAlice

                        DefineField{Alice}
                        showAlice


                        you'll get



                        > Alice=macro:
                        #1->gdef @Alice {#1}.

                        > Alice=macro:
                        #1->gdef My name is Alice{#1}.


                        This can be cured by checking first if Alice is defined:



                        defDefineField#1{%
                        @ifundefined{#1}
                        {% go on, it's undefined
                        expandafteredefcsname #1endcsname##1{%
                        gdefcsname @#1endcsname{##1}%
                        }%
                        }
                        {% ignore the redefinition
                        PackageWarning{andywiecko}{%
                        expandafternoexpandcsname #1endcsname already defined%
                        }%
                        }%
                        }


                        A simpler approach with xparse and expl3:



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        NewDocumentCommand{DefineField}{m}
                        {
                        cs_new_protected:cpn { #1 } ##1
                        {
                        cs_new_protected:cpn { @#1 } { ##1 } % or `cs_new:cpn
                        }
                        }

                        ExplSyntaxOff

                        DefineField{Alice}
                        Alice{My name is Alice}

                        expandaftershowcsname @Aliceendcsname


                        This will produce a standard error if DefineField{Alice} is used twice or if you try doing DefineField{box}; the code will show



                        > @Alice=protectedlong macro:
                        ->My name is Alice.


                        You may want to use cs_new:cpn in the second instance, depending on what expansion context you will use the @Alice macro.





                        A more proper expl3 interface, where instead of defining @foo macros you do UseField{foo} when needed. A way to override already existing fields is provided.



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        prop_new:N g_andywiecko_fields_prop
                        cs_new:Nn andywiecko_define_field:nn
                        {
                        prop_gput:Nnn g_andywiecko_fields_prop { #1 } { #2 }
                        }

                        NewDocumentCommand{DefineField}{sm}
                        {
                        cs_set_protected:Nn __andywiecko:n
                        {
                        andywiecko_define_field:nn { #2 } { ##1 }
                        }
                        IfBooleanTF { #1 }
                        {% override an existing definition
                        cs_gset_eq:cN { #2 } __andywiecko:n
                        }
                        {% new field
                        cs_new_eq:cN { #2 } __andywiecko:n
                        }
                        }

                        NewExpandableDocumentCommand{UseField}{m}
                        {
                        prop_item:Nn g_andywiecko_fields_prop { #1 }
                        }

                        ExplSyntaxOff

                        DefineField{author} % gives error

                        DefineField*{author} % no error, use new interface

                        DefineField{Alice}
                        Alice{My name is Alice}

                        DefineField{Alice} % gives error





                        share|improve this answer















                        You're defining csname @Alice endcsname which results in a control sequence token having a trailing space in its name. The space after csname doesn't find its way during tokenization, because it follows a control word, but the space between #1 and endcsname will not be removed.



                        Your usage of edef is quite problematic as well: if you mistakenly use DefineField{Alice} twice,



                        DefineField{Alice}
                        Alice{My name is Alice}
                        showAlice

                        DefineField{Alice}
                        showAlice


                        you'll get



                        > Alice=macro:
                        #1->gdef @Alice {#1}.

                        > Alice=macro:
                        #1->gdef My name is Alice{#1}.


                        This can be cured by checking first if Alice is defined:



                        defDefineField#1{%
                        @ifundefined{#1}
                        {% go on, it's undefined
                        expandafteredefcsname #1endcsname##1{%
                        gdefcsname @#1endcsname{##1}%
                        }%
                        }
                        {% ignore the redefinition
                        PackageWarning{andywiecko}{%
                        expandafternoexpandcsname #1endcsname already defined%
                        }%
                        }%
                        }


                        A simpler approach with xparse and expl3:



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        NewDocumentCommand{DefineField}{m}
                        {
                        cs_new_protected:cpn { #1 } ##1
                        {
                        cs_new_protected:cpn { @#1 } { ##1 } % or `cs_new:cpn
                        }
                        }

                        ExplSyntaxOff

                        DefineField{Alice}
                        Alice{My name is Alice}

                        expandaftershowcsname @Aliceendcsname


                        This will produce a standard error if DefineField{Alice} is used twice or if you try doing DefineField{box}; the code will show



                        > @Alice=protectedlong macro:
                        ->My name is Alice.


                        You may want to use cs_new:cpn in the second instance, depending on what expansion context you will use the @Alice macro.





                        A more proper expl3 interface, where instead of defining @foo macros you do UseField{foo} when needed. A way to override already existing fields is provided.



                        documentclass{article}
                        usepackage{xparse}

                        ExplSyntaxOn

                        prop_new:N g_andywiecko_fields_prop
                        cs_new:Nn andywiecko_define_field:nn
                        {
                        prop_gput:Nnn g_andywiecko_fields_prop { #1 } { #2 }
                        }

                        NewDocumentCommand{DefineField}{sm}
                        {
                        cs_set_protected:Nn __andywiecko:n
                        {
                        andywiecko_define_field:nn { #2 } { ##1 }
                        }
                        IfBooleanTF { #1 }
                        {% override an existing definition
                        cs_gset_eq:cN { #2 } __andywiecko:n
                        }
                        {% new field
                        cs_new_eq:cN { #2 } __andywiecko:n
                        }
                        }

                        NewExpandableDocumentCommand{UseField}{m}
                        {
                        prop_item:Nn g_andywiecko_fields_prop { #1 }
                        }

                        ExplSyntaxOff

                        DefineField{author} % gives error

                        DefineField*{author} % no error, use new interface

                        DefineField{Alice}
                        Alice{My name is Alice}

                        DefineField{Alice} % gives error






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jan 27 at 12:22

























                        answered Jan 27 at 11:40









                        egregegreg

                        720k8719093208




                        720k8719093208













                        • Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                          – andywiecko
                          Jan 27 at 11:49



















                        • Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                          – andywiecko
                          Jan 27 at 11:49

















                        Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                        – andywiecko
                        Jan 27 at 11:49





                        Yours comments, especially about double usage of DefineField{Alice}, are very useful, thanks!

                        – andywiecko
                        Jan 27 at 11:49











                        1














                        In the other answers the spurious space within the csname..endcsname-expression is already pointed out.



                        In case you wish to avoid typing so many csname..endcsname-expressions, I can offer a macro name.



                        name takes following tokens that are not nested in braces for its first argument and following tokens nested in braces for its second argument and applies csname..endcsname to its second argument.

                        The tokens that form the first argument can, e.g., be: globallongouterdef or newcommand or string or meaning or whatever.
                        You can also leave the first argument empty.



                        Examples:



                        nameshow{foo} yields: showfoo



                        namedef{foo}... yields: deffoo...



                        namegloballongouterdef{foo}... yields: globallongouterdeffoo...



                        namenewcommand{foo}... yields: newcommandfoo...



                        name{foo}... yields: foo



                        namenamegloballet{foo}={bar}

                        yields:
                        namegloballetfoo={bar}

                        yields:
                        globalletfoo=bar



                        documentclass{article}

                        newcommandUDExchange[2]{#2#1}
                        newcommandname{}longdefname#1#{romannumeral0innername{#1}}%
                        newcommandinnername[2]{%
                        expandafterUDExchangeexpandafter{csname#2endcsname}{ #1}%
                        }%

                        makeatletter
                        newcommandnovalueprovided{nfss@text{reset@fontbfseries??}}
                        makeatother

                        newcommandDefineField[2][novalueprovided]{%
                        namenewcommand{#2}[1]{namegdef{@#2}{##1}}%
                        namenewcommand{@#2}{}%
                        name{#2}{#1}%
                        }%

                        newcommandUseField[1]{name{@#1}}%

                        DefineField[initial value of field Alice]{Alice}

                        DefineField{Bob}

                        begin{document}

                        {ttfrenchspacing
                        namestring{Alice}: namemeaning{Alice}

                        namestring{@Alice}: namemeaning{@Alice}

                        namestring{Bob}: namemeaning{Bob}

                        namestring{@Bob}: namemeaning{@Bob}

                        verb|UseField{Alice}:| UseField{Alice}

                        verb|UseField{Bob}:| UseField{Bob}
                        }

                        hrulefill

                        Now the fields are changed:

                        Alice{My name is Alice}

                        Bob{My name is Bob}

                        {ttfrenchspacing
                        namestring{Alice}: namemeaning{Alice}

                        namestring{@Alice}: namemeaning{@Alice}

                        namestring{Bob}: namemeaning{Bob}

                        namestring{@Bob}: namemeaning{@Bob}

                        verb|UseField{Alice}:| UseField{Alice}

                        verb|UseField{Bob}:| UseField{Bob}
                        }

                        end{document}


                        If you provide more info about what you try to achieve in practice, an interface could be developed which also does better error-management.



                        enter image description here






                        share|improve this answer






























                          1














                          In the other answers the spurious space within the csname..endcsname-expression is already pointed out.



                          In case you wish to avoid typing so many csname..endcsname-expressions, I can offer a macro name.



                          name takes following tokens that are not nested in braces for its first argument and following tokens nested in braces for its second argument and applies csname..endcsname to its second argument.

                          The tokens that form the first argument can, e.g., be: globallongouterdef or newcommand or string or meaning or whatever.
                          You can also leave the first argument empty.



                          Examples:



                          nameshow{foo} yields: showfoo



                          namedef{foo}... yields: deffoo...



                          namegloballongouterdef{foo}... yields: globallongouterdeffoo...



                          namenewcommand{foo}... yields: newcommandfoo...



                          name{foo}... yields: foo



                          namenamegloballet{foo}={bar}

                          yields:
                          namegloballetfoo={bar}

                          yields:
                          globalletfoo=bar



                          documentclass{article}

                          newcommandUDExchange[2]{#2#1}
                          newcommandname{}longdefname#1#{romannumeral0innername{#1}}%
                          newcommandinnername[2]{%
                          expandafterUDExchangeexpandafter{csname#2endcsname}{ #1}%
                          }%

                          makeatletter
                          newcommandnovalueprovided{nfss@text{reset@fontbfseries??}}
                          makeatother

                          newcommandDefineField[2][novalueprovided]{%
                          namenewcommand{#2}[1]{namegdef{@#2}{##1}}%
                          namenewcommand{@#2}{}%
                          name{#2}{#1}%
                          }%

                          newcommandUseField[1]{name{@#1}}%

                          DefineField[initial value of field Alice]{Alice}

                          DefineField{Bob}

                          begin{document}

                          {ttfrenchspacing
                          namestring{Alice}: namemeaning{Alice}

                          namestring{@Alice}: namemeaning{@Alice}

                          namestring{Bob}: namemeaning{Bob}

                          namestring{@Bob}: namemeaning{@Bob}

                          verb|UseField{Alice}:| UseField{Alice}

                          verb|UseField{Bob}:| UseField{Bob}
                          }

                          hrulefill

                          Now the fields are changed:

                          Alice{My name is Alice}

                          Bob{My name is Bob}

                          {ttfrenchspacing
                          namestring{Alice}: namemeaning{Alice}

                          namestring{@Alice}: namemeaning{@Alice}

                          namestring{Bob}: namemeaning{Bob}

                          namestring{@Bob}: namemeaning{@Bob}

                          verb|UseField{Alice}:| UseField{Alice}

                          verb|UseField{Bob}:| UseField{Bob}
                          }

                          end{document}


                          If you provide more info about what you try to achieve in practice, an interface could be developed which also does better error-management.



                          enter image description here






                          share|improve this answer




























                            1












                            1








                            1







                            In the other answers the spurious space within the csname..endcsname-expression is already pointed out.



                            In case you wish to avoid typing so many csname..endcsname-expressions, I can offer a macro name.



                            name takes following tokens that are not nested in braces for its first argument and following tokens nested in braces for its second argument and applies csname..endcsname to its second argument.

                            The tokens that form the first argument can, e.g., be: globallongouterdef or newcommand or string or meaning or whatever.
                            You can also leave the first argument empty.



                            Examples:



                            nameshow{foo} yields: showfoo



                            namedef{foo}... yields: deffoo...



                            namegloballongouterdef{foo}... yields: globallongouterdeffoo...



                            namenewcommand{foo}... yields: newcommandfoo...



                            name{foo}... yields: foo



                            namenamegloballet{foo}={bar}

                            yields:
                            namegloballetfoo={bar}

                            yields:
                            globalletfoo=bar



                            documentclass{article}

                            newcommandUDExchange[2]{#2#1}
                            newcommandname{}longdefname#1#{romannumeral0innername{#1}}%
                            newcommandinnername[2]{%
                            expandafterUDExchangeexpandafter{csname#2endcsname}{ #1}%
                            }%

                            makeatletter
                            newcommandnovalueprovided{nfss@text{reset@fontbfseries??}}
                            makeatother

                            newcommandDefineField[2][novalueprovided]{%
                            namenewcommand{#2}[1]{namegdef{@#2}{##1}}%
                            namenewcommand{@#2}{}%
                            name{#2}{#1}%
                            }%

                            newcommandUseField[1]{name{@#1}}%

                            DefineField[initial value of field Alice]{Alice}

                            DefineField{Bob}

                            begin{document}

                            {ttfrenchspacing
                            namestring{Alice}: namemeaning{Alice}

                            namestring{@Alice}: namemeaning{@Alice}

                            namestring{Bob}: namemeaning{Bob}

                            namestring{@Bob}: namemeaning{@Bob}

                            verb|UseField{Alice}:| UseField{Alice}

                            verb|UseField{Bob}:| UseField{Bob}
                            }

                            hrulefill

                            Now the fields are changed:

                            Alice{My name is Alice}

                            Bob{My name is Bob}

                            {ttfrenchspacing
                            namestring{Alice}: namemeaning{Alice}

                            namestring{@Alice}: namemeaning{@Alice}

                            namestring{Bob}: namemeaning{Bob}

                            namestring{@Bob}: namemeaning{@Bob}

                            verb|UseField{Alice}:| UseField{Alice}

                            verb|UseField{Bob}:| UseField{Bob}
                            }

                            end{document}


                            If you provide more info about what you try to achieve in practice, an interface could be developed which also does better error-management.



                            enter image description here






                            share|improve this answer















                            In the other answers the spurious space within the csname..endcsname-expression is already pointed out.



                            In case you wish to avoid typing so many csname..endcsname-expressions, I can offer a macro name.



                            name takes following tokens that are not nested in braces for its first argument and following tokens nested in braces for its second argument and applies csname..endcsname to its second argument.

                            The tokens that form the first argument can, e.g., be: globallongouterdef or newcommand or string or meaning or whatever.
                            You can also leave the first argument empty.



                            Examples:



                            nameshow{foo} yields: showfoo



                            namedef{foo}... yields: deffoo...



                            namegloballongouterdef{foo}... yields: globallongouterdeffoo...



                            namenewcommand{foo}... yields: newcommandfoo...



                            name{foo}... yields: foo



                            namenamegloballet{foo}={bar}

                            yields:
                            namegloballetfoo={bar}

                            yields:
                            globalletfoo=bar



                            documentclass{article}

                            newcommandUDExchange[2]{#2#1}
                            newcommandname{}longdefname#1#{romannumeral0innername{#1}}%
                            newcommandinnername[2]{%
                            expandafterUDExchangeexpandafter{csname#2endcsname}{ #1}%
                            }%

                            makeatletter
                            newcommandnovalueprovided{nfss@text{reset@fontbfseries??}}
                            makeatother

                            newcommandDefineField[2][novalueprovided]{%
                            namenewcommand{#2}[1]{namegdef{@#2}{##1}}%
                            namenewcommand{@#2}{}%
                            name{#2}{#1}%
                            }%

                            newcommandUseField[1]{name{@#1}}%

                            DefineField[initial value of field Alice]{Alice}

                            DefineField{Bob}

                            begin{document}

                            {ttfrenchspacing
                            namestring{Alice}: namemeaning{Alice}

                            namestring{@Alice}: namemeaning{@Alice}

                            namestring{Bob}: namemeaning{Bob}

                            namestring{@Bob}: namemeaning{@Bob}

                            verb|UseField{Alice}:| UseField{Alice}

                            verb|UseField{Bob}:| UseField{Bob}
                            }

                            hrulefill

                            Now the fields are changed:

                            Alice{My name is Alice}

                            Bob{My name is Bob}

                            {ttfrenchspacing
                            namestring{Alice}: namemeaning{Alice}

                            namestring{@Alice}: namemeaning{@Alice}

                            namestring{Bob}: namemeaning{Bob}

                            namestring{@Bob}: namemeaning{@Bob}

                            verb|UseField{Alice}:| UseField{Alice}

                            verb|UseField{Bob}:| UseField{Bob}
                            }

                            end{document}


                            If you provide more info about what you try to achieve in practice, an interface could be developed which also does better error-management.



                            enter image description here







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jan 27 at 14:42

























                            answered Jan 27 at 14:14









                            Ulrich DiezUlrich Diez

                            4,865618




                            4,865618






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f472068%2fmacro-defining-macro-defining-global-macro-similar-to-author-or-title-fie%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                How do I know what Microsoft account the skydrive app is syncing to?

                                Grease: Live!

                                When does type information flow backwards in C++?