├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── .lintr ├── CONTRIBUTING ├── COPYING ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── optparse-package.R └── optparse.R ├── README.Rrst ├── README.rst ├── Rakefile ├── _pkgdown.yml ├── cran-comments.rst ├── exec ├── display_file.R └── example.R ├── inst └── COPYRIGHTS ├── man ├── OptionParser-class.Rd ├── OptionParser.Rd ├── OptionParserOption-class.Rd ├── add_make_option.Rd ├── figures │ ├── logo.png │ └── logo.svg ├── formatter.Rd ├── optparse-package.Rd ├── parse_args.Rd └── print_help.Rd ├── raw-data └── logo.R ├── tests ├── run-all.R ├── test_help.R ├── test_help.Rout.save └── testthat │ └── test-optparse.R └── vignettes └── optparse.Rrst /.Rbuildignore: -------------------------------------------------------------------------------- 1 | cran-comments.rst 2 | CONTRIBUTING 3 | Rakefile 4 | ^raw-data$ 5 | ^pkgdown$ 6 | README.Rrst 7 | README.rst 8 | README.html 9 | ^\.appveyor\.yml$ 10 | ^_pkgdown.yml$ 11 | ^\.lintr$ 12 | ^\.travis\.yml$ 13 | revdep 14 | ^\.github$ 15 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macOS-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel/1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: rcmdcheck 45 | 46 | - uses: r-lib/actions/check-r-package@v2 47 | 48 | - name: Show testthat output 49 | if: always() 50 | run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true 51 | shell: bash 52 | 53 | - name: Upload check results 54 | if: failure() 55 | uses: actions/upload-artifact@main 56 | with: 57 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 58 | path: check 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.timestamp 3 | *.rst 4 | .Rproj.user 5 | /.Rhistory 6 | pkgdown 7 | revdep 8 | README.md 9 | README.html 10 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults(line_length_linter(120), 2 | object_usage_linter = NULL) 3 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Pull requests are welcome but not guaranteed to be accepted (especially if they 2 | break reverse compatibility). It might be a good idea to submit an issue 3 | asking whether such a feature would be accepted before writing a patch. 4 | 5 | When submitting a patch please state that you are giving me an non-exclusive 6 | Unlimited license to your contribution so I have the flexibility of updating 7 | the package license in the future while you retain the right to use your code 8 | on other projects as you see fit as well as the right to fork the version of 9 | package that you contributed to. 10 | 11 | Additionally, although not required, adding a unit test illustrating a bug or 12 | testing the new feature would be much appreciated. 13 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Encoding: UTF-8 2 | Package: optparse 3 | Type: Package 4 | Title: Command Line Option Parser 5 | Version: 1.7.5 6 | Authors@R: c(person("Trevor L.", "Davis", role=c("aut", "cre"), 7 | email="trevor.l.davis@gmail.com", 8 | comment = c(ORCID = "0000-0001-6341-4639")), 9 | person("Allen", "Day", role="ctb", comment="Some documentation and examples ported from the getopt package."), 10 | person("Python Software Foundation", role="ctb", comment="Some documentation from the optparse Python module."), 11 | person("Steve", "Lianoglou", role="ctb"), 12 | person("Jim", "Nikelski", role="ctb"), 13 | person("Kirill", "Müller", role="ctb"), 14 | person("Peter", "Humburg", role="ctb"), 15 | person("Rich", "FitzJohn", role="ctb"), 16 | person("Gyu Jin", "Choi", role="ctb")) 17 | Description: A command line parser inspired by Python's 'optparse' library to 18 | be used with Rscript to write "#!" shebang scripts that accept short and 19 | long flag/options. 20 | License: GPL (>= 2) 21 | Copyright: See file (inst/)COPYRIGHTS. 22 | URL: https://github.com/trevorld/r-optparse 23 | BugReports: https://github.com/trevorld/r-optparse/issues 24 | LazyLoad: yes 25 | Depends: 26 | R (>= 3.6.0) 27 | Imports: 28 | methods, 29 | getopt (>= 1.20.2) 30 | Suggests: 31 | knitr (>= 1.15.19), 32 | stringr, 33 | testthat 34 | VignetteBuilder: knitr 35 | Roxygen: list(markdown = TRUE) 36 | RoxygenNote: 7.3.1 37 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(IndentedHelpFormatter) 4 | export(OptionParser) 5 | export(OptionParserOption) 6 | export(TitledHelpFormatter) 7 | export(add_option) 8 | export(make_option) 9 | export(parse_args) 10 | export(parse_args2) 11 | export(print_help) 12 | exportClasses(OptionParser) 13 | exportClasses(OptionParserOption) 14 | import(getopt) 15 | import(methods) 16 | importFrom(utils,tail) 17 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | optparse 1.7.5 2 | ============== 3 | 4 | * We no longer coerce the type of an option `default` to match that of 5 | its `type` argument when `action = "callback"`. 6 | Thanks husheng (@hs3434) for bug report (#47). 7 | 8 | optparse 1.7.4 9 | ============== 10 | 11 | * Revises vignette engine specification in the `DESCRIPTION` to suppress new CRAN check NOTE (#43). 12 | 13 | optparse 1.7.3 14 | ============== 15 | 16 | * The errors raised by `parse_args()` (and `parse_args2()`) are now of class "optparse\_parse\_error". 17 | 18 | When `interactive()` is `FALSE` we now print out a usage string followed by 19 | a (less verbose) error message. 20 | 21 | * Throws a more informative error message for unknown short flags when ``positional_arguments=TRUE``. 22 | Thanks Greg Minshall for bug report (#42). 23 | 24 | optparse 1.7.1 25 | ============== 26 | 27 | * Add a ``formatter`` argument to ``OptionParser()`` for a function to format the usage message (#30). 28 | By default uses the new function ``IndentedHelpFormatter()``. 29 | `{optparse}` also provides the new function ``TitledHelpFormatter()``. 30 | Thanks Ni Huang for suggestion. 31 | 32 | optparse 1.6.6 33 | ============== 34 | 35 | * Throws an error for unknown short flags and long flags when ``positional_arguments=TRUE``. 36 | Thanks Greg Minshall for bug report (#34). 37 | * If the ``callback`` parameter of ``add_option`` / ``make_option`` is not ``NULL`` then 38 | the default of ``action`` is now ``"callback"``. Thanks Greg Minshall for suggestion (#35). 39 | * Better documentation of ``action=="callback"`` in the man page for ``add_option`` and ``make_option``. 40 | Thanks Greg Minshall for bug report (#35). 41 | 42 | optparse 1.6.4 43 | ============== 44 | 45 | * Fixes bug in printing help for ``action=="callback"`` when ``metavar==NULL`` (#29). 46 | Thanks Ni Huang for bug report. 47 | * Throws an error when passed short flags more than one letter long (#32). 48 | Thanks Gautier Richard for bug report. 49 | 50 | optparse 1.6.2 51 | ============== 52 | 53 | * Fixs a parsing bug when ``action=="callback"`` and ``positional_argument==TRUE`` (#28). 54 | Thanks Ni Huang for bug report. 55 | 56 | optparse 1.6.1 57 | ============== 58 | 59 | * Improves accuracy of README (#27). Thanks Alex Penson for bug report. 60 | 61 | optparse 1.6.0 62 | ============== 63 | 64 | * Supports callback actions (#26). Thanks Gyu Jin Choi for patch. 65 | * If ``interactive() == FALSE`` and ``print_help_and_exit == TRUE`` then 66 | ``optparse`` will now call ``quit(status=0)`` instead of ``quit(status=1)`` after 67 | printing the help message (this matches behaviour of the python package). 68 | * Better error message when forgetting to set ``add_help_option=FALSE`` when 69 | defining an ``-h`` or ``--help`` flag. Thanks Jeff P. Bruce for bug report. 70 | * Increment ``getopt`` requirement so that empty strings are parsed correctly. 71 | Thanks Matthew Flickinger for bug report. 72 | 73 | optparse 1.4.4 74 | ============== 75 | 76 | * Minor documentation fixes. Thanks J. J. Ramsey and Daeyoung Kim for bug reports. 77 | * Fix bug when ``add_help_option`` in ``OptionParser`` set to ``FALSE``. Thanks to Jeff Bruce for bug report. 78 | * ``parse_args`` now supports ``convert_hyphens_to_underscores`` argument which converts any hyphens to underscores 79 | when returning the list of options 80 | * Now includes the convenience function ``parse_args2`` which wraps ``parse_args`` with ``positional_arguments`` set to ``TRUE`` 81 | and ``convert_hyphens_to_underscores`` set to ``TRUE``. 82 | 83 | optparse 1.3.2 84 | ============== 85 | 86 | * ``optparse`` should no longer give any warnings when ``options(warnPartialMatchArgs=TRUE)``. Thanks Rich FitzJohn for patch. 87 | * ``print_help`` no longer throws an error if we have a default argument of length zero. Thanks Benjamin Tyner for bug report. 88 | 89 | optparse 1.3.0 90 | ============== 91 | 92 | * ``OptionParser`` and ``OptionParserOption`` S4 classes are now exported. Thanks Peter Humburg for patch. 93 | 94 | optparse 1.2.0 95 | ============== 96 | 97 | * Parameter ``positional_arguments`` of function ``parse_args`` now accepts one 98 | or two numeric values that denote the minimum and maximum number of supported 99 | positional arguments. 100 | Thanks Kirill Müller for patch. 101 | * If ``interactive() == TRUE`` then ``parse_args`` will no longer ``quit(status=1)`` 102 | after printing a help message but will instead throw an error. 103 | ``optparse`` will continue to ``quit(status=1)`` after printing a help message 104 | for non-interactive Rscripts unless ``print_help_and_exit == FALSE``. 105 | * In ``make_option`` argument ``type="numeric"`` automatically cast to ``double``. 106 | Previously users might have received an error passing negative numbers if they 107 | accidentally specified "numeric" instead of "double". 108 | * Bug fixed in printing usage message for options with default value of NA 109 | and a help string including "%default". 110 | Thanks Stefan Seemayer for bug report and patch. 111 | 112 | optparse 1.0.2 113 | ============== 114 | 115 | * Project website moved to https://github.com/trevorld/optparse 116 | * We now replace all occurrences of %prog in usage message (including description and epilogue). 117 | Previously we would only replace one occurrence and didn't make replacements in description and epilogue. 118 | * Fix bug in ``parse_args`` when we have options with no short flag and positional_arguments=TRUE. 119 | Thanks Miroslav Posta for bug report. 120 | 121 | optparse 1.0.0 122 | ============== 123 | 124 | * Added `description` and `epilogue` arguments to `OptionParser` to allow 125 | users to add more information to generated help messages 126 | * Slightly alters the generated usage string 127 | to match more closely what the Python module does 128 | * No longer exports S4 classes that represent OptionParser and OptionParserOption 129 | * Now requires package getopt (>= 1.19) which has also been moved to 130 | Imports field from Depends field in DESCRIPTION 131 | * Now also Suggests stringr package in DESCRIPTION 132 | -------------------------------------------------------------------------------- /R/optparse-package.R: -------------------------------------------------------------------------------- 1 | #'Command line option parser 2 | #' 3 | #'Goal is to create an R package of a command line parser inspired by Python's 4 | #'\dQuote{optparse} library. 5 | #' 6 | #'\code{optparse} is primarily intended to be used with 7 | #'\dQuote{Rscript}. It facilitates writing \dQuote{#!} shebang scripts that 8 | #'accept short and long flags/options. It can also be used from directly, but 9 | #'is probably less useful in this context. 10 | #' 11 | #'See package vignette for a more detailed example. 12 | #' 13 | #'Notes on naming convention in package: 1. An option is one of the shell-split 14 | #'input strings. 2. A flag is a type of option. a flag can be defined as having 15 | #'no argument (defined below), a required argument, or an optional argument. 3. 16 | #'An argument is a type of option, and is the value associated with a flag. 4. 17 | #'A long flag is a type of flag, and begins with the string \dQuote{--}. If the 18 | #'long flag has an associated argument, it may be delimited from the long flag 19 | #'by either a trailing =, or may be the subsequent option. 5. A short flag is a 20 | #'type of flag, and begins with the string \dQuote{-}. If a short flag has an 21 | #'associated argument, it is the subsequent option. short flags may be bundled 22 | #'together, sharing a single leading \dQuote{"-"}, but only the final short 23 | #'flag is able to have a corresponding argument. %%% 24 | #' 25 | #'@name optparse-package 26 | #'@aliases optparse-package optparse 27 | #'@author Trevor L. Davis. 28 | #' 29 | #'Some documentation and unit tests ported from Allen Day's getopt package. 30 | #' 31 | #'The documentation for Python's optparse library, which this package is based 32 | #'on, is Copyright 1990-2009, Python Software Foundation. 33 | #'@seealso \code{\link[getopt]{getopt}} 34 | #'@references Python's \code{optparse} library, which this package is based on, 35 | #'is described here: \url{https://docs.python.org/3/library/optparse.html} 36 | #'@keywords package 37 | #'@examples 38 | #' 39 | #' example_file <- system.file("exec", "example.R", package = "optparse") 40 | #' example_file_2 <- system.file("exec", "display_file.R", package = "optparse") 41 | #' \dontrun{ 42 | #' readLines(example_file) 43 | #' readLines(example_file_2) 44 | #' } 45 | #' 46 | "_PACKAGE" 47 | -------------------------------------------------------------------------------- /R/optparse.R: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010-2024 Trevor L. Davis 2 | # Copyright (c) 2015 Rick FitzJohn https://github.com/richfitz 3 | # Copyright (c) 2013 Kirill Müller https://github.com/krlmlr 4 | # Copyright (c) 2011 Jim Nikelski 5 | # Copyright (c) 2010 Steve Lianoglou 6 | # 7 | # This file is free software: you may copy, redistribute and/or modify it 8 | # under the terms of the GNU General Public License as published by the 9 | # Free Software Foundation, either version 2 of the License, or (at your 10 | # option) any later version. 11 | # 12 | # This file is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | # 20 | # This file incorporates work from the optparse module in Python 2.6.2. 21 | # 22 | # Copyright (c) 1990-2009 Python Software Foundation; All Rights Reserved 23 | # 24 | # See (inst/)COPYRIGHTS or http://docs.python.org/2/license.html for the full 25 | # Python (GPL-compatible) license stack. 26 | # 27 | # As mentioned above, this file incorporates some patches by Steve Lianoglou (c) 2010 28 | # He explicitly gave me a non-exclusive unlimited license to code in his patches 29 | 30 | #' Option Parser 31 | #' 32 | #' @slot usage The program usage message that will printed out if 33 | #' \code{parse_args} finds a help option, \code{\%prog} is substituted with the 34 | #' value of the \code{prog} argument. 35 | #' @slot options A list of of \code{OptionParserOption} instances that will 36 | #' define how \code{parse_args} reacts to command line options. 37 | #' \code{OptionParserOption} instances are usually created by \code{make_option} 38 | #' and can also be added to an existing \code{OptionParser} instance via the 39 | #' \code{add_option} function. 40 | #' @slot description Additional text for \code{print_help} to print out between 41 | #' usage statement and options statement 42 | #' @slot epilogue Additional text for \code{print_help} to print out after 43 | #' the options statement 44 | #' @slot formatter A function that \code{print_help} will use to print out after 45 | #' the options statement. Default is [IndentedHelpFormatter()]. This 46 | #' package also provides the builtin formatter [TitledHelpFormatter()]. 47 | #' @author Trevor Davis. 48 | #' @seealso \code{\link{OptionParserOption}} 49 | #' @import methods 50 | #' @exportClass OptionParser 51 | setClass("OptionParser", representation(usage = "character", options = "list", 52 | description = "character", epilogue = "character", 53 | formatter = "function")) 54 | 55 | #' Class to hold information about command-line options 56 | #' 57 | #' @slot short_flag String of the desired short flag 58 | #' comprised of the \dQuote{-} followed by a letter. 59 | #' @slot long_flag String of the desired long flag comprised of \dQuote{--} 60 | #' followed by a letter and then a sequence of alphanumeric characters. 61 | #' @slot action A character string that describes the action \code{optparse} 62 | #' should take when it encounters an option, either \dQuote{store}, 63 | #' \dQuote{store_true}, or \dQuote{store_false}. The default is \dQuote{store} 64 | #' which signifies that \code{optparse} should store the specified following 65 | #' value if the option is found on the command string. \dQuote{store_true} 66 | #' stores \code{TRUE} if the option is found and \dQuote{store_false} stores 67 | #' \code{FALSE} if the option is found. 68 | #' @slot type A character string that describes specifies which data type 69 | #' should be stored, either \dQuote{logical}, \dQuote{integer}, \dQuote{double}, 70 | #' \dQuote{complex}, or \dQuote{character}. Default is \dQuote{logical} if 71 | #' \code{action \%in\% c("store_true", store_false)}, \code{typeof(default)} if 72 | #' \code{action == "store"} and default is not \code{NULL} and 73 | #' \dQuote{character} if \code{action == "store"} and default is \code{NULL}. 74 | #' \dQuote{numeric} will be converted to \dQuote{double}. 75 | #' @slot dest A character string that specifies what field in the list returned 76 | #' by \code{parse_args} should \code{optparse} store option values. Default is 77 | #' derived from the long flag in \code{opt_str}. 78 | #' @slot default The default value \code{optparse} should use if it does not 79 | #' find the option on the command line. 80 | #' @slot help A character string describing the option to be used by 81 | #' \code{print_help} in generating a usage message. \code{\%default} will be 82 | #' substituted by the value of \code{default}. 83 | #' @slot metavar A character string that stands in for the option argument when 84 | #' printing help text. Default is the value of \code{dest}. 85 | #' @slot callback A function that executes after the each option value is fully parsed 86 | #' @slot callback_args Additional arguments that pass to the callback function. 87 | #' @seealso \code{\link{make_option}} 88 | #' @exportClass OptionParserOption 89 | #' @export OptionParserOption 90 | OptionParserOption <- setClass("OptionParserOption", representation(short_flag = "character", # nolint 91 | long_flag = "character", 92 | action = "character", 93 | type = "character", 94 | dest = "character", 95 | default = "ANY", 96 | help = "character", 97 | metavar = "character", 98 | callback = "ANY", 99 | callback_args = "ANY")) 100 | 101 | #' A function to create an instance of a parser object 102 | #' 103 | #' This function is used to create an instance of a parser object 104 | #' which when combined with the \code{parse_args}, \code{make_option}, and \code{add_option} 105 | #' methods is very useful for parsing options from the command line. 106 | #' 107 | #' @param usage The program usage message that will printed out if 108 | #' \code{parse_args} finds a help option, \code{\%prog} is substituted with the 109 | #' value of the \code{prog} argument. 110 | #' @param option_list A list of of \code{OptionParserOption} instances that will 111 | #' define how \code{parse_args} reacts to command line options. 112 | #' \code{OptionParserOption} instances are usually created by \code{make_option} 113 | #' and can also be added to an existing \code{OptionParser} instance via the 114 | #' \code{add_option} function. 115 | #' @param add_help_option Whether a standard help option should be automatically 116 | #' added to the \code{OptionParser} instance. 117 | #' @param prog Program name to be substituted for \code{\%prog} in the usage 118 | #' message (including description and epilogue if present), 119 | #' the default is to use the actual Rscript file name if called by an 120 | #' Rscript file and otherwise keep \code{\%prog}. 121 | #' @param description Additional text for \code{print_help} to print out between 122 | #' usage statement and options statement 123 | #' @param epilogue Additional text for \code{print_help} to print out after 124 | #' the options statement 125 | #' @param formatter A function that formats usage text. 126 | #' The function should take only one argument (an `OptionParser()` object). 127 | #' Default is [IndentedHelpFormatter()]. 128 | #' The other builtin formatter provided by this package is [TitledHelpFormatter()]. 129 | #' @return An instance of the \code{OptionParser} class. 130 | #' @author Trevor Davis. 131 | #' 132 | #' @seealso \code{\link{parse_args}} \code{\link{make_option}} 133 | #' \code{\link{add_option}} 134 | #' @references Python's \code{optparse} library, which inspired this package, 135 | #' is described here: \url{https://docs.python.org/3/library/optparse.html} 136 | #' @import getopt 137 | #' @export 138 | OptionParser <- function(usage = "usage: %prog [options]", option_list = list(), # nolint 139 | add_help_option = TRUE, prog = NULL, 140 | description = "", epilogue = "", 141 | formatter = IndentedHelpFormatter) { 142 | 143 | if (is.null(prog)) { 144 | prog <- get_Rscript_filename() 145 | } 146 | if (length(prog) && !is.na(prog)) { 147 | usage <- gsub("%prog", prog, usage) 148 | description <- gsub("%prog", prog, description) 149 | epilogue <- gsub("%prog", prog, epilogue) 150 | } 151 | # Match behavior of usage string in Python optparse package 152 | usage <- sub("^usage: ", "Usage: ", usage) 153 | usage <- ifelse(grepl("^Usage: ", usage), usage, sub("^", "Usage: ", usage)) 154 | if (add_help_option) { 155 | option_list[[length(option_list) + 1]] <- 156 | make_option(c("-h", "--help"), 157 | action = "store_true", dest = "help", default = FALSE, 158 | help = "Show this help message and exit") 159 | } 160 | 161 | return(new("OptionParser", usage = usage, options = option_list, 162 | description = description, epilogue = epilogue, 163 | formatter = formatter)) 164 | } 165 | 166 | #' Functions to enable our OptionParser to recognize specific command line 167 | #' options. 168 | #' 169 | #' \code{add_option} adds a option to a prexisting \code{OptionParser} instance 170 | #' whereas \code{make_option} is used to create a list of 171 | #' \code{OptionParserOption} instances that will be used in the 172 | #' \code{option_list} argument of the \code{OptionParser} function to create a 173 | #' new \code{OptionParser} instance. 174 | #' 175 | #' @rdname add_make_option 176 | #' @param object An instance of the \code{OptionParser} class 177 | #' @param opt_str A character vector containing the string of the desired long 178 | #' flag comprised of \dQuote{--} followed by a letter and then a sequence of 179 | #' alphanumeric characters and optionally a string of the desired short flag 180 | #' comprised of the \dQuote{-} followed by a letter. 181 | #' @param action A character string that describes the action \code{optparse} 182 | #' should take when it encounters an option, either \dQuote{store}, 183 | #' \dQuote{store_true}, \dQuote{store_false}, or \dQuote{callback}. 184 | #' An action of \dQuote{store} signifies that \code{optparse} 185 | #' should store the specified following value if the option is found on the command string. 186 | #' \dQuote{store_true} stores \code{TRUE} if the option is found 187 | #' and \dQuote{store_false} stores \code{FALSE} if the option is found. 188 | #' \dQuote{callback} stores the return value produced by the function 189 | #' specified in the \code{callback} argument. 190 | #' If \code{callback} is not \code{NULL} then the default is \dQuote{callback} else \dQuote{store}. 191 | #' @param type A character string that describes specifies which data type 192 | #' should be stored, either \dQuote{logical}, \dQuote{integer}, \dQuote{double}, 193 | #' \dQuote{complex}, or \dQuote{character}. Default is \dQuote{logical} if 194 | #' \code{action \%in\% c("store_true", store_false)}, \code{typeof(default)} if 195 | #' \code{action == "store"} and default is not \code{NULL} and 196 | #' \dQuote{character} if \code{action == "store"} and default is \code{NULL}. 197 | #' \dQuote{numeric} will be converted to \dQuote{double}. 198 | #' @param dest A character string that specifies what field in the list returned 199 | #' by \code{parse_args} should \code{optparse} store option values. Default is 200 | #' derived from the long flag in \code{opt_str}. 201 | #' @param default The default value \code{optparse} should use if it does not 202 | #' find the option on the command line. 203 | #' @param help A character string describing the option to be used by 204 | #' \code{print_help} in generating a usage message. \code{\%default} will be 205 | #' substituted by the value of \code{default}. 206 | #' @param metavar A character string that stands in for the option argument when 207 | #' printing help text. Default is the value of \code{dest}. 208 | #' @param callback A function that executes after the each option value is fully 209 | #' parsed. It's value is assigned to the option and its arguments are 210 | #' the option S4 object, the long flag string, the value of the option, 211 | #' the parser S4 object, and \code{...}. 212 | #' @param callback_args A list of additional arguments passed to callback function (via \code{do.call}). 213 | #' @return Both \code{make_option} and \code{add_option} return instances of 214 | #' class \code{OptionParserOption}. 215 | #' @author Trevor Davis. 216 | #' 217 | #' @seealso \code{\link{parse_args}} \code{\link{OptionParser}} 218 | #' @references Python's \code{optparse} library, which inspires this package, 219 | #' is described here: \url{https://docs.python.org/3/library/optparse.html} 220 | #' @examples 221 | #' 222 | #' make_option("--longflag") 223 | #' make_option(c("-l", "--longflag")) 224 | #' make_option("--integer", type = "integer", default = 5) 225 | #' make_option("--integer", default = as.integer(5)) # same as previous 226 | #' 227 | #' # examples from package vignette 228 | #' make_option(c("-v", "--verbose"), action = "store_true", default = TRUE, 229 | #' help = "Print extra output [default]") 230 | #' make_option(c("-q", "--quietly"), action = "store_false", 231 | #' dest = "verbose", help = "Print little output") 232 | #' make_option(c("-c", "--count"), type = "integer", default = 5, 233 | #' help = "Number of random normals to generate [default %default]", 234 | #' metavar = "number") 235 | #' make_option("--generator", default = "rnorm", 236 | #' help = "Function to generate random deviates [default \"%default\"]") 237 | #' make_option("--mean", default = 0, 238 | #' help = "Mean if generator == \"rnorm\" [default %default]") 239 | #' make_option("--sd", default = 1, metavar = "standard deviation", 240 | #' help = "Standard deviation if generator == \"rnorm\" [default %default]") 241 | #' 242 | #' @export 243 | make_option <- function(opt_str, action = NULL, type = NULL, dest = NULL, default = NULL, 244 | help = "", metavar = NULL, callback = NULL, callback_args = NULL) { 245 | 246 | action <- ifelse(is.null(action), ifelse(is.null(callback), "store", "callback"), action) 247 | 248 | # flags 249 | short_flag <- opt_str[grepl("^-[[:alpha:]]", opt_str)] 250 | if (length(short_flag) == 0) { 251 | short_flag <- NA_character_ 252 | } else { 253 | if (nchar(short_flag) > 2) { 254 | stop(paste("Short flag", short_flag, "must only be a '-' and a single letter")) 255 | } 256 | } 257 | long_flag <- opt_str[grepl("^--[[:alpha:]]", opt_str)] 258 | if (length(long_flag) == 0) stop("We require a long flag option") 259 | 260 | # type 261 | if (is.null(type)) { 262 | type <- infer_type(action, default) 263 | } 264 | if (type == "numeric") type <- "double" 265 | 266 | # default 267 | if ((action != "callback") && 268 | (type != typeof(default)) && 269 | !is.null(default)) { 270 | storage.mode(default) <- type 271 | } 272 | 273 | # dest 274 | if (is.null(dest)) dest <- sub("^--", "", long_flag) 275 | 276 | # metavar 277 | if (is.null(metavar)) { 278 | if (option_needs_argument_helper(action, type)) { 279 | metavar <- sub("^--", "", long_flag) 280 | } else { 281 | metavar <- character(0) 282 | } 283 | } 284 | warn_callback(action, callback, callback_args) 285 | if (is.null(callback_args)) 286 | callback_args <- list() 287 | 288 | return(new("OptionParserOption", short_flag = short_flag, long_flag = long_flag, 289 | action = action, type = type, dest = dest, default = default, 290 | help = help, metavar = metavar, 291 | callback = callback, callback_args = callback_args)) 292 | } 293 | 294 | infer_type <- function(action, default) { 295 | switch(action, 296 | store = ifelse(is.null(default), "character", typeof(default)), 297 | store_false = "logical", 298 | store_true = "logical", 299 | callback = "NULL") 300 | } 301 | 302 | warn_callback <- function(action, callback, callback_args) { 303 | if (action == "callback") { 304 | if (!is.function(callback)) 305 | warning(sprintf("callback argument is not a function")) 306 | } else { 307 | if (!is.null(callback)) 308 | warning(sprintf("callback argument is supplied for non-callback action")) 309 | if (!is.null(callback_args)) 310 | warning(sprintf("callback_args argument is supplied for non-callback action")) 311 | } 312 | } 313 | 314 | #' @rdname add_make_option 315 | #' @export 316 | add_option <- function(object, opt_str, action = NULL, type = NULL, 317 | dest = NULL, default = NULL, help = "", metavar = NULL, 318 | callback = NULL, callback_args = NULL) { 319 | options_list <- object@options 320 | n_original_options <- length(options_list) 321 | options_list[[n_original_options + 1]] <- make_option(opt_str = opt_str, 322 | action = action, type = type, dest = dest, 323 | default = default, help = help, metavar = metavar, 324 | callback = callback, callback_args = callback_args) 325 | object@options <- options_list 326 | return(object) 327 | } 328 | 329 | #' Printing an usage message from an OptionParser object 330 | #' 331 | #' \code{print_help} print an usage message from an OptionParser object, usually 332 | #' called by \code{parse_args} when it encounters a help option. 333 | #' 334 | #' @param object A \code{OptionParser} instance. 335 | #' @return \code{print_help} uses the \code{cat} function to print out a usage 336 | #' message. It returns \code{invisible(NULL)}. 337 | #' @author Trevor Davis. 338 | #' 339 | #' @seealso \code{{parse_args}} \code{{OptionParser}} 340 | #' @references Python's \code{optparse} library, which inspired this package, 341 | #' is described here: \url{https://docs.python.org/3/library/optparse.html} 342 | #' @export 343 | print_help <- function(object) { 344 | object@formatter(object) 345 | } 346 | 347 | #' Builtin help text formatters 348 | #' 349 | #' `IndentedHelpFormatter()` is the default help text formatter. 350 | #' `TitledHelpFormatter()` is an alternative help text formatter. 351 | #' 352 | #' @param object An [OptionParser()] object. 353 | #' @examples 354 | #' parser <- OptionParser(formatter = IndentedHelpFormatter) 355 | #' parser <- add_option(parser, "--generator", help = "Generator option") 356 | #' parser <- add_option(parser, "--count", help = "Count option") 357 | #' print_help(parser) 358 | #' 359 | #' parser <- OptionParser(formatter = TitledHelpFormatter) 360 | #' parser <- add_option(parser, "--generator", help = "Generator option") 361 | #' parser <- add_option(parser, "--count", help = "Count option") 362 | #' print_help(parser) 363 | #' @return `NULL` invisibly. As a side effect prints out help text. 364 | #' @rdname formatter 365 | #' @export 366 | IndentedHelpFormatter <- function(object) { # nolint 367 | cat(object@usage, fill = TRUE) 368 | cat(object@description, fill = TRUE) 369 | cat("\n") 370 | cat("Options:", sep = "\n") 371 | 372 | options_list <- object@options 373 | for (ii in seq_along(options_list)) { 374 | option <- options_list[[ii]] 375 | cat("\t") 376 | if (!is.na(option@short_flag)) { 377 | cat(option@short_flag) 378 | if (option_needs_argument(option)) { 379 | cat(" ", toupper(option@metavar), sep = "") 380 | } 381 | cat(", ") 382 | } 383 | if (!is.null(option@long_flag)) { 384 | cat(option@long_flag) 385 | if (option_needs_argument(option)) { 386 | cat("=", toupper(option@metavar), sep = "") 387 | } 388 | } 389 | cat("\n\t\t") 390 | cat(sub("%default", as_string(option@default), option@help)) 391 | cat("\n\n") 392 | } 393 | cat(object@epilogue, fill = TRUE) 394 | return(invisible(NULL)) 395 | } 396 | 397 | #' @rdname formatter 398 | #' @export 399 | TitledHelpFormatter <- function(object) { # nolint 400 | usage <- c("Usage\n=====\n", gsub("Usage: ", "", object@usage)) 401 | cat(usage, fill = TRUE) 402 | cat(object@description, fill = TRUE) 403 | cat("\n") 404 | cat("Options", "=======", sep = "\n") 405 | 406 | options_list <- object@options 407 | for (ii in seq_along(options_list)) { 408 | option <- options_list[[ii]] 409 | if (!is.null(option@long_flag)) { 410 | cat(option@long_flag) 411 | if (option_needs_argument(option)) { 412 | cat("=", toupper(option@metavar), sep = "") 413 | } 414 | } 415 | if (!is.na(option@short_flag)) { 416 | cat(", ") 417 | cat(option@short_flag) 418 | if (option_needs_argument(option)) { 419 | cat(" ", toupper(option@metavar), sep = "") 420 | } 421 | } 422 | cat("\n\t\t") 423 | cat(sub("%default", as_string(option@default), option@help)) 424 | cat("\n\n") 425 | } 426 | cat(object@epilogue, fill = TRUE) 427 | return(invisible(NULL)) 428 | } 429 | 430 | # Turn default values into a string we can cat, handles NA's and NULL's 431 | as_string <- function(default) { 432 | if (is.null(default)) { 433 | default_str <- "NULL" 434 | } else if (!length(default)) { 435 | default_str <- paste0(typeof(default), "(0)") 436 | } else if (is.na(default)) { 437 | default_str <- "NA" 438 | } else { 439 | default_str <- as.character(default) 440 | } 441 | } 442 | 443 | #' Parse command line options. 444 | #' 445 | #' \code{parse_args} parses command line options using an \code{OptionParser} 446 | #' instance for guidance. \code{parse_args2} is a wrapper to \code{parse_args} 447 | #' setting the options \code{positional_arguments} and \code{convert_hyphens_to_underscores} 448 | #' to \code{TRUE}. 449 | #' 450 | #' @param object An \code{OptionParser} instance. 451 | #' @param args A character vector containing command line options to be parsed. 452 | #' Default is everything after the Rscript program in the command line. If 453 | #' \code{positional_arguments} is not \code{FALSE} then \code{parse_args} will 454 | #' look for positional arguments at the end of this vector. 455 | #' @param print_help_and_exit Whether \code{parse_args} should call 456 | #' \code{print_help} to print out a usage message and exit the program. Default 457 | #' is \code{TRUE}. 458 | #' @param positional_arguments Number of \emph{positional} arguments. A numeric 459 | #' denoting the exact number of supported arguments, or a numeric vector of 460 | #' length two denoting the minimum and maximum number of arguments 461 | #' (\code{Inf} for no limit). The value \code{TRUE} is equivalent to 462 | #' \code{c(0, Inf)}. The default \code{FALSE} is 463 | #' supported for backward compatibility only, as it alters 464 | #' the format of the return value. 465 | #' @param convert_hyphens_to_underscores If the names in the returned list of options 466 | #' contains hyphens then convert them to underscores. The default \code{FALSE} is 467 | #' supported for backward compatibility reasons as it alters the format of the return value 468 | #' @return Returns a list with field \code{options} containing our option values 469 | #' as well as another field \code{args} which contains a vector of 470 | #' positional arguments. For backward compatibility, if and only if 471 | #' \code{positional_arguments} is \code{FALSE}, returns a list containing 472 | #' option values. 473 | #' @section Acknowledgement: 474 | #' A big thanks to Steve Lianoglou for a bug report and patch; 475 | #' Juan Carlos \enc{Borrás}{Borras} for a bug report; 476 | #' Jim Nikelski for a bug report and patch; 477 | #' Ino de Brujin and Benjamin Tyner for a bug report; 478 | #' Jonas Zimmermann for bug report; Miroslav Posta for bug reports; 479 | #' Stefan Seemayer for bug report and patch; 480 | #' Kirill \enc{Müller}{Muller} for patches; Steve Humburg for patch. 481 | #' @author Trevor Davis. 482 | #' 483 | #' @seealso \code{\link{OptionParser}} \code{\link{print_help}} 484 | #' @references Python's \code{optparse} library, which inspired this package, 485 | #' is described here: \url{https://docs.python.org/3/library/optparse.html} 486 | #' @encoding latin1 487 | #' @examples 488 | #' # example from vignette 489 | #' option_list <- list( 490 | #' make_option(c("-v", "--verbose"), action = "store_true", default = TRUE, 491 | #' help = "Print extra output [default]"), 492 | #' make_option(c("-q", "--quietly"), action = "store_false", 493 | #' dest = "verbose", help = "Print little output"), 494 | #' make_option(c("-c", "--count"), type = "integer", default = 5, 495 | #' help = "Number of random normals to generate [default %default]", 496 | #' metavar = "number"), 497 | #' make_option("--generator", default = "rnorm", 498 | #' help = "Function to generate random deviates [default \"%default\"]"), 499 | #' make_option("--mean", default = 0, 500 | #' help = "Mean if generator == \"rnorm\" [default %default]"), 501 | #' make_option("--sd", default = 1, metavar = "standard deviation", 502 | #' help = "Standard deviation if generator == \"rnorm\" [default %default]") 503 | #' ) 504 | #'parse_args(OptionParser(option_list = option_list), args = c("--sd=3", "--quietly")) 505 | #' 506 | #'# example from vignette using positional arguments 507 | #'option_list2 <- list( 508 | #' make_option(c("-n", "--add-numbers"), action = "store_true", default = FALSE, 509 | #' help = "Print line number at the beginning of each line [default]") 510 | #' ) 511 | #'parser <- OptionParser(usage = "%prog [options] file", option_list = option_list2) 512 | #' 513 | #'parse_args(parser, args = c("--add-numbers", "example.txt"), positional_arguments = TRUE) 514 | #' 515 | #'parse_args(parser, args = c("--add-numbers", "example.txt"), positional_arguments = TRUE, 516 | #' convert_hyphens_to_underscores = TRUE) 517 | #' 518 | #'parse_args2(parser, args = c("--add-numbers", "example.txt")) 519 | #' 520 | #' @import getopt 521 | #' @importFrom utils tail 522 | #' @export 523 | parse_args <- function(object, args = commandArgs(trailingOnly = TRUE), 524 | print_help_and_exit = TRUE, positional_arguments = FALSE, 525 | convert_hyphens_to_underscores = FALSE) { 526 | 527 | tryCatch(parse_args_helper(object, args, 528 | print_help_and_exit, positional_arguments, 529 | convert_hyphens_to_underscores), 530 | error = function(e) pa_stop(object, e)) 531 | } 532 | 533 | quieter_error_handler <- function(e) { 534 | quit('no', status = 1, runLast = FALSE) 535 | } 536 | 537 | pa_stop <- function(object, e) { 538 | cnd <- errorCondition(e$message, 539 | call = "optparse::parse_args_helper()", 540 | class = "optparse_parse_error") 541 | if (interactive()) { 542 | stop(cnd) 543 | } else { 544 | signalCondition(cnd) 545 | msg <- paste0("\n", get_Rscript_filename(), ": error: ", e$message) 546 | cat(object@usage, msg, sep = "\n", file = stderr()) 547 | opt <- options(error = getOption("error", quieter_error_handler), 548 | show.error.messages = FALSE) 549 | on.exit(options(opt)) 550 | stop(cnd) 551 | } 552 | } 553 | 554 | parse_args_helper <- function(object, args = commandArgs(trailingOnly = TRUE), 555 | print_help_and_exit = TRUE, positional_arguments = FALSE, 556 | convert_hyphens_to_underscores = FALSE) { 557 | 558 | pal <- should_include_any_args(positional_arguments) 559 | include_any_args <- pal$include_any_args 560 | positional_arguments <- pal$positional_arguments 561 | 562 | pal <- parse_positional_args(object, args, positional_arguments) 563 | arguments_positional <- pal$arguments_positional 564 | args <- pal$args 565 | 566 | options_list <- parse_options(object, args, convert_hyphens_to_underscores) 567 | 568 | if (any(grepl("^help$", names(options_list)))) { 569 | if (options_list[["help"]] && print_help_and_exit) { 570 | print_help(object) 571 | if (interactive()) 572 | stop("help requested") 573 | else 574 | quit(status = 0) 575 | } 576 | } 577 | 578 | if (length(arguments_positional) < min(positional_arguments)) { 579 | stop(sprintf("required at least %g positional arguments, got %g", 580 | min(positional_arguments), length(arguments_positional))) 581 | } 582 | if (length(arguments_positional) > max(positional_arguments)) { 583 | stop(sprintf("required at most %g positional arguments, got %g", 584 | max(positional_arguments), length(arguments_positional))) 585 | } 586 | if (include_any_args) { 587 | return(list(options = options_list, args = arguments_positional)) 588 | } else { 589 | return(options_list) 590 | } 591 | } 592 | 593 | 594 | getopt_options <- function(object, args) { 595 | # Convert our option specification into ``getopt`` format 596 | n_options <- length(object@options) 597 | spec <- matrix(NA, nrow = n_options, ncol = 5) 598 | for (ii in seq_along(object@options)) { 599 | spec[ii, ] <- convert_to_getopt(object@options[[ii]]) 600 | } 601 | 602 | if (length(args)) { 603 | opt <- try(getopt(spec = spec, opt = args), silent = TRUE) 604 | if (inherits(opt, "try-error")) { 605 | if (grepl("redundant short names for flags", opt)) { 606 | opt <- paste(opt, "did you forget to set ``add_help_option=FALSE`` in ``OptionParser``") 607 | } 608 | stop(opt) 609 | } 610 | } else { 611 | opt <- list() 612 | } 613 | opt 614 | } 615 | 616 | should_include_any_args <- function(positional_arguments) { 617 | # pull out positional arguments if ``positional_arguments`` was set to TRUE 618 | # or not 0 or c(0, 0) 619 | if (!(length(positional_arguments) %in% 1L:2L)) 620 | stop("positional_arguments must have length 1 or 2") 621 | if (is.logical(positional_arguments)) { 622 | if (positional_arguments) { 623 | positional_arguments <- c(0, Inf) 624 | include_any_args <- TRUE 625 | } else { 626 | include_any_args <- FALSE 627 | } 628 | } else if (is.numeric(positional_arguments)) { 629 | include_any_args <- TRUE 630 | } else { 631 | stop("positional_arguments must be logical or numeric") 632 | } 633 | list(include_any_args = include_any_args, 634 | positional_arguments = positional_arguments) 635 | } 636 | 637 | parse_positional_args <- function(object, args, positional_arguments) { 638 | arguments_positional <- character(0) 639 | if (max(positional_arguments) > 0) { 640 | original_arguments <- args 641 | args <- NULL 642 | is_taken <- FALSE # set to true if optional argument needs to take next argument 643 | for (argument in original_arguments) { 644 | if (is_taken) { 645 | args <- c(args, argument) 646 | is_taken <- FALSE 647 | } else { 648 | if (is_option_string(argument, object)) { 649 | args <- c(args, argument) 650 | if (requires_argument(argument, object)) 651 | is_taken <- TRUE 652 | } else { 653 | arguments_positional <- c(arguments_positional, argument) 654 | } 655 | } 656 | } 657 | } 658 | list(arguments_positional = arguments_positional, args = args) 659 | } 660 | 661 | parse_options <- function(object, args, convert_hyphens_to_underscores) { 662 | 663 | opt <- getopt_options(object, args) 664 | 665 | options_list <- list() 666 | for (ii in seq_along(object@options)) { 667 | option <- object@options[[ii]] 668 | option_value <- opt[[sub("^--", "", option@long_flag)]] 669 | if (!is.null(option_value)) { 670 | if (option@action == "store_false") { 671 | options_list[[option@dest]] <- FALSE 672 | } else { 673 | options_list[[option@dest]] <- option_value 674 | } 675 | if (option@action == "callback") { 676 | callback_fn <- function(...) { 677 | option@callback(option, option@long_flag, option_value, object, ...) # nolint 678 | } 679 | options_list[[option@dest]] <- do.call(callback_fn, option@callback_args) 680 | } 681 | } else { 682 | if (!is.null(option@default) && is.null(options_list[[option@dest]])) { 683 | options_list[[option@dest]] <- option@default 684 | } 685 | } 686 | } 687 | if (convert_hyphens_to_underscores) { 688 | names(options_list) <- gsub("-", "_", names(options_list)) 689 | } 690 | options_list 691 | } 692 | 693 | #' @rdname parse_args 694 | #' @export 695 | parse_args2 <- function(object, args = commandArgs(trailingOnly = TRUE), 696 | print_help_and_exit = TRUE) { 697 | parse_args(object, args = args, print_help_and_exit = print_help_and_exit, 698 | positional_arguments = TRUE, convert_hyphens_to_underscores = TRUE) 699 | } 700 | 701 | # Tells me whether a string is a valid option 702 | is_option_string <- function(argument, object) { 703 | if (is_long_flag(argument)) { 704 | return(TRUE) 705 | } else if (is_short_flag(argument)) { 706 | return(TRUE) 707 | } else { 708 | return(FALSE) 709 | } 710 | } 711 | # Tells me if an option string needs to take an argument 712 | requires_argument <- function(argument, object) { 713 | if (is_long_flag(argument)) { 714 | requires_long_flag(argument, object) 715 | } else { # is a short flag 716 | requires_short_flag(argument, object) 717 | } 718 | } 719 | 720 | requires_long_flag <- function(argument, object) { 721 | if (grepl("=", argument)) { 722 | return(FALSE) 723 | } else { 724 | for (ii in seq_along(object@options)) { 725 | option <- object@options[[ii]] 726 | if (option@long_flag == argument) 727 | return(option_needs_argument(option)) 728 | } 729 | stop(paste("no such option:", argument)) 730 | } 731 | } 732 | 733 | requires_short_flag <- function(argument, object) { 734 | last_flag <- tail(expand_short_option(argument), 1) 735 | for (ii in seq_along(object@options)) { 736 | option <- object@options[[ii]] 737 | if (!is.na(option@short_flag) && option@short_flag == last_flag) 738 | return(option_needs_argument(option)) 739 | } 740 | stop(paste("no such option:", last_flag)) 741 | } 742 | 743 | 744 | # convenience functions that tells if argument is a type of flag and returns all long flag options or short flag options 745 | is_long_flag <- function(argument) return(grepl("^--", argument)) 746 | is_short_flag <- function(argument) return(grepl("^-[^-]", argument)) 747 | # expand_short_option based on function by Jim Nikelski (c) 2011 748 | # He gave me a non-exclusive unlimited license to this code 749 | # expand_short_option("-cde") = c("-c", "-d", "-e") # nolint 750 | expand_short_option <- function(argument) { 751 | if (nchar(argument) == 2) { 752 | return(argument) 753 | } else { 754 | argument <- substr(argument, 2, nchar(argument)) # remove leading dash 755 | argument <- strsplit(argument, "")[[1]] # split into individual characters 756 | argument <- paste("-", argument, sep = "") # add leading dash to each short option 757 | return(argument) 758 | } 759 | } 760 | 761 | # Converts our representation of options to format getopt can understand 762 | convert_to_getopt <- function(object) { 763 | short_flag <- sub("^-", "", object@short_flag) 764 | long_flag <- sub("^--", "", object@long_flag) 765 | argument <- ifelse(option_needs_argument(object), 1, 0) 766 | type <- ifelse(object@type == "NULL", "logical", object@type) 767 | return(c(long_flag, short_flag, argument, type, object@help)) 768 | } 769 | option_needs_argument <- function(option) { 770 | option_needs_argument_helper(option@action, option@type) 771 | } 772 | option_needs_argument_helper <- function(action, type) { 773 | switch(action, 774 | store = TRUE, 775 | callback = ifelse(type == "NULL", FALSE, TRUE), 776 | FALSE) 777 | } 778 | -------------------------------------------------------------------------------- /README.Rrst: -------------------------------------------------------------------------------- 1 | optparse: Command line optional argument parser 2 | =============================================== 3 | 4 | .. image:: https://www.r-pkg.org/badges/version/optparse 5 | :target: https://cran.r-project.org/package=optparse 6 | :alt: CRAN Status Badge 7 | 8 | .. image:: https://github.com/trevorld/r-optparse/workflows/R-CMD-check/badge.svg 9 | :target: https://github.com/trevorld/r-optparse/actions 10 | :alt: R-CMD-check 11 | 12 | .. image:: https://codecov.io/github/trevorld/r-optparse/branch/master/graph/badge.svg 13 | :target: https://app.codecov.io/github/trevorld/r-optparse?branch=master 14 | :alt: Coverage Status 15 | 16 | .. image:: https://cranlogs.r-pkg.org/badges/optparse 17 | :target: https://cran.r-project.org/package=optparse 18 | :alt: RStudio CRAN mirror downloads 19 | 20 | .. raw:: html 21 | 22 | optparse hex sticker 23 | 24 | A pure R language command line parser inspired by Python's 'optparse' library to 25 | be used with Rscript to write "#!" shebang scripts that accept short and 26 | long flag/options. 27 | 28 | To install the last version released on CRAN use the following command: 29 | 30 | .. code:: r 31 | 32 | install.packages("optparse") 33 | 34 | To install the development version use the following command: 35 | 36 | .. code:: r 37 | 38 | install.packages("remotes") 39 | remotes::install_github("trevorld/r-optparse") 40 | 41 | dependencies 42 | ------------ 43 | 44 | This package depends on the R package ``getopt``. 45 | 46 | To run the unit tests you will need the suggested R package ``testthat`` and in 47 | order to build the vignette you will need the suggested R package ``knitr`` 48 | which in turn probably requires the system tool ``pandoc``: 49 | 50 | .. code:: bash 51 | 52 | sudo apt install pandoc 53 | 54 | examples 55 | -------- 56 | 57 | A simple example: 58 | 59 | .. {r simple_example} 60 | 61 | library("optparse") 62 | parser <- OptionParser() 63 | parser <- add_option(parser, c("-v", "--verbose"), action="store_true", 64 | default=TRUE, help="Print extra output [default]") 65 | parser <- add_option(parser, c("-q", "--quietly"), action="store_false", 66 | dest="verbose", help="Print little output") 67 | parser <- add_option(parser, c("-c", "--count"), type="integer", default=5, 68 | help="Number of random normals to generate [default %default]", 69 | metavar="number") 70 | parse_args(parser, args = c("--quietly", "--count=15")) 71 | .. .. 72 | 73 | 74 | Note that the ``args`` argument of ``parse_args`` default is ``commandArgs(trailing=TRUE)`` 75 | so it typically doesn't need to be explicitly set if writing an Rscript. 76 | 77 | One can also equivalently make options in a list: 78 | 79 | .. {r list_example} 80 | library("optparse") 81 | option_list <- list( 82 | make_option(c("-v", "--verbose"), action="store_true", default=TRUE, 83 | help="Print extra output [default]"), 84 | make_option(c("-q", "--quietly"), action="store_false", 85 | dest="verbose", help="Print little output"), 86 | make_option(c("-c", "--count"), type="integer", default=5, 87 | help="Number of random normals to generate [default %default]", 88 | metavar="number") 89 | ) 90 | 91 | parse_args(OptionParser(option_list=option_list), args = c("--verbose", "--count=11")) 92 | .. .. 93 | 94 | ``optparse`` automatically creates a help option: 95 | 96 | .. code:: r 97 | 98 | parse_args(parser, args = c("--help")) 99 | 100 | :: 101 | 102 | Usage: %prog [options] 103 | 104 | 105 | Options: 106 | -h, --help 107 | Show this help message and exit 108 | 109 | -v, --verbose 110 | Print extra output [default] 111 | 112 | -q, --quietly 113 | Print little output 114 | 115 | -c NUMBER, --count=NUMBER 116 | Number of random normals to generate [default 5] 117 | 118 | 119 | Error in parse_args(parser, args = c("--help")) : help requested 120 | 121 | Note by default when ``optparse::parse_args`` sees a ``--help`` flag it will first print out a usage message and then either throw an error in interactive use or call ``quit`` in non-interactive use (i.e. when used within an Rscript called by a shell). To disable the error/quit set the argument ``print_help_and_exit`` to ``FALSE`` in ``parse_args`` and to simply print out the usage string one can also use the function ``print_usage``. 122 | 123 | ``optparse`` has limited positional argument support, other command-line parsers for R such as ``argparse`` 124 | have richer positional argument support: 125 | 126 | .. {r positional_example} 127 | parse_args(parser, args = c("-vc", "25", "75", "22"), positional_arguments = TRUE) 128 | .. .. 129 | 130 | The function ``parse_args2`` wraps ``parse_args`` while setting ``positional_arguments=TRUE`` and ``convert_hyphens_to_underscores=TRUE``: 131 | 132 | .. {r parse_args2} 133 | 134 | parse_args2(parser, args = c("-vc", "25", "75", "22")) 135 | .. .. 136 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | optparse: Command line optional argument parser 2 | =============================================== 3 | 4 | .. image:: https://www.r-pkg.org/badges/version/optparse 5 | :target: https://cran.r-project.org/package=optparse 6 | :alt: CRAN Status Badge 7 | 8 | .. image:: https://github.com/trevorld/r-optparse/workflows/R-CMD-check/badge.svg 9 | :target: https://github.com/trevorld/r-optparse/actions 10 | :alt: R-CMD-check 11 | 12 | .. image:: https://codecov.io/github/trevorld/r-optparse/branch/master/graph/badge.svg 13 | :target: https://app.codecov.io/github/trevorld/r-optparse?branch=master 14 | :alt: Coverage Status 15 | 16 | .. image:: https://cranlogs.r-pkg.org/badges/optparse 17 | :target: https://cran.r-project.org/package=optparse 18 | :alt: RStudio CRAN mirror downloads 19 | 20 | .. raw:: html 21 | 22 | optparse hex sticker 23 | 24 | A pure R language command line parser inspired by Python's 'optparse' library to 25 | be used with Rscript to write "#!" shebang scripts that accept short and 26 | long flag/options. 27 | 28 | To install the last version released on CRAN use the following command: 29 | 30 | .. code:: r 31 | 32 | install.packages("optparse") 33 | 34 | To install the development version use the following command: 35 | 36 | .. code:: r 37 | 38 | install.packages("remotes") 39 | remotes::install_github("trevorld/r-optparse") 40 | 41 | dependencies 42 | ------------ 43 | 44 | This package depends on the R package ``getopt``. 45 | 46 | To run the unit tests you will need the suggested R package ``testthat`` and in 47 | order to build the vignette you will need the suggested R package ``knitr`` 48 | which in turn probably requires the system tool ``pandoc``: 49 | 50 | .. code:: bash 51 | 52 | sudo apt install pandoc 53 | 54 | examples 55 | -------- 56 | 57 | A simple example: 58 | 59 | 60 | .. code:: r 61 | 62 | 63 | library("optparse") 64 | parser <- OptionParser() 65 | parser <- add_option(parser, c("-v", "--verbose"), action="store_true", 66 | default=TRUE, help="Print extra output [default]") 67 | parser <- add_option(parser, c("-q", "--quietly"), action="store_false", 68 | dest="verbose", help="Print little output") 69 | parser <- add_option(parser, c("-c", "--count"), type="integer", default=5, 70 | help="Number of random normals to generate [default %default]", 71 | metavar="number") 72 | parse_args(parser, args = c("--quietly", "--count=15")) 73 | 74 | 75 | :: 76 | 77 | ## $help 78 | ## [1] FALSE 79 | ## 80 | ## $verbose 81 | ## [1] FALSE 82 | ## 83 | ## $count 84 | ## [1] 15 85 | 86 | 87 | 88 | 89 | Note that the ``args`` argument of ``parse_args`` default is ``commandArgs(trailing=TRUE)`` 90 | so it typically doesn't need to be explicitly set if writing an Rscript. 91 | 92 | One can also equivalently make options in a list: 93 | 94 | 95 | .. code:: r 96 | 97 | 98 | library("optparse") 99 | option_list <- list( 100 | make_option(c("-v", "--verbose"), action="store_true", default=TRUE, 101 | help="Print extra output [default]"), 102 | make_option(c("-q", "--quietly"), action="store_false", 103 | dest="verbose", help="Print little output"), 104 | make_option(c("-c", "--count"), type="integer", default=5, 105 | help="Number of random normals to generate [default %default]", 106 | metavar="number") 107 | ) 108 | 109 | parse_args(OptionParser(option_list=option_list), args = c("--verbose", "--count=11")) 110 | 111 | 112 | :: 113 | 114 | ## $verbose 115 | ## [1] TRUE 116 | ## 117 | ## $count 118 | ## [1] 11 119 | ## 120 | ## $help 121 | ## [1] FALSE 122 | 123 | 124 | 125 | ``optparse`` automatically creates a help option: 126 | 127 | .. code:: r 128 | 129 | parse_args(parser, args = c("--help")) 130 | 131 | :: 132 | 133 | Usage: %prog [options] 134 | 135 | 136 | Options: 137 | -h, --help 138 | Show this help message and exit 139 | 140 | -v, --verbose 141 | Print extra output [default] 142 | 143 | -q, --quietly 144 | Print little output 145 | 146 | -c NUMBER, --count=NUMBER 147 | Number of random normals to generate [default 5] 148 | 149 | 150 | Error in parse_args(parser, args = c("--help")) : help requested 151 | 152 | Note by default when ``optparse::parse_args`` sees a ``--help`` flag it will first print out a usage message and then either throw an error in interactive use or call ``quit`` in non-interactive use (i.e. when used within an Rscript called by a shell). To disable the error/quit set the argument ``print_help_and_exit`` to ``FALSE`` in ``parse_args`` and to simply print out the usage string one can also use the function ``print_usage``. 153 | 154 | ``optparse`` has limited positional argument support, other command-line parsers for R such as ``argparse`` 155 | have richer positional argument support: 156 | 157 | 158 | .. code:: r 159 | 160 | 161 | parse_args(parser, args = c("-vc", "25", "75", "22"), positional_arguments = TRUE) 162 | 163 | 164 | :: 165 | 166 | ## $options 167 | ## $options$help 168 | ## [1] FALSE 169 | ## 170 | ## $options$verbose 171 | ## [1] TRUE 172 | ## 173 | ## $options$count 174 | ## [1] 25 175 | ## 176 | ## 177 | ## $args 178 | ## [1] "75" "22" 179 | 180 | 181 | 182 | The function ``parse_args2`` wraps ``parse_args`` while setting ``positional_arguments=TRUE`` and ``convert_hyphens_to_underscores=TRUE``: 183 | 184 | 185 | .. code:: r 186 | 187 | 188 | parse_args2(parser, args = c("-vc", "25", "75", "22")) 189 | 190 | 191 | :: 192 | 193 | ## $options 194 | ## $options$help 195 | ## [1] FALSE 196 | ## 197 | ## $options$verbose 198 | ## [1] TRUE 199 | ## 200 | ## $options$count 201 | ## [1] 25 202 | ## 203 | ## 204 | ## $args 205 | ## [1] "75" "22" 206 | 207 | 208 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc "Build files for packaging" 2 | task :default do 3 | sh 'Rscript -e "devtools::document()"' 4 | sh 'Rscript -e "knitr::knit(\"README.Rrst\")"' 5 | sh 'rst2html README.rst README.html' 6 | sh 'pandoc -t markdown_strict -o README.md README.rst' 7 | sh 'Rscript -e "pkgdown::build_site()"' 8 | end 9 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | destination: "../../websites/R/optparse/" 2 | url: "https://trevorldavis.com/R/optparse" 3 | development: 4 | mode: auto 5 | -------------------------------------------------------------------------------- /cran-comments.rst: -------------------------------------------------------------------------------- 1 | **Test environments** 2 | 3 | * local (linux), R 4.3.3 4 | * win-builder (windows), R devel 5 | * Github Actions (linux), R devel and R release 6 | * Github Actions (OSX), R release 7 | * Github Actions (windows), R release 8 | 9 | **R CMD check --as-cran results** 10 | 11 | Status: OK 12 | 13 | **revdepcheck results** 14 | 15 | ## revdepcheck results 16 | 17 | We checked 15 reverse dependencies (7 from CRAN + 8 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 18 | 19 | * We saw 0 new problems 20 | * We failed to check 0 packages 21 | 22 | **Nota benes** 23 | 24 | * As in previous uploads while in a non-interactive session (i.e. in an 25 | Rscript) if `parse_args()` observes a help flag it will print a usage 26 | message and then call ``quit()`` unless the argument ``print_help_and_exit`` 27 | has been set ``FALSE``. 28 | -------------------------------------------------------------------------------- /exec/display_file.R: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | # Copyright 2010-2013 Trevor L Davis 3 | # Copyright 2013 Kirill Müller 4 | # 5 | # This file is free software: you may copy, redistribute and/or modify it 6 | # under the terms of the GNU General Public License as published by the 7 | # Free Software Foundation, either version 2 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # This file is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | suppressPackageStartupMessages(library("optparse")) 18 | 19 | option_list <- list( 20 | make_option(c("-n", "--add_numbers"), action="store_true", default=FALSE, 21 | help="Print line number at the beginning of each line [default]") 22 | ) 23 | parser <- OptionParser(usage = "%prog [options] file", option_list=option_list) 24 | 25 | arguments <- parse_args(parser, positional_arguments = 1) 26 | opt <- arguments$options 27 | file <- arguments$args 28 | 29 | if( file.access(file) == -1) { 30 | stop(sprintf("Specified file ( %s ) does not exist", file)) 31 | } else { 32 | file_text <- readLines(file) 33 | } 34 | 35 | if(opt$add_numbers) { 36 | cat(paste(1:length(file_text), file_text), sep = "\n") 37 | } else { 38 | cat(file_text, sep = "\n") 39 | } 40 | -------------------------------------------------------------------------------- /exec/example.R: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | # Copyright 2010-2013 Trevor L Davis 3 | # Copyright 2008 Allen Day 4 | # 5 | # This file is free software: you may copy, redistribute and/or modify it 6 | # under the terms of the GNU General Public License as published by the 7 | # Free Software Foundation, either version 2 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # This file is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | suppressPackageStartupMessages(library("optparse")) 18 | suppressPackageStartupMessages(library("stats")) 19 | 20 | # specify our desired options in a list 21 | # by default OptionParser will add an help option equivalent to 22 | # make_option(c("-h", "--help"), action="store_true", default=FALSE, 23 | # help="Show this help message and exit") 24 | option_list <- list( 25 | make_option(c("-v", "--verbose"), action="store_true", default=TRUE, 26 | help="Print extra output [default]"), 27 | make_option(c("-q", "--quietly"), action="store_false", 28 | dest="verbose", help="Print little output"), 29 | make_option(c("-c", "--count"), type="integer", default=5, 30 | help="Number of random normals to generate [default %default]", 31 | metavar="number"), 32 | make_option("--generator", default="rnorm", 33 | help = "Function to generate random deviates [default \"%default\"]"), 34 | make_option("--mean", default=0, 35 | help="Mean if generator == \"rnorm\" [default %default]"), 36 | make_option("--sd", default=1, metavar="standard deviation", 37 | help="Standard deviation if generator == \"rnorm\" [default %default]") 38 | ) 39 | 40 | # get command line options, if help option encountered print help and exit, 41 | # otherwise if options not found on command line then set defaults, 42 | opt <- parse_args(OptionParser(option_list=option_list)) 43 | 44 | # print some progress messages to stderr if "quietly" wasn't requested 45 | if ( opt$verbose ) { 46 | write("writing some verbose output to standard error...\n", stderr()) 47 | } 48 | 49 | # do some operations based on user input 50 | if( opt$generator == "rnorm") { 51 | cat(paste(rnorm(opt$count, mean=opt$mean, sd=opt$sd), collapse="\n")) 52 | } else { 53 | cat(paste(do.call(opt$generator, list(opt$count)), collapse="\n")) 54 | } 55 | cat("\n") 56 | -------------------------------------------------------------------------------- /inst/COPYRIGHTS: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | 3 | Files: * 4 | Copyright: 2010-2024 Trevor L Davis 5 | License: GPL-2+ 6 | 7 | File: exec/example.R 8 | Copyright: 2008 Allen Day 9 | 2010-2013 Trevor L Davis 10 | License: GPL-2+ 11 | 12 | File: exec/display_file.R 13 | Copyright: 2010-2013 Trevor L Davis 14 | 2013 Kirill Müller 15 | License: GPL-2+ 16 | 17 | File: NEWS.md 18 | Copyright: 2012-2022 Trevor L Davis 19 | 2013 Kirill Müller 20 | 21 | File: inst/tests/test-optparse.R 22 | Copyright: 2008 Allen Day 23 | 2010-2019 Trevor L Davis 24 | 2013 Kirill Müller 25 | 2015 Rich FitzJohn 26 | 2018 Gyu Jin Choi 27 | License: GPL-2+ 28 | 29 | File: R/optparse-package.R 30 | Copyright: 2008 Allen Day 31 | 2010-2013 Trevor L Davis 32 | License: GPL-2+ 33 | 34 | File: R/optparse.R 35 | Copyright: 1990-2009 Python Software Foundation 36 | 2011-2024 Trevor L Davis 37 | 2010 Steve Lianoglou 38 | 2011 Jim Nikelski 39 | 2013 Kirill Müller 40 | 2014 Peter Humburg 41 | 2015 Rich FitzJohn 42 | 2018 Gyu Jin Choi 43 | License: GPL-2+ and Python-2.6.2 44 | Comment: The FSF considers recent Python licenses (post Python version 2.1.1) to be 45 | GPL-compatible (http://www.gnu.org/licenses/license-list.html#Python). Note 46 | that the "Python License" the FSF has on their website 47 | (http://directory.fsf.org/wiki?title=License:Python2.0.1) is the full Python 48 | license stack which includes the historical modified CNRI and BEOPEN licenses 49 | and not merely the PSF License Agreement at the top. In 2001 ago the FSF 50 | negotiated with CNRI to change the wording of an earlier Python license 51 | (https://www.gnu.org/licenses/license-list.html#PythonOld, 52 | http://directory.fsf.org/wiki/License:Python1.6b1) because it had an overly 53 | strong "governed in Virginia" clause but later Python license stacks have a version 54 | of the CNRI license with a weakened enough clause to satisfy the FSF 55 | lawyers as being GPL-compatible. 56 | 57 | License: GPL-2+ 58 | This program is free software; you can redistribute it and/or modify it under 59 | the terms of the GNU General Public License as published by the Free Software 60 | Foundation; either version 2 of the License, or (at your option) any later 61 | version. 62 | . 63 | This program is distributed in the hope that it will be useful, but WITHOUT 64 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 65 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 66 | details. 67 | . 68 | You should have received a copy of the GNU General Public License along with 69 | this package; if not, write to the Free Software Foundation, Inc., 51 70 | Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 71 | . 72 | The full text of the GNU General Public License version 2 can be found in the 73 | file COPYING (source) or `R_HOME/share/licenses/GPL-2' (installed). 74 | 75 | License: Python-2.6.2 76 | PSF LICENSE AGREEMENT FOR PYTHON 2.6.2 77 | . 78 | 1. This LICENSE AGREEMENT is between the Python Software Foundation 79 | ("PSF"), and the Individual or Organization ("Licensee") accessing and 80 | otherwise using Python 2.6.2 software in source or binary form and its 81 | associated documentation. 82 | 2. Subject to the terms and conditions of this License Agreement, PSF 83 | hereby grants Licensee a nonexclusive, royalty-free, world-wide license 84 | to reproduce, analyze, test, perform and/or display publicly, prepare 85 | derivative works, distribute, and otherwise use Python 2.6.2 alone or in 86 | any derivative version, provided, however, that PSF's License Agreement 87 | and PSF's notice of copyright, i.e., "Copyright © 2001-2009 Python 88 | Software Foundation; All Rights Reserved" are retained in Python 2.6.2 89 | alone or in any derivative version prepared by Licensee. 90 | 3. In the event Licensee prepares a derivative work that is based on or 91 | incorporates Python 2.6.2 or any part thereof, and wants to make the 92 | derivative work available to others as provided herein, then Licensee 93 | hereby agrees to include in any such work a brief summary of the changes 94 | made to Python 2.6.2. 95 | 4. PSF is making Python 2.6.2 available to Licensee on an "AS IS" basis. 96 | PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF 97 | EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY 98 | REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY 99 | PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.6.2 WILL NOT INFRINGE ANY 100 | THIRD PARTY RIGHTS. 101 | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.6.2 102 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT 103 | OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.6.2, OR ANY 104 | DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 105 | 6. This License Agreement will automatically terminate upon a material 106 | breach of its terms and conditions. 107 | 7. Nothing in this License Agreement shall be deemed to create any 108 | relationship of agency, partnership, or joint venture between PSF and 109 | Licensee. This License Agreement does not grant permission to use PSF 110 | trademarks or trade name in a trademark sense to endorse or promote 111 | products or services of Licensee, or any third party. 112 | 8. By copying, installing or otherwise using Python 2.6.2, Licensee 113 | agrees to be bound by the terms and conditions of this License Agreement. 114 | . 115 | BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 116 | . 117 | BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 118 | . 119 | 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an 120 | office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual 121 | or Organization ("Licensee") accessing and otherwise using this software 122 | in source or binary form and its associated documentation ("the 123 | Software"). 124 | 2. Subject to the terms and conditions of this BeOpen Python License 125 | Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, 126 | world-wide license to reproduce, analyze, test, perform and/or display 127 | publicly, prepare derivative works, distribute, and otherwise use the 128 | Software alone or in any derivative version, provided, however, that the 129 | BeOpen Python License is retained in the Software, alone or in any 130 | derivative version prepared by Licensee. 131 | 3. BeOpen is making the Software available to Licensee on an "AS IS" 132 | basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR 133 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND 134 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS 135 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT 136 | INFRINGE ANY THIRD PARTY RIGHTS. 137 | 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE 138 | SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS 139 | AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY 140 | DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 141 | 5. This License Agreement will automatically terminate upon a material 142 | breach of its terms and conditions. 143 | 6. This License Agreement shall be governed by and interpreted in all 144 | respects by the law of the State of California, excluding conflict of 145 | law provisions. Nothing in this License Agreement shall be deemed to 146 | create any relationship of agency, partnership, or joint venture between 147 | BeOpen and Licensee. This License Agreement does not grant permission to 148 | use BeOpen trademarks or trade names in a trademark sense to endorse or 149 | promote products or services of Licensee, or any third party. As an 150 | exception, the "BeOpen Python" logos available at 151 | http://www.pythonlabs.com/logos.html may be used according to the 152 | permissions granted on that web page. 153 | 7. By copying, installing or otherwise using the software, Licensee 154 | agrees to be bound by the terms and conditions of this License 155 | Agreement. 156 | . 157 | CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 158 | . 159 | 1. This LICENSE AGREEMENT is between the Corporation for National 160 | Research Initiatives, having an office at 1895 Preston White Drive, 161 | Reston, VA 20191 ("CNRI"), and the Individual or Organization 162 | ("Licensee") accessing and otherwise using Python 1.6.1 software in 163 | source or binary form and its associated documentation. 164 | 2. Subject to the terms and conditions of this License Agreement, CNRI 165 | hereby grants Licensee a nonexclusive, royalty-free, world-wide license 166 | to reproduce, analyze, test, perform and/or display publicly, prepare 167 | derivative works, distribute, and otherwise use Python 1.6.1 alone or in 168 | any derivative version, provided, however, that CNRI's License Agreement 169 | and CNRI's notice of copyright, i.e., "Copyright © 1995-2001 Corporation 170 | for National Research Initiatives; All Rights Reserved" are retained in 171 | Python 1.6.1 alone or in any derivative version prepared by Licensee. 172 | Alternately, in lieu of CNRI's License Agreement, Licensee may 173 | substitute the following text (omitting the quotes): "Python 1.6.1 is 174 | made available subject to the terms and conditions in CNRI's License 175 | Agreement. This Agreement together with Python 1.6.1 may be located on 176 | the Internet using the following unique, persistent identifier (known as 177 | a handle): 1895.22/1013. This Agreement may also be obtained from a 178 | proxy server on the Internet using the following URL: 179 | http://hdl.handle.net/1895.22/1013." 180 | 3. In the event Licensee prepares a derivative work that is based on or 181 | incorporates Python 1.6.1 or any part thereof, and wants to make the 182 | derivative work available to others as provided herein, then Licensee 183 | hereby agrees to include in any such work a brief summary of the changes 184 | made to Python 1.6.1. 185 | 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" 186 | basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. 187 | BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY 188 | REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY 189 | PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY 190 | THIRD PARTY RIGHTS. 191 | 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 192 | 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A 193 | RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR 194 | ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 195 | 6. This License Agreement will automatically terminate upon a material 196 | breach of its terms and conditions. 197 | 7. This License Agreement shall be governed by the federal intellectual 198 | property law of the United States, including without limitation the 199 | federal copyright law, and, to the extent such U.S. federal law does not 200 | apply, by the law of the Commonwealth of Virginia, excluding Virginia's 201 | conflict of law provisions. Notwithstanding the foregoing, with regard 202 | to derivative works based on Python 1.6.1 that incorporate non-separable 203 | material that was previously distributed under the GNU General Public 204 | License (GPL), the law of the Commonwealth of Virginia shall govern this 205 | License Agreement only as to issues arising under or with respect to 206 | Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this 207 | License Agreement shall be deemed to create any relationship of agency, 208 | partnership, or joint venture between CNRI and Licensee. This License 209 | Agreement does not grant permission to use CNRI trademarks or trade name 210 | in a trademark sense to endorse or promote products or services of 211 | Licensee, or any third party. 212 | 8. By clicking on the "ACCEPT" button where indicated, or by copying, 213 | installing or otherwise using Python 1.6.1, Licensee agrees to be bound 214 | by the terms and conditions of this License Agreement. 215 | . 216 | ACCEPT 217 | . 218 | CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 219 | . 220 | Copyright © 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The 221 | Netherlands. All rights reserved. 222 | . 223 | Permission to use, copy, modify, and distribute this software and its 224 | documentation for any purpose and without fee is hereby granted, provided 225 | that the above copyright notice appear in all copies and that both that 226 | copyright notice and this permission notice appear in supporting 227 | documentation, and that the name of Stichting Mathematisch Centrum or CWI 228 | not be used in advertising or publicity pertaining to distribution of the 229 | software without specific, written prior permission. 230 | . 231 | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 232 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 233 | IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, 234 | INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 235 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 236 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 237 | PERFORMANCE OF THIS SOFTWARE. 238 | -------------------------------------------------------------------------------- /man/OptionParser-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \docType{class} 4 | \name{OptionParser-class} 5 | \alias{OptionParser-class} 6 | \title{Option Parser} 7 | \description{ 8 | Option Parser 9 | } 10 | \section{Slots}{ 11 | 12 | \describe{ 13 | \item{\code{usage}}{The program usage message that will printed out if 14 | \code{parse_args} finds a help option, \code{\%prog} is substituted with the 15 | value of the \code{prog} argument.} 16 | 17 | \item{\code{options}}{A list of of \code{OptionParserOption} instances that will 18 | define how \code{parse_args} reacts to command line options. 19 | \code{OptionParserOption} instances are usually created by \code{make_option} 20 | and can also be added to an existing \code{OptionParser} instance via the 21 | \code{add_option} function.} 22 | 23 | \item{\code{description}}{Additional text for \code{print_help} to print out between 24 | usage statement and options statement} 25 | 26 | \item{\code{epilogue}}{Additional text for \code{print_help} to print out after 27 | the options statement} 28 | 29 | \item{\code{formatter}}{A function that \code{print_help} will use to print out after 30 | the options statement. Default is \code{\link[=IndentedHelpFormatter]{IndentedHelpFormatter()}}. This 31 | package also provides the builtin formatter \code{\link[=TitledHelpFormatter]{TitledHelpFormatter()}}.} 32 | }} 33 | 34 | \seealso{ 35 | \code{\link{OptionParserOption}} 36 | } 37 | \author{ 38 | Trevor Davis. 39 | } 40 | -------------------------------------------------------------------------------- /man/OptionParser.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \name{OptionParser} 4 | \alias{OptionParser} 5 | \title{A function to create an instance of a parser object} 6 | \usage{ 7 | OptionParser( 8 | usage = "usage: \%prog [options]", 9 | option_list = list(), 10 | add_help_option = TRUE, 11 | prog = NULL, 12 | description = "", 13 | epilogue = "", 14 | formatter = IndentedHelpFormatter 15 | ) 16 | } 17 | \arguments{ 18 | \item{usage}{The program usage message that will printed out if 19 | \code{parse_args} finds a help option, \code{\%prog} is substituted with the 20 | value of the \code{prog} argument.} 21 | 22 | \item{option_list}{A list of of \code{OptionParserOption} instances that will 23 | define how \code{parse_args} reacts to command line options. 24 | \code{OptionParserOption} instances are usually created by \code{make_option} 25 | and can also be added to an existing \code{OptionParser} instance via the 26 | \code{add_option} function.} 27 | 28 | \item{add_help_option}{Whether a standard help option should be automatically 29 | added to the \code{OptionParser} instance.} 30 | 31 | \item{prog}{Program name to be substituted for \code{\%prog} in the usage 32 | message (including description and epilogue if present), 33 | the default is to use the actual Rscript file name if called by an 34 | Rscript file and otherwise keep \code{\%prog}.} 35 | 36 | \item{description}{Additional text for \code{print_help} to print out between 37 | usage statement and options statement} 38 | 39 | \item{epilogue}{Additional text for \code{print_help} to print out after 40 | the options statement} 41 | 42 | \item{formatter}{A function that formats usage text. 43 | The function should take only one argument (an \code{OptionParser()} object). 44 | Default is \code{\link[=IndentedHelpFormatter]{IndentedHelpFormatter()}}. 45 | The other builtin formatter provided by this package is \code{\link[=TitledHelpFormatter]{TitledHelpFormatter()}}.} 46 | } 47 | \value{ 48 | An instance of the \code{OptionParser} class. 49 | } 50 | \description{ 51 | This function is used to create an instance of a parser object 52 | which when combined with the \code{parse_args}, \code{make_option}, and \code{add_option} 53 | methods is very useful for parsing options from the command line. 54 | } 55 | \references{ 56 | Python's \code{optparse} library, which inspired this package, 57 | is described here: \url{https://docs.python.org/3/library/optparse.html} 58 | } 59 | \seealso{ 60 | \code{\link{parse_args}} \code{\link{make_option}} 61 | \code{\link{add_option}} 62 | } 63 | \author{ 64 | Trevor Davis. 65 | } 66 | -------------------------------------------------------------------------------- /man/OptionParserOption-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \docType{class} 4 | \name{OptionParserOption-class} 5 | \alias{OptionParserOption-class} 6 | \alias{OptionParserOption} 7 | \title{Class to hold information about command-line options} 8 | \description{ 9 | Class to hold information about command-line options 10 | } 11 | \section{Slots}{ 12 | 13 | \describe{ 14 | \item{\code{short_flag}}{String of the desired short flag 15 | comprised of the \dQuote{-} followed by a letter.} 16 | 17 | \item{\code{long_flag}}{String of the desired long flag comprised of \dQuote{--} 18 | followed by a letter and then a sequence of alphanumeric characters.} 19 | 20 | \item{\code{action}}{A character string that describes the action \code{optparse} 21 | should take when it encounters an option, either \dQuote{store}, 22 | \dQuote{store_true}, or \dQuote{store_false}. The default is \dQuote{store} 23 | which signifies that \code{optparse} should store the specified following 24 | value if the option is found on the command string. \dQuote{store_true} 25 | stores \code{TRUE} if the option is found and \dQuote{store_false} stores 26 | \code{FALSE} if the option is found.} 27 | 28 | \item{\code{type}}{A character string that describes specifies which data type 29 | should be stored, either \dQuote{logical}, \dQuote{integer}, \dQuote{double}, 30 | \dQuote{complex}, or \dQuote{character}. Default is \dQuote{logical} if 31 | \code{action \%in\% c("store_true", store_false)}, \code{typeof(default)} if 32 | \code{action == "store"} and default is not \code{NULL} and 33 | \dQuote{character} if \code{action == "store"} and default is \code{NULL}. 34 | \dQuote{numeric} will be converted to \dQuote{double}.} 35 | 36 | \item{\code{dest}}{A character string that specifies what field in the list returned 37 | by \code{parse_args} should \code{optparse} store option values. Default is 38 | derived from the long flag in \code{opt_str}.} 39 | 40 | \item{\code{default}}{The default value \code{optparse} should use if it does not 41 | find the option on the command line.} 42 | 43 | \item{\code{help}}{A character string describing the option to be used by 44 | \code{print_help} in generating a usage message. \code{\%default} will be 45 | substituted by the value of \code{default}.} 46 | 47 | \item{\code{metavar}}{A character string that stands in for the option argument when 48 | printing help text. Default is the value of \code{dest}.} 49 | 50 | \item{\code{callback}}{A function that executes after the each option value is fully parsed} 51 | 52 | \item{\code{callback_args}}{Additional arguments that pass to the callback function.} 53 | }} 54 | 55 | \seealso{ 56 | \code{\link{make_option}} 57 | } 58 | -------------------------------------------------------------------------------- /man/add_make_option.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \name{make_option} 4 | \alias{make_option} 5 | \alias{add_option} 6 | \title{Functions to enable our OptionParser to recognize specific command line 7 | options.} 8 | \usage{ 9 | make_option( 10 | opt_str, 11 | action = NULL, 12 | type = NULL, 13 | dest = NULL, 14 | default = NULL, 15 | help = "", 16 | metavar = NULL, 17 | callback = NULL, 18 | callback_args = NULL 19 | ) 20 | 21 | add_option( 22 | object, 23 | opt_str, 24 | action = NULL, 25 | type = NULL, 26 | dest = NULL, 27 | default = NULL, 28 | help = "", 29 | metavar = NULL, 30 | callback = NULL, 31 | callback_args = NULL 32 | ) 33 | } 34 | \arguments{ 35 | \item{opt_str}{A character vector containing the string of the desired long 36 | flag comprised of \dQuote{--} followed by a letter and then a sequence of 37 | alphanumeric characters and optionally a string of the desired short flag 38 | comprised of the \dQuote{-} followed by a letter.} 39 | 40 | \item{action}{A character string that describes the action \code{optparse} 41 | should take when it encounters an option, either \dQuote{store}, 42 | \dQuote{store_true}, \dQuote{store_false}, or \dQuote{callback}. 43 | An action of \dQuote{store} signifies that \code{optparse} 44 | should store the specified following value if the option is found on the command string. 45 | \dQuote{store_true} stores \code{TRUE} if the option is found 46 | and \dQuote{store_false} stores \code{FALSE} if the option is found. 47 | \dQuote{callback} stores the return value produced by the function 48 | specified in the \code{callback} argument. 49 | If \code{callback} is not \code{NULL} then the default is \dQuote{callback} else \dQuote{store}.} 50 | 51 | \item{type}{A character string that describes specifies which data type 52 | should be stored, either \dQuote{logical}, \dQuote{integer}, \dQuote{double}, 53 | \dQuote{complex}, or \dQuote{character}. Default is \dQuote{logical} if 54 | \code{action \%in\% c("store_true", store_false)}, \code{typeof(default)} if 55 | \code{action == "store"} and default is not \code{NULL} and 56 | \dQuote{character} if \code{action == "store"} and default is \code{NULL}. 57 | \dQuote{numeric} will be converted to \dQuote{double}.} 58 | 59 | \item{dest}{A character string that specifies what field in the list returned 60 | by \code{parse_args} should \code{optparse} store option values. Default is 61 | derived from the long flag in \code{opt_str}.} 62 | 63 | \item{default}{The default value \code{optparse} should use if it does not 64 | find the option on the command line.} 65 | 66 | \item{help}{A character string describing the option to be used by 67 | \code{print_help} in generating a usage message. \code{\%default} will be 68 | substituted by the value of \code{default}.} 69 | 70 | \item{metavar}{A character string that stands in for the option argument when 71 | printing help text. Default is the value of \code{dest}.} 72 | 73 | \item{callback}{A function that executes after the each option value is fully 74 | parsed. It's value is assigned to the option and its arguments are 75 | the option S4 object, the long flag string, the value of the option, 76 | the parser S4 object, and \code{...}.} 77 | 78 | \item{callback_args}{A list of additional arguments passed to callback function (via \code{do.call}).} 79 | 80 | \item{object}{An instance of the \code{OptionParser} class} 81 | } 82 | \value{ 83 | Both \code{make_option} and \code{add_option} return instances of 84 | class \code{OptionParserOption}. 85 | } 86 | \description{ 87 | \code{add_option} adds a option to a prexisting \code{OptionParser} instance 88 | whereas \code{make_option} is used to create a list of 89 | \code{OptionParserOption} instances that will be used in the 90 | \code{option_list} argument of the \code{OptionParser} function to create a 91 | new \code{OptionParser} instance. 92 | } 93 | \examples{ 94 | 95 | make_option("--longflag") 96 | make_option(c("-l", "--longflag")) 97 | make_option("--integer", type = "integer", default = 5) 98 | make_option("--integer", default = as.integer(5)) # same as previous 99 | 100 | # examples from package vignette 101 | make_option(c("-v", "--verbose"), action = "store_true", default = TRUE, 102 | help = "Print extra output [default]") 103 | make_option(c("-q", "--quietly"), action = "store_false", 104 | dest = "verbose", help = "Print little output") 105 | make_option(c("-c", "--count"), type = "integer", default = 5, 106 | help = "Number of random normals to generate [default \%default]", 107 | metavar = "number") 108 | make_option("--generator", default = "rnorm", 109 | help = "Function to generate random deviates [default \"\%default\"]") 110 | make_option("--mean", default = 0, 111 | help = "Mean if generator == \"rnorm\" [default \%default]") 112 | make_option("--sd", default = 1, metavar = "standard deviation", 113 | help = "Standard deviation if generator == \"rnorm\" [default \%default]") 114 | 115 | } 116 | \references{ 117 | Python's \code{optparse} library, which inspires this package, 118 | is described here: \url{https://docs.python.org/3/library/optparse.html} 119 | } 120 | \seealso{ 121 | \code{\link{parse_args}} \code{\link{OptionParser}} 122 | } 123 | \author{ 124 | Trevor Davis. 125 | } 126 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trevorld/r-optparse/a7f641dba92108d3980fa8b3ee353dae50e9e020/man/figures/logo.png -------------------------------------------------------------------------------- /man/figures/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /man/formatter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \name{IndentedHelpFormatter} 4 | \alias{IndentedHelpFormatter} 5 | \alias{TitledHelpFormatter} 6 | \title{Builtin help text formatters} 7 | \usage{ 8 | IndentedHelpFormatter(object) 9 | 10 | TitledHelpFormatter(object) 11 | } 12 | \arguments{ 13 | \item{object}{An \code{\link[=OptionParser]{OptionParser()}} object.} 14 | } 15 | \value{ 16 | \code{NULL} invisibly. As a side effect prints out help text. 17 | } 18 | \description{ 19 | \code{IndentedHelpFormatter()} is the default help text formatter. 20 | \code{TitledHelpFormatter()} is an alternative help text formatter. 21 | } 22 | \examples{ 23 | parser <- OptionParser(formatter = IndentedHelpFormatter) 24 | parser <- add_option(parser, "--generator", help = "Generator option") 25 | parser <- add_option(parser, "--count", help = "Count option") 26 | print_help(parser) 27 | 28 | parser <- OptionParser(formatter = TitledHelpFormatter) 29 | parser <- add_option(parser, "--generator", help = "Generator option") 30 | parser <- add_option(parser, "--count", help = "Count option") 31 | print_help(parser) 32 | } 33 | -------------------------------------------------------------------------------- /man/optparse-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse-package.R 3 | \docType{package} 4 | \name{optparse-package} 5 | \alias{optparse-package} 6 | \alias{optparse} 7 | \title{Command line option parser} 8 | \description{ 9 | Goal is to create an R package of a command line parser inspired by Python's 10 | \dQuote{optparse} library. 11 | } 12 | \details{ 13 | \code{optparse} is primarily intended to be used with 14 | \dQuote{Rscript}. It facilitates writing \dQuote{#!} shebang scripts that 15 | accept short and long flags/options. It can also be used from directly, but 16 | is probably less useful in this context. 17 | 18 | See package vignette for a more detailed example. 19 | 20 | Notes on naming convention in package: 1. An option is one of the shell-split 21 | input strings. 2. A flag is a type of option. a flag can be defined as having 22 | no argument (defined below), a required argument, or an optional argument. 3. 23 | An argument is a type of option, and is the value associated with a flag. 4. 24 | A long flag is a type of flag, and begins with the string \dQuote{--}. If the 25 | long flag has an associated argument, it may be delimited from the long flag 26 | by either a trailing =, or may be the subsequent option. 5. A short flag is a 27 | type of flag, and begins with the string \dQuote{-}. If a short flag has an 28 | associated argument, it is the subsequent option. short flags may be bundled 29 | together, sharing a single leading \dQuote{"-"}, but only the final short 30 | flag is able to have a corresponding argument. \%\%\% 31 | } 32 | \examples{ 33 | 34 | example_file <- system.file("exec", "example.R", package = "optparse") 35 | example_file_2 <- system.file("exec", "display_file.R", package = "optparse") 36 | \dontrun{ 37 | readLines(example_file) 38 | readLines(example_file_2) 39 | } 40 | 41 | } 42 | \references{ 43 | Python's \code{optparse} library, which this package is based on, 44 | is described here: \url{https://docs.python.org/3/library/optparse.html} 45 | } 46 | \seealso{ 47 | \code{\link[getopt]{getopt}} 48 | } 49 | \author{ 50 | Trevor L. Davis. 51 | 52 | Some documentation and unit tests ported from Allen Day's getopt package. 53 | 54 | The documentation for Python's optparse library, which this package is based 55 | on, is Copyright 1990-2009, Python Software Foundation. 56 | } 57 | \keyword{package} 58 | -------------------------------------------------------------------------------- /man/parse_args.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \encoding{latin1} 4 | \name{parse_args} 5 | \alias{parse_args} 6 | \alias{parse_args2} 7 | \title{Parse command line options.} 8 | \usage{ 9 | parse_args( 10 | object, 11 | args = commandArgs(trailingOnly = TRUE), 12 | print_help_and_exit = TRUE, 13 | positional_arguments = FALSE, 14 | convert_hyphens_to_underscores = FALSE 15 | ) 16 | 17 | parse_args2( 18 | object, 19 | args = commandArgs(trailingOnly = TRUE), 20 | print_help_and_exit = TRUE 21 | ) 22 | } 23 | \arguments{ 24 | \item{object}{An \code{OptionParser} instance.} 25 | 26 | \item{args}{A character vector containing command line options to be parsed. 27 | Default is everything after the Rscript program in the command line. If 28 | \code{positional_arguments} is not \code{FALSE} then \code{parse_args} will 29 | look for positional arguments at the end of this vector.} 30 | 31 | \item{print_help_and_exit}{Whether \code{parse_args} should call 32 | \code{print_help} to print out a usage message and exit the program. Default 33 | is \code{TRUE}.} 34 | 35 | \item{positional_arguments}{Number of \emph{positional} arguments. A numeric 36 | denoting the exact number of supported arguments, or a numeric vector of 37 | length two denoting the minimum and maximum number of arguments 38 | (\code{Inf} for no limit). The value \code{TRUE} is equivalent to 39 | \code{c(0, Inf)}. The default \code{FALSE} is 40 | supported for backward compatibility only, as it alters 41 | the format of the return value.} 42 | 43 | \item{convert_hyphens_to_underscores}{If the names in the returned list of options 44 | contains hyphens then convert them to underscores. The default \code{FALSE} is 45 | supported for backward compatibility reasons as it alters the format of the return value} 46 | } 47 | \value{ 48 | Returns a list with field \code{options} containing our option values 49 | as well as another field \code{args} which contains a vector of 50 | positional arguments. For backward compatibility, if and only if 51 | \code{positional_arguments} is \code{FALSE}, returns a list containing 52 | option values. 53 | } 54 | \description{ 55 | \code{parse_args} parses command line options using an \code{OptionParser} 56 | instance for guidance. \code{parse_args2} is a wrapper to \code{parse_args} 57 | setting the options \code{positional_arguments} and \code{convert_hyphens_to_underscores} 58 | to \code{TRUE}. 59 | } 60 | \section{Acknowledgement}{ 61 | 62 | A big thanks to Steve Lianoglou for a bug report and patch; 63 | Juan Carlos \enc{Borrás}{Borras} for a bug report; 64 | Jim Nikelski for a bug report and patch; 65 | Ino de Brujin and Benjamin Tyner for a bug report; 66 | Jonas Zimmermann for bug report; Miroslav Posta for bug reports; 67 | Stefan Seemayer for bug report and patch; 68 | Kirill \enc{Müller}{Muller} for patches; Steve Humburg for patch. 69 | } 70 | 71 | \examples{ 72 | # example from vignette 73 | option_list <- list( 74 | make_option(c("-v", "--verbose"), action = "store_true", default = TRUE, 75 | help = "Print extra output [default]"), 76 | make_option(c("-q", "--quietly"), action = "store_false", 77 | dest = "verbose", help = "Print little output"), 78 | make_option(c("-c", "--count"), type = "integer", default = 5, 79 | help = "Number of random normals to generate [default \%default]", 80 | metavar = "number"), 81 | make_option("--generator", default = "rnorm", 82 | help = "Function to generate random deviates [default \"\%default\"]"), 83 | make_option("--mean", default = 0, 84 | help = "Mean if generator == \"rnorm\" [default \%default]"), 85 | make_option("--sd", default = 1, metavar = "standard deviation", 86 | help = "Standard deviation if generator == \"rnorm\" [default \%default]") 87 | ) 88 | parse_args(OptionParser(option_list = option_list), args = c("--sd=3", "--quietly")) 89 | 90 | # example from vignette using positional arguments 91 | option_list2 <- list( 92 | make_option(c("-n", "--add-numbers"), action = "store_true", default = FALSE, 93 | help = "Print line number at the beginning of each line [default]") 94 | ) 95 | parser <- OptionParser(usage = "\%prog [options] file", option_list = option_list2) 96 | 97 | parse_args(parser, args = c("--add-numbers", "example.txt"), positional_arguments = TRUE) 98 | 99 | parse_args(parser, args = c("--add-numbers", "example.txt"), positional_arguments = TRUE, 100 | convert_hyphens_to_underscores = TRUE) 101 | 102 | parse_args2(parser, args = c("--add-numbers", "example.txt")) 103 | 104 | } 105 | \references{ 106 | Python's \code{optparse} library, which inspired this package, 107 | is described here: \url{https://docs.python.org/3/library/optparse.html} 108 | } 109 | \seealso{ 110 | \code{\link{OptionParser}} \code{\link{print_help}} 111 | } 112 | \author{ 113 | Trevor Davis. 114 | } 115 | -------------------------------------------------------------------------------- /man/print_help.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optparse.R 3 | \name{print_help} 4 | \alias{print_help} 5 | \title{Printing an usage message from an OptionParser object} 6 | \usage{ 7 | print_help(object) 8 | } 9 | \arguments{ 10 | \item{object}{A \code{OptionParser} instance.} 11 | } 12 | \value{ 13 | \code{print_help} uses the \code{cat} function to print out a usage 14 | message. It returns \code{invisible(NULL)}. 15 | } 16 | \description{ 17 | \code{print_help} print an usage message from an OptionParser object, usually 18 | called by \code{parse_args} when it encounters a help option. 19 | } 20 | \references{ 21 | Python's \code{optparse} library, which inspired this package, 22 | is described here: \url{https://docs.python.org/3/library/optparse.html} 23 | } 24 | \seealso{ 25 | \code{{parse_args}} \code{{OptionParser}} 26 | } 27 | \author{ 28 | Trevor Davis. 29 | } 30 | -------------------------------------------------------------------------------- /raw-data/logo.R: -------------------------------------------------------------------------------- 1 | library("bittermelon") 2 | library("grid") 3 | library("piecepackr") 4 | 5 | font_file <- system.file("fonts/spleen/spleen-8x16.hex.gz", package = "bittermelon") 6 | font <- read_hex(font_file) 7 | optparse <- as_bm_bitmap("optparse", font = font) 8 | hashbang <- as_bm_bitmap("#!", font = font) 9 | 10 | draw_logo <- function() { 11 | hex <- pp_shape("convex6") 12 | grid.newpage() 13 | grid.draw(hex$shape(gp = gpar(col = NA, fill = "#C0C0C0"))) 14 | plot(optparse, col = c("transparent", "black"), 15 | vp = viewport(y = 0.65, width=0.75, height = 0.21)) 16 | plot(hashbang, col = c("transparent", "black"), 17 | vp = viewport(y = 0.33, width = 0.5, height = 0.4)) 18 | grid.draw(hex$mat(mat_width = 0.03, gp = gpar(col = NA, fill = "black"))) 19 | } 20 | 21 | w <- 3.0 22 | svg("man/figures/logo.svg", width = w, height = w, bg = "transparent") 23 | draw_logo() 24 | dev.off() 25 | 26 | png("man/figures/logo.png", width = w, height = w, units = "in", 27 | res = 72, bg = "transparent") 28 | draw_logo() 29 | dev.off() 30 | -------------------------------------------------------------------------------- /tests/run-all.R: -------------------------------------------------------------------------------- 1 | library("testthat") 2 | 3 | test_check("optparse") 4 | -------------------------------------------------------------------------------- /tests/test_help.R: -------------------------------------------------------------------------------- 1 | library("optparse") 2 | 3 | parser <- OptionParser() 4 | parse_args(parser, "--help") 5 | -------------------------------------------------------------------------------- /tests/test_help.Rout.save: -------------------------------------------------------------------------------- 1 | 2 | R version 3.3.2 (2016-10-31) -- "Sincere Pumpkin Patch" 3 | Copyright (C) 2016 The R Foundation for Statistical Computing 4 | Platform: x86_64-pc-linux-gnu (64-bit) 5 | 6 | R is free software and comes with ABSOLUTELY NO WARRANTY. 7 | You are welcome to redistribute it under certain conditions. 8 | Type 'license()' or 'licence()' for distribution details. 9 | 10 | Natural language support but running in an English locale 11 | 12 | R is a collaborative project with many contributors. 13 | Type 'contributors()' for more information and 14 | 'citation()' on how to cite R or R packages in publications. 15 | 16 | Type 'demo()' for some demos, 'help()' for on-line help, or 17 | 'help.start()' for an HTML browser interface to help. 18 | Type 'q()' to quit R. 19 | 20 | > library("optparse") 21 | > 22 | > parser <- OptionParser() 23 | > parse_args(parser, "--help") 24 | Usage: %prog [options] 25 | 26 | 27 | Options: 28 | -h, --help 29 | Show this help message and exit 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/testthat/test-optparse.R: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2019 Trevor L Davis 2 | # Copyright 2013 Kirill Müller 3 | # Copyright 2008 Allen Day 4 | # 5 | # This file is free software: you may copy, redistribute and/or modify it 6 | # under the terms of the GNU General Public License as published by the 7 | # Free Software Foundation, either version 2 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # This file is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | option_list <- list( 19 | make_option(c("-v", "--verbose"), action = "store_true", default = TRUE, 20 | help = "Print extra output [default]"), 21 | make_option(c("-q", "--quietly"), action = "store_false", 22 | dest = "verbose", help = "Print little output"), 23 | make_option(c("-c", "--count"), type = "integer", default = 5, 24 | help = "Number of random normals to generate [default \\%default]", 25 | metavar = "number"), 26 | make_option("--generator", default = "rnorm", 27 | help = "Function to generate random deviates [default \"\\%default\"]"), 28 | make_option("--mean", default = 0, 29 | help = "Mean if generator == \"rnorm\" [default \\%default]"), 30 | make_option("--sd", default = 1, metavar = "standard deviation", 31 | help = "Standard deviation if generator == \"rnorm\" [default \\%default]") 32 | ) 33 | parser_ol <- OptionParser(option_list = option_list) 34 | 35 | 36 | test_that("`make_option()` works as expected", { 37 | expect_equal(make_option("--integer", type = "integer", default = 5), 38 | make_option("--integer", default = as.integer(5))) 39 | expect_equal(make_option("--logical", type = "logical", default = "TRUE"), 40 | make_option("--logical", default = TRUE)) 41 | expect_equal(make_option("--filename")@type, "character") 42 | expect_that(make_option("badflag"), throws_error()) 43 | expect_error(make_option("-cd"), "must only be") 44 | }) 45 | 46 | get_long_flags <- function(parser) { 47 | sort(sapply(parser@options, function(x) x@long_flag)) 48 | } 49 | test_that("`add_option()` works as expected", { 50 | parser1 <- OptionParser(option_list = list(make_option("--generator"), make_option("--count"))) 51 | parser2 <- OptionParser() 52 | parser2 <- add_option(parser2, "--generator") 53 | parser2 <- add_option(parser2, "--count") 54 | expect_equal(get_long_flags(parser1), get_long_flags(parser2)) 55 | }) 56 | 57 | test_that("`parse_args()` works as expected", { 58 | # option_list took outside test_that 59 | option_list2 <- list( 60 | make_option(c("-n", "--add-numbers"), action = "store_true", default = FALSE, 61 | help = "Print line number at the beginning of each line [default]") 62 | ) 63 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list2) 64 | expect_equal(sort_list(parse_args(parser_ol, 65 | args = c("--sd=3", "--quietly"))), 66 | sort_list(list(sd = 3, verbose = FALSE, help = FALSE, 67 | count = 5, mean = 0, generator = "rnorm"))) 68 | expect_equal(sort_list(parse_args(parser_ol, 69 | args = character(0), positional_arguments = TRUE)), 70 | sort_list(list(options = list(sd = 1, help = FALSE, verbose = TRUE, 71 | count = 5, mean = 0, generator = "rnorm"), 72 | args = character(0)))) 73 | expect_equal(sort_list(parse_args(parser_ol, 74 | args = c("-c", "10"))), 75 | sort_list(list(sd = 1, help = FALSE, verbose = TRUE, 76 | count = 10, mean = 0, generator = "rnorm"))) 77 | expect_equal(sort_list(parse_args(parser, args = c("--add-numbers", "example.txt"), 78 | positional_arguments = TRUE)), 79 | sort_list(list(options = list(`add-numbers` = TRUE, help = FALSE), 80 | args = c("example.txt")))) 81 | expect_equal(sort_list(parse_args(parser, args = c("--add-numbers"), 82 | positional_arguments = TRUE)), 83 | sort_list(list(options = list(`add-numbers` = TRUE, help = FALSE), 84 | args = character(0)))) 85 | expect_equal(sort_list(parse_args(parser, args = c("--add-numbers"), 86 | positional_arguments = TRUE, convert_hyphens_to_underscores = TRUE)), 87 | sort_list(list(options = list(add_numbers = TRUE, help = FALSE), 88 | args = character(0)))) 89 | expect_equal(sort_list(parse_args2(parser, args = c("--add-numbers"))), 90 | sort_list(list(options = list(add_numbers = TRUE, help = FALSE), 91 | args = character(0)))) 92 | expect_error(parse_args(parser, args = c("-add-numbers", "example.txt")), positional_arguments = FALSE) 93 | expect_error(parse_args(parser, args = c("-add-numbers", "example.txt"), positional_arguments = TRUE)) 94 | expect_equal(sort_list(parse_args(parser, args = c("--add-numbers", "example.txt"), 95 | positional_arguments = c(1, 3))), 96 | sort_list(list(options = list(`add-numbers` = TRUE, help = FALSE), 97 | args = c("example.txt")))) 98 | expect_equal(sort_list(parse_args(parser, args = c("example.txt"), 99 | positional_arguments = 1)), 100 | sort_list(list(options = list(`add-numbers` = FALSE, help = FALSE), 101 | args = c("example.txt")))) 102 | expect_that(parse_args(parser, args = c("-add-numbers", "example.txt"), 103 | positional_arguments = c(0, 1)), throws_error()) 104 | expect_that(parse_args(parser, args = c("example.txt"), 105 | positional_arguments = c(2, Inf)), throws_error()) 106 | expect_that(parse_args(parser, args = c("example.txt"), 107 | positional_arguments = 2), throws_error()) 108 | expect_that(parse_args(parser, args = c("example.txt"), 109 | positional_arguments = "any"), throws_error("must be logical or numeric")) 110 | expect_that(parse_args(parser, args = c("example.txt"), 111 | positional_arguments = 1:3), throws_error("must have length 1 or 2")) 112 | 113 | if (interactive()) { 114 | expect_that(capture.output(parse_args(parser, args = c("--help"))), 115 | throws_error("help requested")) 116 | expect_that(capture.output(parse_args(parser, args = c("--help"), positional_arguments = c(1, 2))), 117 | throws_error("help requested")) 118 | } 119 | }) 120 | 121 | # Patch from Gyu Jin Choi. 122 | test_that("callback works as expected", { 123 | power <- function(x, n = 2) x^n 124 | callback_fn <- function(option, flag, option_value, parser, n = 2) { 125 | power(option_value, n) 126 | } 127 | 128 | parser0 <- OptionParser() 129 | parser1 <- add_option(parser0, c("-s", "--squared_distance"), type = "integer", 130 | action = "callback", help = "Squared distance between two points", 131 | callback = callback_fn, callback_args = list(2)) 132 | opts <- parse_args(parser1, args = c("--squared_distance=16")) 133 | expect_equal(opts$squared_distance, 256) 134 | # Bug found by Ni Huang (#28) 135 | opts <- parse_args(parser1, positional_argument = TRUE, args = c("-s", "3")) 136 | expect_equal(opts$options$squared_distance, 9) 137 | # Bug found by Ni Huang (#29) 138 | expect_output(print_help(parser1), "SQUARED_DISTANCE") 139 | 140 | parser2 <- add_option(parser0, c("-v", "--value"), type = "integer", 141 | action = "callback", callback = callback_fn, callback_args = list(n = 3)) 142 | opts <- parse_args(parser2, args = c("--value=2")) 143 | expect_equal(opts$value, 8) 144 | 145 | parser3 <- add_option(parser0, c("-v", "--value"), type = "integer", 146 | action = "callback", callback = callback_fn) 147 | opts <- parse_args(parser3, args = c("--value=2")) 148 | expect_equal(opts$value, 4) 149 | 150 | expect_warning(add_option(parser0, "--warning", action = "store", callback = as.list), 151 | "callback argument is supplied for non-callback action") 152 | expect_warning(add_option(parser0, "--warning", callback_args = list(3, b = 4)), 153 | "callback_args argument is supplied for non-callback action") 154 | expect_warning(add_option(parser0, "--warning", action = "callback", type = "numeric", callback = "hello"), 155 | "callback argument is not a function") 156 | 157 | callback_fn <- function(option, flag, option_value, parser) { 158 | 42 159 | } 160 | parser4 <- add_option(parser0, "--null_type", type = NULL, callback = callback_fn) 161 | opts <- parse_args(parser4, args = c("--null_type")) 162 | expect_equal(opts$null_type, 42) 163 | }) 164 | 165 | # Bug found by Miroslav Posta 166 | test_that("test using numeric instead of double", { 167 | option_list_neg <- list(make_option(c("-m", "--mean"), default = 0, type = "numeric")) 168 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list_neg) 169 | opts <- parse_args(parser, args = c("-m", "-5.0")) 170 | expect_equal(opts$mean, -5.0) 171 | }) 172 | 173 | # Bug found by Juan Carlos Borrás 174 | test_that("test bug of multiple '=' signs", { 175 | optlist <- list( 176 | make_option(c("-s", "--substitutions"), type = "character", 177 | dest = "substitutions", default = NULL, 178 | help = 'String of the form "KEY1=VALUE1 KEY2=VALUE2 ... KEY=VALUE" 179 | stating the SQL template substitutions', 180 | metavar = "substitution-list") 181 | ) 182 | optparser <- OptionParser(option_list = optlist) 183 | opt <- parse_args(optparser, c("-s", "FOO=bar")) 184 | opt_alt <- parse_args(optparser, c("--substitutions=FOO=bar")) 185 | expect_that(opt, equals(opt_alt)) 186 | 187 | # also check when positional_arguments is set to true, like later bug unit test 188 | opt <- parse_args(optparser, c("-s", "FOO=bar"), positional_arguments = TRUE) 189 | opt_alt <- parse_args(optparser, c("--substitutions=FOO=bar"), positional_arguments = TRUE) 190 | expect_that(opt, equals(opt_alt)) 191 | }) 192 | 193 | # Bug found by Jim Nikelski 194 | test_that("test bug when multiple short flag options '-abc' with positional_arguments = TRUE", { 195 | sort_list <- function(unsorted_list) { 196 | for (ii in seq_along(unsorted_list)) { 197 | if (is.list(unsorted_list[[ii]])) { 198 | unsorted_list[[ii]] <- sort_list(unsorted_list[[ii]]) 199 | } 200 | } 201 | unsorted_list[sort(names(unsorted_list))] 202 | } 203 | expect_equal(sort_list(parse_args(parser_ol, 204 | args = c("-qc", "10"), positional_arguments = TRUE)), 205 | sort_list(list(options = list(sd = 1, help = FALSE, verbose = FALSE, 206 | count = 10, mean = 0, generator = "rnorm"), 207 | args = character(0)))) 208 | expect_error(parse_args(parser_ol, args = c("-qcde", "10"), positional_arguments = TRUE)) 209 | expect_error(parse_args(parser_ol, args = c("a", "b", "c", "d", "e"), positional_arguments = c(1, 3))) 210 | expect_equal(sort_list(parse_args(parser_ol, 211 | args = c("CMD", "-qc", "10", "bumblebee"), positional_arguments = TRUE)), 212 | sort_list(list(options = list(sd = 1, help = FALSE, verbose = FALSE, 213 | count = 10, mean = 0, generator = "rnorm"), 214 | args = c("CMD", "bumblebee")))) 215 | args <- c("CMD", "-qc", "10", "bumblebee", "--qcdefg") 216 | expect_error(parse_args(parser_ol, args = args, positional_arguments = TRUE), 217 | "no such option: --qcdefg") 218 | args <- c("-qxc", "10", "bumblebee") 219 | expect_error(parse_args(parser_ol, args = args, positional_arguments = TRUE), 220 | 'short flag "x" is invalid') 221 | }) 222 | 223 | # Bug found by Ino de Brujin and Benjamin Tyner 224 | test_that("test bug when long flag option with '=' with positional_arguments = TRUE", { 225 | expect_equal(sort_list(parse_args(parser_ol, 226 | args = c("--count=10"), positional_arguments = TRUE)), 227 | sort_list(list(options = list(sd = 1, help = FALSE, verbose = TRUE, 228 | count = 10, mean = 0, generator = "rnorm"), 229 | args = character(0)))) 230 | }) 231 | 232 | # Bug found by Miroslav Posta 233 | optlist <- list(make_option(c("--tmin"), type = "numeric", help = "Startup time [sec]. ")) 234 | parser <- OptionParser(option_list = optlist, usage = "", epilogue = "") 235 | test_that("test bug with a NA short flag option with positional_arguments = TRUE", { 236 | expect_equal(sort_list(parse_args(args = c("-h", "foo"), parser, positional_arguments = TRUE, 237 | print_help_and_exit = FALSE)), 238 | sort_list(list(options = list(help = TRUE), args = "foo"))) 239 | }) 240 | 241 | test_that("description and epilogue work as expected", { 242 | parser <- OptionParser() 243 | expect_output(print_help(parser), "Usage:") 244 | expect_output(print_help(parser), "Options:") 245 | parser2 <- OptionParser(usage = "program", description = "foo", epilogue = "bar") 246 | expect_output(print_help(parser2), "foo") 247 | expect_output(print_help(parser2), "bar$") 248 | expect_output(print_help(parser2), "^Usage: ") 249 | expect_equal(stringr::str_count( 250 | capture.output(print_help(OptionParser("usage: foo bar")))[1], 251 | "[Uu]sage"), 1) 252 | 253 | parser <- OptionParser(formatter = TitledHelpFormatter) 254 | parser <- add_option(parser, c("-f", "--foo"), help = "Foobar") 255 | expect_output(print_help(parser), "Usage\n=====") 256 | 257 | # bug found by Stefan Seemayer for NA default 258 | optlist <- list( 259 | make_option(c("--na"), type = "character", default = NA, help = "NA default is %default"), 260 | make_option(c("--null"), type = "character", default = NULL, help = "NULL default is %default"), 261 | make_option(c("--str"), type = "character", default = "str", help = "str default is %default"), 262 | make_option(c("--bool"), type = "logical", default = TRUE, help = "bool default is %default"), 263 | make_option(c("--int"), type = "integer", default = 42, help = "int default is %default"), 264 | make_option(c("--int"), type = "double", default = 11.11, help = "double default is %default") 265 | ) 266 | parser <- OptionParser(option_list = optlist) 267 | expect_output(print_help(parser), "NA default is NA") 268 | expect_output(print_help(parser), "NULL default is NULL") 269 | expect_output(print_help(parser), "str default is str") 270 | expect_output(print_help(parser), "bool default is TRUE") 271 | expect_output(print_help(parser), "int default is 42") 272 | expect_output(print_help(parser), "double default is 11.11") 273 | 274 | # bug / feature request by Miroslav Posta 275 | parser <- OptionParser(usage = "test %prog test %prog", epilogue = "epilog test %prog %prog", 276 | description = "description %prog test %prog", prog = "unit_test.r") 277 | expect_output(print_help(parser), "Usage:.*unit_test.r.*unit_test.r") 278 | expect_output(print_help(parser), "description unit_test.r test unit_test.r") 279 | expect_output(print_help(parser), "epilog test unit_test.r unit_test.r") 280 | }) 281 | 282 | # Bug found by Benjamin Tyner 283 | test_that("Can set zero length default options", { 284 | option_list_neg <- list(make_option(c("-m", "--mean"), default = numeric(0), 285 | type = "numeric", help = "Default %default")) 286 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list_neg) 287 | expect_equal(sort_list(parse_args(parser, args = c("-m", "-5.0"))), 288 | sort_list(list(mean = -5, help = FALSE))) 289 | expect_equal(sort_list(parse_args(parser)), 290 | sort_list(list(mean = numeric(0), help = FALSE))) 291 | expect_output(print_help(parser), "Default double") 292 | }) 293 | 294 | # Bug found by Matthew Flickinger 295 | test_that("Can parse empty string", { 296 | option_list <- list(make_option(c("", "--string"))) 297 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list) 298 | expect_equal(sort_list(parse_args(parser, args = c("--string="))), 299 | sort_list(list(string = "", help = FALSE))) 300 | }) 301 | 302 | # nolint start 303 | # # Bug found by Rich FitzJohn 304 | # oo <- options() 305 | # on.exit(options(oo)) 306 | # options(warnPartialMatchArgs = TRUE) 307 | # test_that("Avoid partial matching of arguments", { 308 | # expect_that(seq(along = 1:10), gives_warning("partial argument match")) 309 | # expect_that(seq_along(1:10), not(gives_warning())) 310 | # expect_that(parse_args(args = c("-h", "foo"), parser, positional_arguments = TRUE, print_help_and_exit = FALSE), 311 | # not(gives_warning())) 312 | # expect_that(print_help(OptionParser()), not(gives_warning())) 313 | # }) 314 | # nolint end 315 | 316 | # Use h flag for non-help (Reported by Jeff Bruce) 317 | test_that("Use h option for non-help", { 318 | option_list_neg <- list(make_option(c("-h", "--mean"), default = 0.0)) 319 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list_neg) 320 | expect_error(parse_args(parser, args = c("-h", "-5.0")), "redundant short names") 321 | 322 | option_list_neg <- list(make_option(c("-h", "--mean"), default = 0.0)) 323 | parser <- OptionParser(usage = "\\%prog [options] file", option_list = option_list_neg, add_help_option = FALSE) 324 | args <- parse_args(parser, args = c("-h", "-5.0")) 325 | expect_equal(args, list(mean = -5.0)) 326 | }) 327 | 328 | # Bug found by @husheng (#47) 329 | test_that("Don't coerce `default` of callback action match that of `type`", { 330 | parser <- OptionParser() 331 | str2bool <- function(option, flag, option_value, parser) as.logical(option_value) 332 | parser <- add_option(parser, "--bool", type = "character", default = FALSE, callback = str2bool) 333 | expect_equal(parse_args(parser, c())$bool, FALSE) 334 | expect_equal(parse_args(parser, "--bool=T")$bool, TRUE) 335 | }) 336 | -------------------------------------------------------------------------------- /vignettes/optparse.Rrst: -------------------------------------------------------------------------------- 1 | .. 2 | %\VignetteIndexEntry{optparse Command Line Option Parsing} 3 | %\VignetteEngine{knitr::knitr} 4 | 5 | optparse Command Line Option Parsing 6 | ==================================== 7 | 8 | optparse is a command line option parser inspired by Python's "optparse" library. Use this with Rscript to write "#!"-shebang scripts that accept short and long flags/options, generate a usage statement, and set default values for options that are not specified on the command line. 9 | 10 | .. {r echo=FALSE} 11 | .. library("knitr") 12 | .. Rscript_executable <- paste(file.path(R.home(), "bin", "Rscript"), "--vanilla") # nolint 13 | .. opts_knit$set(root.dir = system.file("exec", package = "optparse")) # to access the "Rscript files" 14 | .. opts_chunk$set(comment = NA, echo = FALSE) 15 | .. list_file_command <- "ls" 16 | .. chmod_command <- "chmod ug+x display_file.R example.R" 17 | .. path_command <- "export PATH=$PATH:`pwd`" 18 | .. run_command <- function(string) suppressWarnings(cat(system(string, intern = TRUE), sep = "\n")) 19 | .. .. 20 | 21 | In our working directory we have two example R scripts, named "example.R" and "display\_file.R" illustrating the use of the optparse package. 22 | 23 | **:r:`paste("bash$", list_file_command)`** 24 | .. {r} 25 | .. run_command(sprintf("%s", list_file_command)) 26 | .. command <- "display_file.R example.R" # to show file 27 | .. .. 28 | 29 | In order for a \*nix system to recognize a "#!"-shebang line you need to mark the file executable with the ``chmod`` command, it also helps to add the directory containing your Rscripts to your path: 30 | 31 | **:r:`paste("bash$", chmod_command)`** 32 | 33 | **:r:`paste("bash$", path_command)`** 34 | 35 | Here is what ``example.R`` contains: 36 | 37 | **:r:`paste("bash$", command)`** 38 | .. {r} 39 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 40 | .. .. 41 | 42 | .. {r} 43 | .. command <- "example.R --help" # same as system("Rscript example.R -h") 44 | .. .. 45 | 46 | By default *optparse* will generate a help message if it encounters ``--help`` or ``-h`` on the command line. Note how ``%default`` in the example program was replaced by the actual default values in the help statement that *optparse* generated. 47 | 48 | **:r:`paste("bash$", command)`** 49 | .. {r} 50 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 51 | .. command <- "example.R" # rely only on defaults 52 | .. .. 53 | 54 | If you specify default values when creating your ``OptionParser`` then *optparse* will use them as expected. 55 | 56 | **:r:`paste("bash$", command)`** 57 | .. {r} 58 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 59 | .. command <- "example.R --mean=10 --sd=10 --count=3" 60 | .. .. 61 | 62 | Or you can specify your own values. 63 | 64 | **:r:`paste("bash$", command)`** 65 | .. {r} 66 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 67 | .. command <- "example.R --quiet -c 4 --generator=\"runif\"" # same as above but "quiet" 68 | .. .. 69 | 70 | If you remember from the example program that ``--quiet`` had ``action="store_false"`` and 71 | ``dest="verbose"``. This means that ``--quiet`` is a switch that turns the ``verbose`` option from its default value of ``TRUE`` to ``FALSE``. Note how the ``verbose`` and ``quiet`` options store their value in the exact same variable. 72 | 73 | **:r:`paste("bash$", command)`** 74 | .. {r} 75 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 76 | .. command <- "example.R --silent -m 5" # same as above but "quiet" 77 | .. .. 78 | 79 | If you specify an illegal flag then *optparse* will throw an error. 80 | 81 | **:r:`paste("bash$", command)`** 82 | .. {r} 83 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 84 | .. command <- "example.R -c 100 -c 2 -c 1000 -c 7" # same as above but "quiet" 85 | .. .. 86 | 87 | If you specify the same option multiple times then *optparse* will use the value of the last option specified. 88 | 89 | **:r:`paste("bash$", command)`** 90 | .. {r} 91 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 92 | .. .. 93 | 94 | *optparse* can also recognize positional arguments if ``parse_args`` is given the option ``positional_arguments = c(min_pa, max_pa)`` where ``min_pa`` is the minimum and ``max_pa`` is the maximum number of supported positional arguments. (A single numeric corresponds to ``min_pa == max_pa``, ``TRUE`` is equivalent to ``c(0, Inf)``, and ``FALSE``, the default, is equivalent to ``0``.) Below we give an example program *display_file.R*, which is a program that prints out the contents of a single file (the required positional argument, not an optional argument) and which accepts the normal help option as well as an option to add line numbers to the output. Note that the positional arguments need to be placed *after* the optional arguments. 95 | 96 | .. {r} 97 | .. command <- "display_file.R --help" 98 | .. .. 99 | **:r:`paste("bash$", command)`** 100 | .. {r} 101 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 102 | .. command <- "display_file.R --add_numbers display_file.R" 103 | .. .. 104 | **:r:`paste("bash$", command)`** 105 | .. {r} 106 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 107 | .. command <- "display_file.R non_existent_file.txt" 108 | .. .. 109 | **:r:`paste("bash$", command)`** 110 | .. {r} 111 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 112 | .. command <- "display_file.R" 113 | .. .. 114 | 115 | **:r:`paste("bash$", command)`** 116 | .. {r} 117 | .. run_command(sprintf("%s %s 2>&1", Rscript_executable, command)) 118 | .. .. 119 | --------------------------------------------------------------------------------