@@ -42,7 +42,7 @@ public class RootCliCommand
4242 public string Option1 { get ; set ; } = " DefaultForOption1" ;
4343
4444 [CliArgument (Description = " Description for Argument1" )]
45- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
45+ public string Argument1 { get ; set ; }
4646
4747 public void Run ()
4848 {
@@ -137,14 +137,43 @@ When you run the app via
137137- `TestApp .exe ` in project output path (e .g . in `TestApp \bin \Debug \net6 .0 `)
138138- or `dotnet run `in project directory (e .g . in `TestApp `)
139139
140+ You see this result :
141+ ```console
142+ Required argument missing for command : 'TestApp' .
143+ ```
144+ This is because a `CliArgument ` decorated property is required by default (`CliArgument .Required ` property 's default value is `true `).
145+ A `CliArgument ` is a parameter for the command itself (for the root command - the exe in this case ), that 's why it' s required by default .
146+
147+ If you want to make a `CliArgument ` optional , set `CliArgument .Required ` property to `false ` and set a default value for the decorated property .
148+ In that case , the default value for the decorated property will be used when the user does not specify the argument on the command line .
149+ ```c #
150+ [CliArgument (Required = false )]
151+ public string Argument1 { get ; set ; } = " DefaultForArgument1" ;
152+ ```
153+ -- -
154+ When you run ,
155+ ```console
156+ TestApp .exe NewValueForArgument1
157+ ```
158+ or (note the double hyphen / dash which allows `dotnet run ` to pass arguments to our actual application ):
159+ ```console
160+ dotnet run -- NewValueForArgument1
161+ ```
140162You see this result :
141163```console
142164Handler for 'TestApp.Commands.RootCliCommand' is run :
143165Value for Option1 property is 'DefaultForOption1'
144- Value for Argument1 property is 'DefaultForArgument1 '
166+ Value for Argument1 property is 'NewValueForArgument1 '
145167```
146- As we set default values for properties in the class , the option and the argument were already populated (even when the user did not pass any values ).
168+ This is because a `CliOption ` decorated property is not required by default (`CliOption .Required ` property 's default value is `false `).
169+ A `CliOption ` is optional , as the name implies , for the command itself (for the root command - the exe in this case ), that 's why it' s not required by default .
147170
171+ If you want to make a `CliOption ` required , set `CliArgument .Required ` property to `true `.
172+ In that case , the default value for the decorated property will be ignored (if exists ) and the user has to specify the option on the command line .
173+ ```c #
174+ [CliOption (Required = true )]
175+ public string Option1 { get ; set ; }
176+ ```
148177-- -
149178When you run ,
150179```console
@@ -179,7 +208,6 @@ The following types for properties is supported:
179208 But an option whose argument type is `bool ` doesn 't require an argument to be specified .
180209 The presence of the option token on the command line , with no argument following it , results in a value of `true `.
181210* Enums - The values are bound by name , and the binding is case insensitive
182- * Arrays and lists (any IEnumerable type )
183211* Common CLR types :
184212
185213 * `string `, `bool `
@@ -191,7 +219,37 @@ The following types for properties is supported:
191219 * `Guid `
192220 * `Uri `, `IPAddress `, `IPEndPoint `
193221
194- * Any type with a public constructor or a static `Parse ` method with a string parameter - These types can be bound / parsed
222+ * Arrays , lists , collections - any type that implements `IEnumerable < T > ` and has a public constructor with a `IEnumerable < T > ` or `IList < T > ` parameter (other parameters , if any , should be optional ).
223+ If type is generic `IEnumerable <T >`, `IList < T > `, `ICollection < T > ` interfaces itself , array `T []` will be used .
224+ If type is non -generic `IEnumerable `, `IList `, `ICollection ` interfaces itself , array `object []` will be used .
225+ ```c #
226+ [CliCommand ]
227+ public class EnumerableCliCommand
228+ {
229+ [CliOption ]
230+ public IEnumerable < int > OptEnumerable { get ; set ; }
231+
232+ [CliOption ]
233+ public List < string > OptList { get ; set ; }
234+
235+ [CliOption (AllowMultipleArgumentsPerToken = true )]
236+ public FileAccess [] OptEnumArray { get ; set ; }
237+
238+ [CliOption ]
239+ public Collection < string > OptCollection { get ; set ; }
240+
241+ [CliOption ]
242+ public HashSet < string > OptHashSet { get ; set ; }
243+
244+ [CliOption ]
245+ public Queue < FileInfo > OptQueue { get ; set ; }
246+
247+ [CliArgument ]
248+ public IList ArgIList { get ; set ; }
249+ }
250+ ```
251+
252+ * Any type with a public constructor or a static `Parse ` method with a string parameter (other parameters , if any , should be optional ) - These types can be bound / parsed
195253 automatically even if they are wrapped with `Enumerable ` or `Nullable ` type .
196254 ```c #
197255 [CliCommand ]
@@ -200,7 +258,7 @@ The following types for properties is supported:
200258 [CliOption ]
201259 public ClassWithConstructor Opt { get ; set ; }
202260
203- [CliOption ]
261+ [CliOption ( AllowMultipleArgumentsPerToken = true ) ]
204262 public ClassWithConstructor [] OptArray { get ; set ; }
205263
206264 [CliOption ]
@@ -212,29 +270,11 @@ The following types for properties is supported:
212270 [CliOption ]
213271 public List < ClassWithConstructor > OptList { get ; set ; }
214272
273+ [CliOption ]
274+ public CustomList < ClassWithConstructor > OptCustomList { get ; set ; }
275+
215276 [CliArgument ]
216277 public IEnumerable < Sub .ClassWithParser > Arg { get ; set ; }
217-
218- public void Run ()
219- {
220- Console .WriteLine ($@" Handler for '{GetType ().FullName }' is run:" );
221-
222- foreach (var property in GetType ().GetProperties ())
223- {
224- var value = property .GetValue (this );
225- if (value is IEnumerable enumerable )
226- value = string .Join (" , " ,
227- enumerable
228- .Cast <object >()
229- .Select (s => s .ToString ())
230- );
231-
232- Console .WriteLine ($@" Value for {property .Name } property is '{value }'" );
233-
234- }
235-
236- Console .WriteLine ();
237- }
238278 }
239279
240280 public class ClassWithConstructor
@@ -251,7 +291,7 @@ The following types for properties is supported:
251291 return value ;
252292 }
253293 }
254-
294+
255295 public struct CustomStruct
256296 {
257297 private readonly string value ;
@@ -271,40 +311,48 @@ The following types for properties is supported:
271311 {
272312 public class ClassWithParser
273313 {
274- private readonly string value ;
275-
276- private ClassWithParser (string value )
277- {
278- this .value = value ;
279- }
314+ public string Value { get ; set ; }
280315
281316 public override string ToString ()
282317 {
283- return value ;
318+ return Value ;
284319 }
285320
286321 public static ClassWithParser Parse (string value )
287322 {
288- return new ClassWithParser (value );
323+ var instance = new ClassWithParser
324+ {
325+ Value = value
326+ };
327+ return instance ;
289328 }
290329 }
291330 }
331+
332+ public class CustomList < T > : List < T >
333+ {
334+ public CustomList (IEnumerable < T > items )
335+ : base (items )
336+ {
337+
338+ }
339+ }
292340 ```
293341
294342## Help output
295343
296344When you run the app via `TestApp .exe - ? ` or `dotnet run -- - ? `, you see this usage help :
297345```console
298- DotMake Command - Line TestApp v1 .4 . 0
346+ DotMake Command - Line TestApp v1 .5 . 4
299347Copyright © 2023 DotMake
300348
301349A root cli command
302350
303351Usage :
304- TestApp [ < argument - 1 > ] [options ]
352+ TestApp < argument - 1 > [options ]
305353
306354Arguments :
307- < argument - 1 > Description for Argument1 [default : DefaultForArgument1 ]
355+ < argument - 1 > Description for Argument1 [required ]
308356
309357Options :
310358 - o , -- option - 1 < option - 1 > Description for Option1 [default : DefaultForOption1 ]
@@ -351,13 +399,13 @@ using DotMake.CommandLine;
351399 NamePrefixConvention = CliNamePrefixConvention .ForwardSlash ,
352400 ShortFormPrefixConvention = CliNamePrefixConvention .ForwardSlash
353401)]
354- public class RootCliCommand
402+ public class RootSnakeSlashCliCommand
355403{
356404 [CliOption (Description = " Description for Option1" )]
357405 public string Option1 { get ; set ; } = " DefaultForOption1" ;
358406
359407 [CliArgument (Description = " Description for Argument1" )]
360- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
408+ public string Argument1 { get ; set ; }
361409
362410 public void Run ()
363411 {
@@ -370,14 +418,16 @@ public class RootCliCommand
370418```
371419When you run the app via `TestApp .exe - ? ` or `dotnet run -- - ? `, you see this usage help :
372420```console
373- Description :
374- A cli command with snake_case name casing and forward slash prefix conventions
421+ DotMake Command - Line TestApp v1 .5 . 4
422+ Copyright © 2023 DotMake
423+
424+ A cli command with snake_case name casing and forward slash prefix conventions
375425
376426Usage :
377- TestApp [ < argument_1 > ] [options ]
427+ TestApp < argument_1 > [options ]
378428
379429Arguments :
380- < argument_1 > Description for Argument1 [default : DefaultForArgument1 ]
430+ < argument_1 > Description for Argument1 [required ]
381431
382432Options :
383433 / o , / option_1 < option_1 > Description for Option1 [default : DefaultForOption1 ]
@@ -413,7 +463,7 @@ public class WithNestedChildrenCliCommand
413463 public string Option1 { get ; set ; } = " DefaultForOption1" ;
414464
415465 [CliArgument (Description = " Description for Argument1" )]
416- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
466+ public string Argument1 { get ; set ; }
417467
418468 public void Run ()
419469 {
@@ -430,7 +480,7 @@ public class WithNestedChildrenCliCommand
430480 public string Option1 { get ; set ; } = " DefaultForOption1" ;
431481
432482 [CliArgument (Description = " Description for Argument1" )]
433- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
483+ public string Argument1 { get ; set ; }
434484
435485 public void Run ()
436486 {
@@ -447,7 +497,7 @@ public class WithNestedChildrenCliCommand
447497 public string Option1 { get ; set ; } = " DefaultForOption1" ;
448498
449499 [CliArgument (Description = " Description for Argument1" )]
450- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
500+ public string Argument1 { get ; set ; }
451501
452502 public void Run ()
453503 {
@@ -472,7 +522,7 @@ public class RootCliCommand
472522 public string Option1 { get ; set ; } = " DefaultForOption1" ;
473523
474524 [CliArgument (Description = " Description for Argument1" )]
475- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
525+ public string Argument1 { get ; set ; }
476526
477527 public void Run ()
478528 {
@@ -494,7 +544,7 @@ public class ExternalLevel1SubCliCommand
494544 public string Option1 { get ; set ; } = " DefaultForOption1" ;
495545
496546 [CliArgument (Description = " Description for Argument1" )]
497- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
547+ public string Argument1 { get ; set ; }
498548
499549 public void Run ()
500550 {
@@ -511,7 +561,7 @@ public class ExternalLevel1SubCliCommand
511561 public string Option1 { get ; set ; } = " DefaultForOption1" ;
512562
513563 [CliArgument (Description = " Description for Argument1" )]
514- public string Argument1 { get ; set ; } = " DefaultForArgument1 " ;
564+ public string Argument1 { get ; set ; }
515565
516566 public void Run ()
517567 {
0 commit comments