You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: control attributes, fix: nullable array fluent collection
* feat: FluentContinueWith and FluentBreak control attributes (wip1)
* docs: add clarifying docstrings
* docs: add clarifying docstrings
* refactor: split method overloads into separate fluent api info groups.
* fix: comment
* feat: FluentContinueWith and FluentBreak control attributes (wip2)
* improve(test): reverse testClassPathAndName array for better readability in the unit test panel
* fix: FluentBreak and FluentContinueWith class names
* test: continue with self
* test: person class with break and continue with attributes
* test: person class with break and continue with attributes
* improve: handling of diagnostics
* refactor: move fluent API additional info from the code board to the fluent API infos.
* refactor: store fluent API info groups in class FluentApiClassAdditionalInfo.
* feat: conflicting control attributes diagnostic
* feat: missing builder step diagnostic
* test: conflicting control attributes and missing builder step
* fix: FluentCollection on a nullable array results in duplicate method signatures
* tidy: remove empty lines
* improve(ExampleProject): add Person class
* feat(StoryBook): add control attributes
* feat: disable warning CS1591 (missing xml comments) in generated files
* feat(SourceGenerator): make new line string configurable
* chore: move unshipped rules analyzer rules to shipped
* chore: increase packages' versions to 1.1.0
* docs: extend and improve readme
* chore: change order in person usage example
* docs: specify .NET 6 as minimum required version
@@ -5,7 +5,7 @@ Everybody wants to use fluent APIs but writing them is tedious. With this librar
5
5
The generated code follows the builder design pattern and allows you to construct objects step by step. This approach avoids big constructors and results in very readable code.
A package reference will be added to your `csproj` file. Moreover, since this library provides code via source code generation, consumers of your project don't need the reference to `M31.FluentAPI`. Therefore, it is recommended to use the `PrivateAssets` metadata tag:
If you would like to examine the generated code, you may emit it by adding the following lines to your `csproj` file:
@@ -39,11 +39,15 @@ If you would like to examine the generated code, you may emit it by adding the f
39
39
40
40
The code can then be found in the `obj/Generated` folder.
41
41
42
-
# Usage
42
+
##Usage
43
43
44
-
If you use this library for the first time I recommend that you read the storybook: [M31.FluentApi.Storybook.csproj>Program.cs](src/M31.FluentApi.Storybook/Program.cs).
44
+
If you use this library for the first time I recommend that you read the storybook:
45
45
46
-
Here is an example that uses all of the available attributes:
-[02 Control attributes](src/M31.FluentApi.Storybook/02_ControlAttributes.cs)
48
+
49
+
50
+
Here is the full example from the introduction to the basics:
47
51
48
52
```cs
49
53
[FluentApi]
@@ -87,89 +91,250 @@ public class Student
87
91
88
92

89
93
90
-
You may have a look at the generated code for this example: [CreateStudent.g.cs](src/M31.FluentApi.Tests/CodeGeneration/TestClasses/StudentClass/CreateStudent.g.cs). Note that if you use private members or properties with a private set accessor, as it is the case in this example, the generated code will use reflection in order to set the properties 'by force'.
94
+
You may have a look at the generated code for this example: [CreateStudent.g.cs](src/M31.FluentApi.Tests/CodeGeneration/TestClasses/StudentClass/CreateStudent.g.cs). Note that if you use private members or properties with a private set accessor, as it is the case in this example, the generated code will use reflection to set the properties.
91
95
92
96
## Attributes
93
97
94
-
The attributes `FluentApi` and `FluentMember` are the basic attributes; they are all you need in order to get started. The attributes `FluentPredicate` and `FluentCollection` can be used instead of a `FluentMember` attribute if the decorated member is a boolean or a collection, respectively. `FluentDefault` and `FluentNullable` are orthogonal attributes and used in combination with the attributes above. Finally, the `FluentMethod` attribute is used for custom implementations.
98
+
The attributes `FluentApi` and `FluentMember` are all you need in order to get started.
95
99
96
-
---
100
+
The attributes `FluentPredicate` and `FluentCollection` can be used instead of a `FluentMember` attribute if the decorated member is a boolean or a collection, respectively.
97
101
98
-
### FluentApi
102
+
`FluentDefault` and `FluentNullable` can be used in combination with these attributes to set a default value or null, respectively.
103
+
104
+
The `FluentMethod` attribute is used for custom builder method implementations.
The control attribute `FluentContinueWith` indicates a jump to the specified builder step, and `FluentBreak` stops the builder.
107
+
108
+
109
+
### FluentApi
101
110
111
+
```cs
112
+
FluentApi(stringbuilderClassName="Create{Name}")
113
+
```
102
114
Use this attribute for your class / struct / record. The optional parameter allows you to specify the name of the builder class that will be generated. Within the argument the template `{Name}` can be used, which will be replaced by the name of your decorated type.
Use this attribute for fields and properties of your class. They can be private but properties must have a set accessor. The `builderStep` parameter specifies the step in which the member can be set. With the `method` parameter you can specify the name of the builder method.
132
+
133
+
```cs
134
+
[FluentMember(0)]
135
+
public string FirstName { get; private set; }
136
+
```
137
+
138
+
```cs
139
+
...WithFirstName("Alice")...
140
+
```
141
+
142
+
If two `FluentMember` attributes with the same builder step and equal method names are specified, a compound method will be created, which is a builder method that sets multiple properties at once. For compounds the position of the parameters can be controlled by the parameter `parameterPosition`.
109
143
110
-
Use this attribute for fields and properties of your class. They can be private but properties must have a set accessor. The `builderStep` parameter specifies the step in which the member can be set. With the method parameter you can specify the name of the builder method.
144
+
```cs
145
+
[FluentMember(0, "Named", 0)]
146
+
publicstringFirstName { get; privateset; }
111
147
112
-
If two `FluentMember` attributes with the same builder step are used, either a compound method or a fork will be created.
113
-
If the specified method names are equal, a compound method will be created, which is a builder method that sets multiple properties at once. See the `WithName` method in the example above. For compounds the position of the parameters can be controlled by the last parameter of this attribute.<br/>
114
-
If the specified method names differ, a fork will be created. That means that there are multiple methods at this step but you can call only one. See the `OfAge` and `BornOn` methods in the example above.
Can be used instead of a `FluentMember` attribute if the decorated member is of type `bool`. This attribute generates two methods, one for setting the value of the member to `true` and one for setting it to `false`.
163
+
Can be used instead of a `FluentMember` attribute if the decorated member is of type `bool`. This attribute generates three methods, one for setting the value of the member to `true`, one for setting it to `false`, and one for passing the boolean value.
164
+
165
+
```cs
166
+
[FluentPredicate(4, "WhoIsHappy", "WhoIsSad")]
167
+
publicboolIsHappy { get; privateset; }
168
+
```
169
+
170
+
```cs
171
+
...WhoIsHappy()...
172
+
...WhoIsSad()...
173
+
...WhoIsHappy(true)...
174
+
```
123
175
124
-
---
125
176
126
177
### FluentCollection
127
178
128
-
**Definition**: FluentCollectionAttribute(
179
+
```cs
180
+
FluentCollection(
129
181
intbuilderStep,
130
182
stringsingularName,
131
183
stringwithItems="With{Name}",
132
184
stringwithItem="With{SingularName}",
133
185
stringwithZeroItems="WithZero{Name}")
186
+
```
134
187
135
188
Can be used instead of a `FluentMember` attribute if the decorated member is a collection. This attribute generates methods for setting multiple items, one item and zero items. The supported collection types can be seen in the source file [CollectionInference.cs](src/M31.FluentApi.Generator/SourceGenerators/Collections/CollectionInference.cs).
Can be used for fields and properties in addition to other attributes. When the generated builder method is called the member will keep its initial value.
Use this attribute on methods to provide a custom implementation for setting values or triggering additional behavior. The decorated method must return `void`.
Can be used at all steps on fields, properties, and methods to jump to a specific builder step. Useful for skipping steps and branching. May be used to create optional builder methods:
Can be used at all steps on fields, properties, and methods to stop the builder. Only relevant for non-linear APIs that make use of `FluentContinueWith`.
158
300
159
-
Use this attribute on methods in order to provide a custom implementation for setting values or triggering additional behavior. The decorated method must return `void`.
301
+
```cs
302
+
[FluentMethod(1)]
303
+
[FluentBreak]
304
+
privatevoidWhoseAddressIsUnknown()
305
+
{
306
+
}
307
+
```
160
308
161
-
# When not to use this library
309
+
```cs
310
+
...WhoseAddressIsUnknown();
311
+
```
162
312
163
-
This library generates a builder class for initializing objects step by step. There are use cases for simpler builder classes that don't offer a step by step initialization. E.g. consider the following API for combining hash codes:
313
+
### Forks
314
+
315
+
To create forks specify builder methods at the same builder step. The resulting API offers all specified methods at this step but only one can be called:
The `Add` and `AddSequence` methods can be called any number of times and in any order. This behavior can not be modeled with the fluent API library. In order to create such a builder class I suggest to write the code by hand, since the implementation is straight forward and does not require a lot of additional code.
171
336
172
-
# Problems with the IDE
337
+
##Problems with the IDE
173
338
174
339
As of 2023 code generation with Roslyn is still a relatively new feature but is already supported quite well in Visual Studio and Rider. Since code generation is potentially triggered with every single key stroke, there are sometimes situations where the code completion index of the IDE does not keep up with all the changes.
175
340
@@ -180,8 +345,8 @@ In particular, if your IDE visually indicates that there are errors in your code
180
345
- Close and reopen the IDE
181
346
- Remove the .vs folder (Visual Studio) or the .idea folder (Rider)
182
347
183
-
#Contributing
348
+
## Support and Contribution
184
349
185
-
Would you like to improve this project? You are kindly invited to contribute. If you would like to implement a new feature, please create a GitHub issue and you will receive timely feedback.
350
+
This library is free. If you find it valuable and wish to express your support, please leave a star. You are kindly invited to contribute. If you see the possibility for enhancement, please create a GitHub issue and you will receive timely feedback.
0 commit comments