Skip to content

Commit 7c9fe5c

Browse files
committed
Add processors to doc
1 parent 6c82cd7 commit 7c9fe5c

File tree

1 file changed

+240
-1
lines changed

1 file changed

+240
-1
lines changed

doc/files/JSON-CONFIG-PROCESSOR.md

Lines changed: 240 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,240 @@
1-
# JSONConfigProcessors
1+
# JSONConfigProcessors
2+
3+
Is an abstract class from which any custom process must extend. The functionality of this class is a bit advanced, but basically, it serves as a way to create functions to process the user input before or after the property tests.
4+
5+
## Usage
6+
7+
This plugin uses processors as a way to allow the user to execute any custom code during the JSON validation process, in case the functionality provided by this framework is not enough. This page would explain how to use them. But first, let's discuss some behaviour of the validation process.
8+
9+
Each property execute the validation process in three phases:
10+
1. **Preprocess:** The user determines this phase behaviour. However, it can not modify the input data.
11+
2. **Type validation:** This phase executes all the validation tests that we have been discussing in other parts of this documentation.
12+
3. **Postprocess:** The user determines this phase behaviour. This phase can modify the input data.
13+
14+
Whenever an error arises in any of these phases, the process would not execute the following ones. On the other hand, raising warnings would not stop the validation process.
15+
16+
Also, when the process validates a dictionary or [JSONPropertyObject](./JSON-PROPERTY-OBJECT.md), it first executes the preprocess, then its type validation consists on the preprocess, type validation, and postprocess cycle of each of the dictionary properties, and finally it executes the postprocess. The same occurs in [JSONPropertyArray](./JSON-PROPERTY-ARRAY.md).
17+
18+
Finally, on a side note, the process validates the properties of a dictionary in the order they were defined. This fact becomes significant when the custom processes writte and read global variables.
19+
20+
Now we would explain what you can do when using custom processes:
21+
- You can access the property to call its methods, using the 'get_property' method.
22+
- You can raise custom errors and warnings, using the 'add_error' and 'add_warning' metho.
23+
- You can modify the output of a certain property, but only while postprocessing.
24+
- You can set global variables that can be accessed or modify at any point of the validation process, using the 'set_variable', 'has_variable' and 'get_variable' methods.
25+
26+
When creating a new processor, we would need to overwrite the '_preprocess' method, which does not receive the input data and does not return anything, or the '_postprocess' method, which gets the input data as a parameter and returns an output.
27+
28+
## Example: Properties determine the validation process of another property
29+
30+
In this example, the JSON file would contain a 'min' and a 'max' property that would set the minimum and the maximum value of another property 'value':
31+
32+
```JSON
33+
{
34+
"min": 0,
35+
"max": 5,
36+
"value": 2
37+
}
38+
```
39+
40+
To achieve this, we would need three processors in three different scripts. First, the 'set_min' postprocessor:
41+
42+
```GDScript
43+
extends JSONConfigProcessor
44+
45+
# Overwrite the '_postprocess' method
46+
func _postprocess(minimum : int):
47+
# Set a global variable called 'min'
48+
set_variable("min", minimum)
49+
50+
# It is a postprocessor, so it must return a value
51+
return minimum
52+
```
53+
54+
The 'set_max' postprocessor:
55+
56+
```GDScript
57+
extends JSONConfigProcessor
58+
59+
# Overwrite the '_postprocess' method
60+
func _postprocess(maximum : int):
61+
# Set a global variable called 'max'
62+
set_variable("max", maximum)
63+
64+
# It is a postprocessor, so it must return a value
65+
return maximum
66+
```
67+
68+
The 'set_range' preprocessor. It is crucial to notice that we need to check if the variables exists. Just in case the input data is non-valid, and the variables are not declared:
69+
70+
```GDScript
71+
extends JSONConfigProcessor
72+
73+
# Overwrite the '_preprocess' method
74+
func _preprocess():
75+
# Check if the global variable min exists
76+
if has_variable("min"):
77+
# Set the integer minimum value
78+
get_property().set_min_value(get_variable("min"))
79+
# Check if the global variable max exists
80+
if has_variable("max"):
81+
# Set the integer maximum value
82+
get_property().set_max_value(get_variable("max"))
83+
84+
# It is a preprocessor, so it does not return a value
85+
```
86+
87+
Now we can declare a new JSON configuration file that would check if 'value' is between 'min' and 'max':
88+
89+
```GDScript
90+
# Create the 'min' property
91+
var min_value = JSONPropertyInteger.new()
92+
min_value.set_postprocessor(preload("res://set_min.gd").new())
93+
94+
# Create the 'max' property
95+
var max_value = JSONPropertyInteger.new()
96+
max_value.set_postprocessor(preload("res://set_max.gd").new())
97+
98+
# Create the 'value' property
99+
var value = JSONPropertyInteger.new()
100+
value.set_preprocessor(preload("res://set_range.gd").new())
101+
102+
# Create the JSON configuration file
103+
var json_config_file = JSONConfigFile.new()
104+
# Add the 'min' property
105+
json_config_file.add_property("min", min_value)
106+
# Add the 'max' property
107+
json_config_file.add_property("max", max_value)
108+
# Add the 'value' property
109+
json_config_file.add_property("value", value)
110+
111+
# Validate input
112+
json_config_file.validate(json_file_path)
113+
```
114+
115+
## Example: Transforming an enum into an integer
116+
In this case, we want the user to introduce an enum. This field would be a string on the final dictionary, but we can transform this field to be an integer that represents a value of a Godot's enum. For this purpose, we must define a postprocessor called 'transform_gender_enum' that looks like this:
117+
118+
```GDScript
119+
extends JSONConfigProcessor
120+
121+
122+
enum Genders{
123+
MALE,
124+
FEMALE,
125+
NON_BINARY
126+
}
127+
128+
129+
func _postprocess(gender : String):
130+
match gender:
131+
"MALE":
132+
return Genders.MALE
133+
"FEMALE":
134+
return Genders.FEMALE
135+
"NON_BINARY":
136+
return Genders.NON_BINARY
137+
138+
return -1
139+
```
140+
141+
Then we can create the following JSON configuration file:
142+
143+
```GDScript
144+
# Create the 'gender' property
145+
var gender = JSONPropertyEnum.new()
146+
gender.set_enum(["MALE", "FEMALE", "NON_BINARY"])
147+
gender.set_postprocessor(preload("res://transform_gender_enum.gd").new())
148+
149+
# Create the JSON configuration file
150+
var json_config_file = JSONConfigFile.new()
151+
# Add the 'gender' property
152+
json_config_file.add_property("gender", gender)
153+
154+
# Validate input
155+
json_config_file.validate(json_file_path)
156+
```
157+
158+
Using this method, this JSON file:
159+
160+
```JSON
161+
{
162+
"gender": "MALE"
163+
}
164+
```
165+
166+
Would generate this dictionary:
167+
168+
```GDScript
169+
{
170+
"gender": Genders.MALE
171+
}
172+
```
173+
174+
## Example: Primes validation
175+
176+
In this last example, we would raise a custom error. We will check if an integer is a prime. For this purpose, we need to create another postprocessor called 'prime_check':
177+
178+
```GDScript
179+
extends JSONConfigProcessor
180+
181+
182+
func _postprocess(integer : int):
183+
# One is not a prime >:(
184+
if integer == 1:
185+
add_error({"error": "This is not a prime"})
186+
return null
187+
188+
# A simple prime check
189+
for i in range(2, sqrt(integer) + 1):
190+
# If is not prime
191+
if integer % i == 0:
192+
add_error({"error": "This is not a prime"})
193+
return null
194+
195+
return integer
196+
```
197+
198+
Now we can create the following JSON configuration file:
199+
200+
```GDScript
201+
# Create the 'prime' property
202+
var prime = JSONPropertyInteger.new()
203+
prime.set_postprocessor(preload("res://prime_check.gd").new())
204+
205+
# Create the JSON configuration file
206+
var json_config_file = JSONConfigFile.new()
207+
# Add the 'prime' property
208+
json_config_file.add_property("prime", prime)
209+
210+
# Validate input
211+
json_config_file.validate(json_file_path)
212+
```
213+
214+
In this case, this JSON file would not raise any error:
215+
216+
```JSON
217+
{
218+
"prime": 7
219+
}
220+
```
221+
222+
This file, on the other hand, would raise our custom error:
223+
224+
```JSON
225+
{
226+
"prime": 4
227+
}
228+
```
229+
230+
Returned error:
231+
232+
```GDScript
233+
[
234+
{
235+
"error": "This is not a prime",
236+
"context": "prime",
237+
"as_text": "This is not a prime, at 'prime'."
238+
}
239+
]
240+
```

0 commit comments

Comments
 (0)