@@ -5,7 +5,7 @@ Reading through this before using the package is recommended.
5
5
6
6
!!! note
7
7
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.
9
9
Make sure to test the interface you build before using it.
10
10
If you notice any issues or want to request new features, create an issue on
11
11
[GitHub](https://github.com/zachmatson/ArgMacros.jl)
@@ -14,37 +14,45 @@ Reading through this before using the package is recommended.
14
14
15
15
ArgMacros is designed for parsing arguments in command-line Julia scripts.
16
16
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.
20
19
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 .
25
24
26
25
## Installation
27
26
28
27
Install ArgMacros using Julia's Pkg package manager. Enter the Pkg prompt
29
28
by typing ` ] ` at the REPL and then install:
30
29
31
30
``` julia-repl
32
- (@v1.4 ) pkg> add ArgMacros
31
+ (@v1.5 ) pkg> add ArgMacros
33
32
```
34
33
35
34
Then load ArgMacros into your script with ` using ArgMacros ` .
36
35
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
+
37
45
## Adding Arguments
38
46
39
47
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:
41
49
``` julia
42
- @beginarguments begin
50
+ @inlinearguments begin
43
51
* arguments go here*
44
52
end
45
53
```
46
54
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:
48
56
* Options (` @argument... ` ) - Marked with flags
49
57
- [ ` @argumentrequired ` ] ( @ref )
50
58
- [ ` @argumentdefault ` ] ( @ref )
@@ -68,9 +76,11 @@ For this reason, ALL options must be declared before ANY positionals, required
68
76
positionals must be declared before default/optional ones, and positional arguments
69
77
must be declared in the order the user is expected to enter them.
70
78
79
+ You should make your argument types ` Symbol ` , ` String ` , or subtypes of ` Number ` .
80
+
71
81
Here is an example with some arguments:
72
82
``` julia
73
- @beginarguments begin
83
+ @inlinearguments begin
74
84
@argumentrequired String foo " -f" " --foo"
75
85
@argumentdefault String " lorem ipsum" bar " --bar"
76
86
@argumentflag verbose " -v"
@@ -94,17 +104,23 @@ of the name of local variable they will be stored in.
94
104
95
105
## Using Argument Values
96
106
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
98
108
correct type. [ ` @argumentoptional ` ] ( @ref ) and [ ` @positionaloptional ` ] ( @ref ) will use the type ` Union{T, Nothing} ` ,
99
109
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.
102
111
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.
104
120
105
121
``` julia
106
122
function main ()
107
- @beginarguments begin
123
+ @inlinearguments begin
108
124
@positionalrequired Int x
109
125
@positionaldefault Int 5 y
110
126
@positionaloptional Int z
@@ -119,17 +135,98 @@ function main()
119
135
end
120
136
```
121
137
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
+
122
219
## Validating Arguments
123
220
124
221
Perhaps you want to impose certain conditions on the values of an argument beyond its type.
125
222
You can use the [ ` @argtest ` ] ( @ref ) macro, which will exit the program if a specified unary predicate returns
126
223
` false ` for the argument value.
127
224
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 .
130
227
131
228
``` julia
132
- @beginarguments begin
229
+ @inlinearguments begin
133
230
...
134
231
@positionalrequired String input " input_file"
135
232
@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
146
243
The [ ` @helpusage ` ] ( @ref ) will prepend your usage text with "Usage: ", so do not include this in the string you pass.
147
244
148
245
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.
150
247
151
248
``` julia
152
- @beginarguments begin
249
+ @inlinearguments begin
153
250
@helpusage " example.jl input_file [output_file] [-f | --foo] [--bar] [-v]"
154
251
@helpdescription """
155
252
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
@@ -172,11 +269,11 @@ end
172
269
By default, the program will exit and print a warning if more arguments are given than the program declares.
173
270
If you don't want this to happen, include the [ ` @allowextraarguments ` ] ( @ref ) macro.
174
271
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,
176
273
after all other help, test, and argument declarations.
177
274
178
275
``` julia
179
- @beginarguments begin
276
+ @inlinearguments begin
180
277
...
181
278
@allowextraarguments
182
279
end
185
282
## Taking Argument Code out of Main Function
186
283
187
284
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
189
286
in a macro:
190
287
191
288
``` julia
@@ -203,3 +300,7 @@ function main()
203
300
# The argument values will be available here
204
301
end
205
302
```
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.
0 commit comments