{"id":5594,"date":"2014-04-02T08:22:10","date_gmt":"2014-04-02T08:22:10","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/04\/02\/how-to-create-a-command-with-key-values-collection-of-common-programming-errors\/"},"modified":"2014-04-02T08:22:10","modified_gmt":"2014-04-02T08:22:10","slug":"how-to-create-a-command-with-key-values-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/04\/02\/how-to-create-a-command-with-key-values-collection-of-common-programming-errors\/","title":{"rendered":"How to create a command with key values?-Collection of common programming errors"},"content":{"rendered":"<p>Use <code>pgfkeys<\/code>! There are three steps to this: first, you must make your command accept keys as options. Traditionally, this is as you wrote it: an optional argument. In that case, you should start your definition like this:<\/p>\n<pre><code>\\newcommand\\myparbox[2][]{%\n \\pgfkeys{#1}%\n ...\n}\n<\/code><\/pre>\n<p>The syntax is that the optional argument is expected to contain a list of keys (possibly set to values) that are then passed to <code>\\pgfkeys<\/code> for processing. The second step is to figure out what you&#8217;re going to do with the results: that is, you imagine that <code>\\pgfkeys<\/code> does some kind of magic and produces a bunch of macros, or conditionals, and you need to make these things affect the operation of <code>\\myparbox<\/code>.<\/p>\n<p>Let&#8217;s take the easy ones as an example: <code>width<\/code> and <code>height<\/code>. You will probably just pass them to <code>\\parbox<\/code> as the optional parameters that control the width and height, and a good way to do that is to store their values in a macro. Let&#8217;s say that <code>width<\/code> goes to the macro <code>\\myparboxWidth<\/code> and <code>height<\/code> goes to <code>\\myparboxHeight<\/code>. Then your definition of <code>\\myparbox<\/code> will look more like:<\/p>\n<pre><code>\\newcommand\\myparbox[2][]{%\n \\pgfkeys{#1}%\n \\parbox[t][\\myparboxHeight]{\\myparboxWidth}{#2}%\n}\n<\/code><\/pre>\n<p>I had to write <code>[t]<\/code> for the first optional argument in <code>\\parbox<\/code>, which specifies the position in the surrounding text, because height is the second argument. This suggests that we ought to have a <code>position<\/code> key as well that corresponds to a macro <code>\\myparboxPosition<\/code>. There&#8217;s a third optional argument that I didn&#8217;t give, but it&#8217;s the &#8220;inner position&#8221;, which can be either top, bottom, centered, or stretched. Might as well have an <code>inner position<\/code> key that sets <code>\\myparboxInnerPos<\/code>. That gives:<\/p>\n<pre><code>\\newcommand\\myparbox[2][1]{%\n \\pgfkeys{#1}%\n \\parbox[\\myparboxPosition][\\myparboxHeight]\n        [\\myparboxInnerPos]{\\myparboxWidth}{#2}\n}\n<\/code><\/pre>\n<p>That&#8217;s enough for now. In order to make this work, you have to define your keys, and that&#8217;s where <code>pgfkeys<\/code> is far, far better than its competitors. You can tell it to do all sorts of things with the values other than just storing them, though for <code>height<\/code> and <code>width<\/code> that will be enough. You define keys by using <code>\\pgfkeys<\/code> in the preamble to set things up:<\/p>\n<pre><code>\\usepackage{pgfkeys}\n\\pgfkeys{\n \/myparbox\/.is family, \/myparbox,\n width\/.estore in = \\myparboxWidth,\n height\/.estore in = \\myparboxHeight,\n}\n<\/code><\/pre>\n<p>This has a few features. The real action is that I&#8217;ve said that both of these keys will &#8220;pass through&#8221; their arguments to the respective macros; if you said &#8220;width = 10pt&#8221; in the options to <code>\\myparbox<\/code>, then <code>\\myparboxWidth<\/code> would get set to <code>10pt<\/code>. I wrote <code>.estore in<\/code> rather than plain <code>.store in<\/code> to force the value to be expanded before being saved; this prevents subtle errors if someone passes a macro that could get changed somehow before being used in <code>\\myparbox<\/code>.<\/p>\n<p>The other feature is that I&#8217;ve put the keys in a family, called <code>\/myparbox<\/code>. In <code>pgfkeys<\/code> jargon, this is a &#8220;directory&#8221;, like in a file system. Calling the <code>\/myparbox<\/code> key changes directory to this one, and then all keys are private to that directory. This prevents name clashes with the (very common) key names <code>width<\/code> and <code>height<\/code>. Now you have to modify your <code>\\pgfkeys<\/code> call in <code>\\myparbox<\/code> as well to change directory:<\/p>\n<pre><code>\\newcommand\\myparbox[2][1]{%\n \\pgfkeys{\/myparbox, #1}%\n ...\n}\n<\/code><\/pre>\n<p>For the position arguments, it would be nice if they could have more&#8230;logical names than simply &#8220;t&#8221;, &#8220;b&#8221;, &#8220;c&#8221;, or &#8220;s&#8221;. Since <code>pgfkeys<\/code> is, at heart, a lookup engine, it is pretty easy to have it map logical names to various actions: you just make each name a key that points to the corresponding action. I would do the following:<\/p>\n<pre><code>\\pgfkeys{\n \/myparbox,\n position\/.style = {positions\/#1\/.get = \\myparboxPosition},\n inner position\/.style = {positions\/#1\/.get = \\myparboxInnerPos},\n positions\/.cd,\n  top\/.initial = t,\n  center\/.initial = c,\n  bottom\/.initial = b,\n  stretch\/.initial = s,\n}\n<\/code><\/pre>\n<p>This is <em>much<\/em> more intricate than <code>width<\/code> and <code>height<\/code>, so I&#8217;ll take it apart.<\/p>\n<ul>\n<li>\n<p>First, we have the basic <code>position<\/code> and <code>inner position<\/code> keys, which are passed values. <code>\\pgfkeys<\/code> treats these keys like macros with one argument, so the value is available as <code>#1<\/code>. We tell them to store the values in the appropriate place. The <code>\/.style<\/code> suffix is a &#8220;handler&#8221; that defines a more complex behavior for a key than just setting a value; in this case, it makes the key &#8220;expand&#8221; to other keys that are then called to continue the work.<\/p>\n<\/li>\n<li>\n<p>What gets stored, though, has to be properly formatted: <code>\\parbox<\/code> expects those one-character options and not words. So we define a <code>positions<\/code> subdirectory containing all the words we want to accept, defined to contain their translations into <code>\\parbox<\/code>-speak. (As before, we isolate these special keys in a directory where they can&#8217;t be seen and won&#8217;t conflict with real options.) The <code>\/.initial<\/code> handler sets values for keys the first time they are seen (these keys will never be redefined, actually).<\/p>\n<\/li>\n<li>\n<p>Back in <code>position<\/code> and <code>inner position<\/code>, the way we actually store the values is by using the <code>\/.get<\/code> handler for the appropriate <code>positions\/<\/code> subkey. What this does is simply copy the value in that key into the named macro, which is what we wanted: <code>position = top<\/code> becomes <code>\\def\\myparboxPosition{t}<\/code> (effectively).<\/p>\n<\/li>\n<\/ul>\n<p>There is <em>one<\/em> more complication to take care of: what happens if you only specify half the options? The remaining macros <code>\\myparboxWhatever<\/code> will be undefined or, more insidiously, defined to be whatever they got set to the last time they called <code>\\myparbox<\/code>. We need to establish some defaults. The easiest way of doing that is to make a <code>default<\/code> style key that we run before processing the options in <code>\\myparbox<\/code>. It may look like this:<\/p>\n<pre><code>\\pgfkeys{\n \/myparbox,\n default\/.style = \n  {width = \\textwidth, height = \\baselineskip,\n   position = center, inner position = center}\n}\n<\/code><\/pre>\n<p>Then the <code>\\pgfkeys<\/code> call in <code>\\myparbox<\/code> becomes<\/p>\n<pre><code>\\pgfkeys{\/myparbox, default, #1}\n<\/code><\/pre>\n<p>Here is the final result:<\/p>\n<pre><code>\\documentclass{article}\n\\usepackage{pgfkeys}\n\n% Set up the keys.  Only the ones directly under \/myparbox\n% can be accepted as options to the \\myparbox macro.\n\\pgfkeys{\n \/myparbox\/.is family, \/myparbox,\n % Here are the options that a user can pass\n default\/.style = \n  {width = \\textwidth, height = \\baselineskip,\n   position = center, inner position = center},\n width\/.estore in = \\myparboxWidth,\n height\/.estore in = \\myparboxHeight,\n position\/.style = {positions\/#1\/.get = \\myparboxPosition},\n inner position\/.style = {positions\/#1\/.get = \\myparboxInnerPos},\n % Here is the dictionary for positions.\n positions\/.cd,\n  top\/.initial = t,\n  center\/.initial = c,\n  bottom\/.initial = b,\n  stretch\/.initial = s,\n}\n\n% We process the options first, then pass them to `\\parbox` in the form of macros.\n\\newcommand\\myparbox[2][]{%\n \\pgfkeys{\/myparbox, default, #1}%\n \\parbox[\\myparboxPosition][\\myparboxHeight]\n        [\\myparboxInnerPos]{\\myparboxWidth}{#2}\n}\n\n\\begin{document}\n % This should print \"Some text, and\"\n % followed by \"a box\" raised about one line above the natural position\n % followed by \"and more text\" after a large space.\n Some text, and \\myparbox[width = 50pt, height = 20pt, position = bottom, inner position = top]{a box} and more text.\n\n % Should look pretty much like normal text, with slight offsets down and over around the box.\n Some text, and \\myparbox[width = 30pt]{a box} and more text.\n\n % The box should have very spread-out lines\n Some text, and\n \\myparbox[width = 30pt, height = 100pt, inner position = stretch]\n {a box\\par \\vspace{\\stretch{1}}with\\par\\vspace{\\stretch{1}}words}\n and more text.\n\\end{document}\n<\/code><\/pre>\n<p>Using these techniques, you can (perhaps not easily at first) craft your own options and make them tweak the behavior of <code>\\myparbox<\/code>. For example, if you wanted to have a <code>color<\/code> option, you would link it to the argument of a <code>\\textcolor<\/code> command.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use pgfkeys! There are three steps to this: first, you must make your command accept keys as options. Traditionally, this is as you wrote it: an optional argument. In that case, you should start your definition like this: \\newcommand\\myparbox[2][]{% \\pgfkeys{#1}% &#8230; } The syntax is that the optional argument is expected to contain a list [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5594","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5594","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=5594"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5594\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=5594"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=5594"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=5594"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}