Skip to content

Commit 1d07e54

Browse files
authored
V0.2
Changes for version 0.2.0 Testing, new documentation, new output formats, deprecate @beginarguments
1 parent 2a194c8 commit 1d07e54

16 files changed

+734
-143
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020 zachmatson
3+
Copyright (c) 2020 Zachary Matson
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ArgMacros"
22
uuid = "dbc42088-9de8-42a0-8ec8-2cd114e1ea3e"
33
authors = ["zachmatson"]
4-
version = "0.1.3"
4+
version = "0.2.0"
55

66
[deps]
77
TextWrap = "b718987f-49a8-5099-9789-dcd902bef87d"

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
push!(LOAD_PATH,"../src/")
1+
prepend!(LOAD_PATH, ["../src/"])
22

33
using Documenter
44
using ArgMacros

docs/src/index.md

Lines changed: 127 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Reading through this before using the package is recommended.
55

66
!!! note
77

8-
Version 0.1.x of ArgMacros might be rough around some edge cases.
8+
Version 0.2.x of ArgMacros might be rough around some edge cases.
99
Make sure to test the interface you build before using it.
1010
If you notice any issues or want to request new features, create an issue on
1111
[GitHub](https://github.com/zachmatson/ArgMacros.jl)
@@ -14,37 +14,45 @@ Reading through this before using the package is recommended.
1414

1515
ArgMacros is designed for parsing arguments in command-line Julia scripts.
1616
Compilation time is the greatest bottleneck for startup of scripts in Julia,
17-
and is mostly unavoidable. While attention is paid to making
18-
code that compiles relatively quickly, the emphasis of ArgMacros is on quick
19-
parsing and type stability after compilation.
17+
and is mostly unavoidable. ArgMacros provides quick parsing after compilation while
18+
ensuring compilation time fast too.
2019

21-
Variables created using ArgMacros are statically typed,
22-
and available immediately within your main function, without manually
23-
retrieving them from an intermediate data structure. This can also make it
24-
more convenient when writing scripts.
20+
ArgMacros also provides convenience when writing scripts by offering various and easily
21+
interchangeable formats for outputting parsed arguments, a simple interface, and guaranteed
22+
type safety of parsed arguments. Some output formats also provide static typing of the
23+
argument variables.
2524

2625
## Installation
2726

2827
Install ArgMacros using Julia's Pkg package manager. Enter the Pkg prompt
2928
by typing `]` at the REPL and then install:
3029

3130
```julia-repl
32-
(@v1.4) pkg> add ArgMacros
31+
(@v1.5) pkg> add ArgMacros
3332
```
3433

3534
Then load ArgMacros into your script with `using ArgMacros`.
3635

36+
## Argument Format Types
37+
38+
There are four formats for your program or script to receive the parsed arguments with ArgMacros,
39+
all of which use the same interface for argument declaration:
40+
* Inline, typed local variables ([`@inlinearguments`](@ref))
41+
* An automatically generated custom `struct` type ([`@structarguments`](@ref))
42+
* `NamedTuple` ([`@tuplearguments`](@ref))
43+
* `Dict` ([`@dictarguments`](@ref))
44+
3745
## Adding Arguments
3846

3947
All arguments must be declared using the macros provided, and all of the declarations must
40-
exist within the [`@beginarguments`](@ref) block like so:
48+
exist within the [`@inlinearguments`](@ref) block, or other argument macro block, like so:
4149
```julia
42-
@beginarguments begin
50+
@inlinearguments begin
4351
*arguments go here*
4452
end
4553
```
4654

47-
The types of arguments supported are broken down into two main categories:
55+
The types of arguments supported are broken down into two categories:
4856
* Options (`@argument...`) - Marked with flags
4957
- [`@argumentrequired`](@ref)
5058
- [`@argumentdefault`](@ref)
@@ -68,9 +76,11 @@ For this reason, ALL options must be declared before ANY positionals, required
6876
positionals must be declared before default/optional ones, and positional arguments
6977
must be declared in the order the user is expected to enter them.
7078

79+
You should make your argument types `Symbol`, `String`, or subtypes of `Number`.
80+
7181
Here is an example with some arguments:
7282
```julia
73-
@beginarguments begin
83+
@inlinearguments begin
7484
@argumentrequired String foo "-f" "--foo"
7585
@argumentdefault String "lorem ipsum" bar "--bar"
7686
@argumentflag verbose "-v"
@@ -94,17 +104,23 @@ of the name of local variable they will be stored in.
94104

95105
## Using Argument Values
96106

97-
Once an argument is decalred, it is statically typed and you can be sure it holds a value of the
107+
Once an argument is decalred, you can be sure it holds a value of the
98108
correct type. [`@argumentoptional`](@ref) and [`@positionaloptional`](@ref) will use the type `Union{T, Nothing}`,
99109
however, and may also contain `nothing`. [`@argumentflag`](@ref) uses `Bool` and [`@argumentcount`](@ref) uses `Int`.
100-
The other macros will all store the type specified. No additional code is required to begin using the
101-
argument value after parsing.
110+
The other macros will all store the type specified.
102111

103-
You should make your argument types `Symbol`, `String`, or subtypes of `Number`.
112+
How exactly you use the values depends on the format used, the following will demonstrate the same arguments
113+
with each of the available formats, and some of the consequences of each of them:
114+
115+
### Inline ([`@inlinearguments`](@ref))
116+
117+
The arguments are stored directly in local variables, which are statically typed. You can use them immediately
118+
without any other boilerplate, but must respect the variable types. These variables, because they are typed, must
119+
always be in local scope. You cannot put this block in a global scope.
104120

105121
```julia
106122
function main()
107-
@beginarguments begin
123+
@inlinearguments begin
108124
@positionalrequired Int x
109125
@positionaldefault Int 5 y
110126
@positionaloptional Int z
@@ -119,17 +135,98 @@ function main()
119135
end
120136
```
121137

138+
### Custom `struct` ([`@structarguments`](@ref))
139+
140+
A new `struct` type is created to store the arguments, and you can decide if it will be mutable.
141+
The zero-argument constructor function for the new type parses the arguments when it is called.
142+
You must *declare* the arguments in global scope due to the rules for type declarations,
143+
but the constructor can be used anywhere.
144+
145+
The fields of the struct will all be typed.
146+
147+
```julia
148+
# Declare mutable type Args and the arguments it will hold
149+
@structarguments true Args begin
150+
@positionalrequired Int x
151+
@positionaldefault Int 5 y
152+
@positionaloptional Int z
153+
end
154+
155+
function main()
156+
args = Args() # The arguments are parsed here
157+
158+
println(args.x + args.y) # Prints x + y, the variables must be Ints
159+
println(isnothing(args.z)) # z might be nothing, because it was optional
160+
161+
# These assignemnt operations would all fail if we made Args immutable instead
162+
args.z = nothing # It is fine to store values of type Nothing or Int in z now
163+
args.z = 8
164+
args.x = 5.5 # Raises an error, x must hold Int values
165+
args.y = nothing # Raises an error, only optional arguments can hold nothing
166+
end
167+
```
168+
169+
### `NamedTuple` ([`@tuplearguments`](@ref))
170+
171+
A `NamedTuple` is returned containing all of the argument values, keyed by the variable names given. You can use this
172+
version from any scope. All of the fields are typed, and as a `NamedTuple` the returned object will be immutable.
173+
174+
```julia
175+
function main()
176+
args = @tuplearguments begin
177+
@positionalrequired Int x
178+
@positionaldefault Int 5 y
179+
@positionaloptional Int z
180+
end
181+
182+
println(args.x + args.y) # Prints x + y, the variables must be Ints
183+
println(isnothing(args.z)) # z might be nothing, because it was optional
184+
185+
# These assignemnt operations will fail because NamedTuples are always immutable
186+
args.z = nothing
187+
args.z = 8
188+
189+
args.x == 5.5 # Can never be true, args.x is guaranteed to be an Int
190+
isnothing(args.y) # Must be false, y is not optional
191+
end
192+
```
193+
194+
### `Dict` ([`@dictarguments`](@ref))
195+
196+
A `Dict{Symbol, Any}` is returned containing all of the argument variables, keyed by the argument names as *`Symbol`s*. You can use
197+
this version from any scope. The `Dict` type is mutable, and any type can be stored in any of its fields. Therefore, this version
198+
does not provide as strong of a guarantee about types to the compuler when argument values are used later. However, the values
199+
are guaranteed to be of the correct types when the `Dict` is first returned.
200+
201+
```julia
202+
function main()
203+
args = @dictarguments begin
204+
@positionalrequired Int x
205+
@positionaldefault Int 5 y
206+
@positionaloptional Int z
207+
end
208+
209+
println(args[:x] + args[:y]) # Prints x + y, the variable names are available right away and must be Ints at first
210+
println(isnothing(args[:z])) # z might be nothing, because it was optional
211+
args[:z] = nothing # It is fine to store values of any type in z now
212+
args[:z] = 8
213+
args[:x] = 5.5 # Same for x
214+
args[:y] = nothing # And y
215+
args[:a] = "some string" # New entries can even be added later, of any type
216+
end
217+
```
218+
122219
## Validating Arguments
123220

124221
Perhaps you want to impose certain conditions on the values of an argument beyond its type.
125222
You can use the [`@argtest`](@ref) macro, which will exit the program if a specified unary predicate returns
126223
`false` for the argument value.
127224

128-
If using an anonymous function for this, make sure to enclose it in parentheses so it is passed to the
129-
macro as a single expression.
225+
If using an operator function, make sure to enclose it in parentheses so it is passed to the
226+
macro as a separate expression from the first argument.
130227

131228
```julia
132-
@beginarguments begin
229+
@inlinearguments begin
133230
...
134231
@positionalrequired String input "input_file"
135232
@argtest input isfile "The input must be a valid file" # Confirm that the input file really exists
@@ -146,10 +243,10 @@ When using the [`@arghelp`](@ref) macro, note that it always applies to the last
146243
The [`@helpusage`](@ref) will prepend your usage text with "Usage: ", so do not include this in the string you pass.
147244

148245
It is recommended to place [`@helpusage`](@ref), [`@helpdescription`](@ref), and [`@helpepilog`](@ref) in that order at the
149-
beginning of the [`@beginarguments`](@ref) block, but this is not a requirement.
246+
beginning of the `@...arguments` block, but this is not a requirement.
150247

151248
```julia
152-
@beginarguments begin
249+
@inlinearguments begin
153250
@helpusage "example.jl input_file [output_file] [-f | --foo] [--bar] [-v]"
154251
@helpdescription """
155252
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
@@ -172,11 +269,11 @@ end
172269
By default, the program will exit and print a warning if more arguments are given than the program declares.
173270
If you don't want this to happen, include the [`@allowextraarguments`](@ref) macro.
174271

175-
This can occur anywhere inside the [`@beginarguments`](@ref) block, but the recommended placement is at the end,
272+
This can occur anywhere inside the `@...arguments` block, but the recommended placement is at the end,
176273
after all other help, test, and argument declarations.
177274

178275
```julia
179-
@beginarguments begin
276+
@inlinearguments begin
180277
...
181278
@allowextraarguments
182279
end
@@ -185,7 +282,7 @@ end
185282
## Taking Argument Code out of Main Function
186283

187284
It may be preferable, in some cases, not to declare all of your arguments and help information
188-
inside of your main function. In this case, the [`@beginarguments`](@ref) block can be enclosed
285+
inside of your main function. In this case, the [`@inlinearguments`](@ref) block can be enclosed
189286
in a macro:
190287

191288
```julia
@@ -203,3 +300,7 @@ function main()
203300
# The argument values will be available here
204301
end
205302
```
303+
304+
The [`@structarguments`](@ref) must be used in a global scope, but its constructor can then be used anywhere.
305+
The other forms which directly return an object can be placed into an external function because they don't rely
306+
on being in the same namespace as the point where the arguments are used, as [`@inlinearguments`](@ref) does.

docs/src/macros.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
# Available Macros
22

3-
## `@beginarguments`
3+
## `@...arguments`
44

5-
The `@beginarguments begin ... end` block will hold all of your `ArgMacros` code.
6-
You shouldn't have to worry about this macro as long as you use it to enclose your other code.
5+
The `@...arguments begin ... end` block will hold all of your `ArgMacros` code.
6+
The [Using Argument Values](@ref) section provides a good comparison of the different available macros.
77
```@docs
8-
@beginarguments
8+
@inlinearguments
9+
@structarguments
10+
@tuplearguments
11+
@dictarguments
912
```
1013

1114
## Option Arguments

src/ArgMacros.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ end
88
using TextWrap
99
using Base: @kwdef
1010

11-
export @beginarguments
11+
export @beginarguments, @inlinearguments, @structarguments,
12+
@tuplearguments, @dictarguments
1213
export @helpusage, @helpdescription, @helpepilog
1314
export @argumentrequired, @argumentdefault, @argumentoptional,
1415
@argumentflag, @argumentcount
@@ -35,7 +36,7 @@ results in typed local variables.
3536
Basic usage:
3637
```julia
3738
julia_main()
38-
@beginarguments begin
39+
@inlinearguments begin
3940
@argumentrequired Int foo "-f" "--foo"
4041
@argumentdefault Int 5 bar "-b" "--bar"
4142
...

src/constants.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
# ArgMacros
22
# constants.jl
33

4-
const usage_symbol = Symbol("@helpusage")
5-
const description_symbol = Symbol("@helpdescription")
6-
const epilog_symbol = Symbol("@helpepilog")
7-
const arghelp_symbol = Symbol("@arghelp")
4+
const USAGE_SYMBOL = Symbol("@helpusage")
5+
const DESCRIPTION_SYMBOL = Symbol("@helpdescription")
6+
const EPILOG_SYMBOL = Symbol("@helpepilog")
7+
const ARGHELP_SYMBOL = Symbol("@arghelp")
88

9-
const argument_required_symbol = Symbol("@argumentrequired")
10-
const argument_default_symbol = Symbol("@argumentdefault")
11-
const argument_optional_symbol = Symbol("@argumentoptional")
12-
const argument_flag_symbol = Symbol("@argumentflag")
13-
const argument_count_symbol = Symbol("@argumentcount")
14-
const flagged_symbols = [argument_required_symbol, argument_default_symbol, argument_optional_symbol,
15-
argument_flag_symbol, argument_count_symbol]
9+
const ARGUMENT_REQUIRED_SYMBOL = Symbol("@argumentrequired")
10+
const ARGUMENT_DEFAULT_SYMBOL = Symbol("@argumentdefault")
11+
const ARGUMENT_OPTIONAL_SYMBOL = Symbol("@argumentoptional")
12+
const ARGUMENT_FLAG_SYMBOL = Symbol("@argumentflag")
13+
const ARGUMENT_COUNT_SYMBOL = Symbol("@argumentcount")
14+
const FLAGGED_SYMBOLS = [ARGUMENT_REQUIRED_SYMBOL, ARGUMENT_DEFAULT_SYMBOL, ARGUMENT_OPTIONAL_SYMBOL,
15+
ARGUMENT_FLAG_SYMBOL, ARGUMENT_COUNT_SYMBOL]
1616

17-
const positional_required_symbol = Symbol("@positionalrequired")
18-
const positional_default_symbol = Symbol("@positionaldefault")
19-
const positional_optional_symbol = Symbol("@positionaloptional")
20-
const positional_optional_symbols = [positional_default_symbol, positional_optional_symbol]
17+
const POSITIONAL_REQUIRED_SYMBOL = Symbol("@positionalrequired")
18+
const POSITIONAL_DEFAULT_SYMBOL = Symbol("@positionaldefault")
19+
const POSITIONAL_OPTIONAL_SYMBOL = Symbol("@positionaloptional")
20+
const POSITIONAL_OPTIONAL_SYMBOLS = [POSITIONAL_DEFAULT_SYMBOL, POSITIONAL_OPTIONAL_SYMBOL]

0 commit comments

Comments
 (0)