reportinator 0.1.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -7
- data/Gemfile.lock +11 -1
- data/README.md +201 -291
- data/app/reports/example.report.json +7 -3
- data/app/reports/multiplication.report.json +1 -1
- data/app/reports/multiplication_v2.report.json +15 -0
- data/data/schema/report_schema.json +76 -0
- data/docs/0_first_report.md +267 -0
- data/lib/reportinator/base.rb +2 -1
- data/lib/reportinator/config.rb +30 -0
- data/lib/reportinator/function.rb +33 -0
- data/lib/reportinator/functions/array/flatten.rb +12 -0
- data/lib/reportinator/functions/array/helper.rb +77 -0
- data/lib/reportinator/functions/array/join.rb +11 -0
- data/lib/reportinator/functions/array/method.rb +9 -0
- data/lib/reportinator/functions/array/range.rb +11 -0
- data/lib/reportinator/functions/array/snippet.rb +30 -0
- data/lib/reportinator/functions/array/string.rb +10 -0
- data/lib/reportinator/functions/array.rb +43 -0
- data/lib/reportinator/functions/string/addition.rb +11 -0
- data/lib/reportinator/functions/string/constant.rb +9 -0
- data/lib/reportinator/functions/string/date.rb +9 -0
- data/lib/reportinator/functions/string/join.rb +10 -0
- data/lib/reportinator/functions/string/logical.rb +14 -0
- data/lib/reportinator/functions/string/number.rb +33 -0
- data/lib/reportinator/functions/string/range.rb +14 -0
- data/lib/reportinator/functions/string/symbol.rb +9 -0
- data/lib/reportinator/functions/string/variable.rb +12 -0
- data/lib/reportinator/functions/string.rb +29 -0
- data/lib/reportinator/helpers.rb +29 -0
- data/lib/reportinator/parser.rb +25 -0
- data/lib/reportinator/parsers/method.rb +8 -3
- data/lib/reportinator/parsers/report.rb +47 -0
- data/lib/reportinator/parsers/value.rb +15 -112
- data/lib/reportinator/report/column.rb +25 -0
- data/lib/reportinator/report/loader.rb +71 -0
- data/lib/reportinator/report/report.rb +33 -0
- data/lib/reportinator/report/row.rb +42 -0
- data/lib/reportinator/report/template.rb +108 -0
- data/lib/reportinator/{report.rb → report_type.rb} +4 -1
- data/lib/reportinator/types/model.rb +15 -7
- data/lib/reportinator/types/preset.rb +23 -2
- data/lib/reportinator/version.rb +1 -1
- data/lib/reportinator.rb +23 -9
- metadata +48 -5
- data/lib/reportinator/loader.rb +0 -112
@@ -0,0 +1,76 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
3
|
+
"$id": "https://moxvallix.com/meta/reportinator/report_schema.json",
|
4
|
+
"title": "Report",
|
5
|
+
"description": "A Reportinator Report",
|
6
|
+
"type": ["array", "object"],
|
7
|
+
"$defs": {
|
8
|
+
"template": {
|
9
|
+
"type": "object",
|
10
|
+
"properties": {
|
11
|
+
"type": {
|
12
|
+
"type": ["string", "array"]
|
13
|
+
},
|
14
|
+
"template": {
|
15
|
+
"type": ["string", "array"]
|
16
|
+
},
|
17
|
+
"metadata": {
|
18
|
+
"type": "object",
|
19
|
+
"properties": {
|
20
|
+
"snippets": {
|
21
|
+
"type": "object"
|
22
|
+
},
|
23
|
+
"variables": {
|
24
|
+
"type": "object"
|
25
|
+
}
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"params": {
|
29
|
+
"type": "object"
|
30
|
+
}
|
31
|
+
},
|
32
|
+
"oneOf": [
|
33
|
+
{
|
34
|
+
"required": ["type"]
|
35
|
+
},
|
36
|
+
{
|
37
|
+
"required": ["template"]
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"allOf": [
|
41
|
+
{
|
42
|
+
"if": {
|
43
|
+
"properties": { "type": { "const": ":preset" } }
|
44
|
+
},
|
45
|
+
"then": {
|
46
|
+
"properties": { "params": { "properties": { "values": { "type": "array" } } } }
|
47
|
+
}
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"if": {
|
51
|
+
"properties": { "type": { "const": ":model" } }
|
52
|
+
},
|
53
|
+
"then": {
|
54
|
+
"properties": {
|
55
|
+
"params": {
|
56
|
+
"properties": {
|
57
|
+
"target": { "type": ["string", "array"] },
|
58
|
+
"method_list": { "type": "array" }
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}
|
66
|
+
},
|
67
|
+
"if": {
|
68
|
+
"type": "object"
|
69
|
+
},
|
70
|
+
"then": {
|
71
|
+
"$ref": "#/$defs/template"
|
72
|
+
},
|
73
|
+
"else": {
|
74
|
+
"properties": { "items": { "$ref": "#/$defs/template" } }
|
75
|
+
}
|
76
|
+
}
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# Creating my First Report
|
2
|
+
Let's start by considering what we want our output to be.
|
3
|
+
Say we want a multiplication table, like such:
|
4
|
+
| nx1 | nx2 | nx3 | nx4 | nx5 |
|
5
|
+
|-----|-----|-----|-----|-----|
|
6
|
+
| 1 | 2 | 3 | 4 | 5 |
|
7
|
+
| 2 | 4 | 6 | 8 | 10 |
|
8
|
+
| 3 | 6 | 9 | 12 | 15 |
|
9
|
+
| 4 | 8 | 12 | 16 | 20 |
|
10
|
+
| 5 | 10 | 15 | 20 | 25 |
|
11
|
+
|
12
|
+
Make a new file in your `app/reports` directory.
|
13
|
+
Name it `multiplication.report.json`
|
14
|
+
|
15
|
+
Set it's type to ":preset". The ":preset" type takes one parameter, "data",
|
16
|
+
and returns any values passed inside it, but with their values parsed.
|
17
|
+
We put a colon in front of the word "preset", such that the value parser
|
18
|
+
knows to turn it into a symbol.
|
19
|
+
|
20
|
+
```
|
21
|
+
{
|
22
|
+
"type": ":preset"
|
23
|
+
}
|
24
|
+
```
|
25
|
+
|
26
|
+
Next we need to give it parameters to be passed into the report.
|
27
|
+
":preset" only accepts the "data" parameter.
|
28
|
+
Add "data" to a "params" object, and set it to be an empty array.
|
29
|
+
|
30
|
+
```
|
31
|
+
{
|
32
|
+
"type": ":preset",
|
33
|
+
"params": {
|
34
|
+
"values": []
|
35
|
+
}
|
36
|
+
}
|
37
|
+
```
|
38
|
+
|
39
|
+
You can now try running this report:
|
40
|
+
|
41
|
+
```
|
42
|
+
> Reportinator.report("multiplication")
|
43
|
+
=> []
|
44
|
+
```
|
45
|
+
|
46
|
+
If all went to plan, you should have gotten an empty array.
|
47
|
+
Let's now add some data to this bad boy.
|
48
|
+
|
49
|
+
```
|
50
|
+
{
|
51
|
+
"type": ":preset",
|
52
|
+
"params": {
|
53
|
+
"values": ["nx1","nx2","nx3","nx4","nx5"]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
```
|
57
|
+
```
|
58
|
+
> Reportinator.report("multiplication")
|
59
|
+
=> [["nx1", "nx2", "nx3", "nx4", "nx5"]]
|
60
|
+
```
|
61
|
+
|
62
|
+
Now we could add the other rows ourselves, by adding more rows to "values":
|
63
|
+
|
64
|
+
```
|
65
|
+
{
|
66
|
+
"type": ":preset",
|
67
|
+
"params": {
|
68
|
+
"values": [
|
69
|
+
["nx1","nx2","nx3","nx4","nx5"],
|
70
|
+
[1, 2, 3, 4, 5],
|
71
|
+
[2, 4, 6, 8, 10],
|
72
|
+
[3, 6, 9, 12, 15],
|
73
|
+
[4, 8, 12, 16, 20],
|
74
|
+
[5, 10, 15, 20, 25]
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
```
|
79
|
+
```
|
80
|
+
> Reportinator.report("multiplication")
|
81
|
+
=>
|
82
|
+
[
|
83
|
+
["nx1", "nx2", "nx3", "nx4", "nx5"],
|
84
|
+
[1, 2, 3, 4, 5],
|
85
|
+
[2, 4, 6, 8, 10],
|
86
|
+
[3, 6, 9, 12, 15],
|
87
|
+
[4, 8, 12, 16, 20],
|
88
|
+
[5, 10, 15, 20, 25]
|
89
|
+
]
|
90
|
+
```
|
91
|
+
|
92
|
+
However, there is a cleaner way of doing this.
|
93
|
+
Move your entire report object inside of an array.
|
94
|
+
This allows us to string reports together in the same template.
|
95
|
+
|
96
|
+
```
|
97
|
+
[
|
98
|
+
{
|
99
|
+
"type": ":preset",
|
100
|
+
"params": {
|
101
|
+
"values": ["nx1","nx2","nx3","nx4","nx5"]
|
102
|
+
}
|
103
|
+
}
|
104
|
+
]
|
105
|
+
```
|
106
|
+
|
107
|
+
Add a new report object underneath the first.
|
108
|
+
This time, the type will be ":model".
|
109
|
+
|
110
|
+
":model" reports take two parameters:
|
111
|
+
1. "target"
|
112
|
+
2. "method_list"
|
113
|
+
|
114
|
+
Add both these keys to the "params" of the second report object.
|
115
|
+
Set both to be an empty array.
|
116
|
+
|
117
|
+
```
|
118
|
+
[
|
119
|
+
{
|
120
|
+
"type": ":preset",
|
121
|
+
"params": {
|
122
|
+
"values": ["nx1","nx2","nx3","nx4","nx5"]
|
123
|
+
}
|
124
|
+
},
|
125
|
+
{
|
126
|
+
"type": ":model",
|
127
|
+
"params": {
|
128
|
+
"target": [],
|
129
|
+
"method_list": []
|
130
|
+
}
|
131
|
+
}
|
132
|
+
]
|
133
|
+
```
|
134
|
+
|
135
|
+
Model reports take a target, as specified in "target", and run methods against it,
|
136
|
+
specified in "method_list", saving the outputs of each to the row.
|
137
|
+
|
138
|
+
If the target is enumerable, said methods will run on each enumeration of the target,
|
139
|
+
each enumeration adding a new row to the report.
|
140
|
+
|
141
|
+
A method is specified by either a symbol, array or hash.
|
142
|
+
Lets take the string "100" as our target.
|
143
|
+
|
144
|
+
If our method was to be `":reverse"`, it would be the same as running"
|
145
|
+
|
146
|
+
```
|
147
|
+
> "100".reverse
|
148
|
+
=> "001"
|
149
|
+
```
|
150
|
+
|
151
|
+
We can chain methods using an array. For example: `[":reverse", ":to_i"]`
|
152
|
+
|
153
|
+
```
|
154
|
+
> "100".reverse.to_i
|
155
|
+
=> 1
|
156
|
+
```
|
157
|
+
|
158
|
+
Methods inside a hash allow for parameters to be passed to the method.
|
159
|
+
The value of the hash are passed as the parameters, and an array is passed
|
160
|
+
as multiple parameters.
|
161
|
+
|
162
|
+
Eg. `{"gsub": ["0", "1"]}`
|
163
|
+
|
164
|
+
```
|
165
|
+
> "100".gsub("0", "1")
|
166
|
+
=> "111"
|
167
|
+
```
|
168
|
+
|
169
|
+
In Ruby, it turns out the multiplication "*" sign is a method.
|
170
|
+
Using this, we can write a much smarter report.
|
171
|
+
|
172
|
+
```
|
173
|
+
[
|
174
|
+
{
|
175
|
+
"type": ":preset",
|
176
|
+
"params": {
|
177
|
+
"values": ["nx1","nx2","nx3","nx4","nx5"]
|
178
|
+
}
|
179
|
+
},
|
180
|
+
{
|
181
|
+
"type": ":model",
|
182
|
+
"params": {
|
183
|
+
"target": [1, 2, 3, 4, 5],
|
184
|
+
"method_list": [{"*": 1},{"*": 2},{"*": 3},{"*": 4},{"*": 5}]
|
185
|
+
}
|
186
|
+
}
|
187
|
+
]
|
188
|
+
```
|
189
|
+
|
190
|
+
The "*" is behaving exactly the same way as our "gsub" example earlier.
|
191
|
+
|
192
|
+
If we run our report again:
|
193
|
+
|
194
|
+
```
|
195
|
+
> Reportinator.report("multiplication")
|
196
|
+
=>
|
197
|
+
[
|
198
|
+
["nx1", "nx2", "nx3", "nx4", "nx5"],
|
199
|
+
[1, 2, 3, 4, 5],
|
200
|
+
[2, 4, 6, 8, 10],
|
201
|
+
[3, 6, 9, 12, 15],
|
202
|
+
[4, 8, 12, 16, 20],
|
203
|
+
[5, 10, 15, 20, 25]
|
204
|
+
]
|
205
|
+
```
|
206
|
+
|
207
|
+
The result should be exactly the same.
|
208
|
+
|
209
|
+
This is pretty good, but we can do better!
|
210
|
+
Notice how the "target" was an array? As it is enumerable,
|
211
|
+
we could run our methods against each element within it.
|
212
|
+
|
213
|
+
But what if we wanted to have 10 rows? Or 50? Soon our array is going to get pretty long.
|
214
|
+
|
215
|
+
This is where a range would be perfect. Set the start value to 1, the end to whatever number we need,
|
216
|
+
and then we go from there.
|
217
|
+
|
218
|
+
Unfortunately, we can't use a range in JSON.
|
219
|
+
|
220
|
+
... or can we?
|
221
|
+
|
222
|
+
Reportinator has a bunch of handy built in functions, for converting strings.
|
223
|
+
We have already seen ":symbol" to make a string into a symbol.
|
224
|
+
|
225
|
+
We won't explore all the functions now, but we will explore "!r".
|
226
|
+
Or more specifically, "!rn", which auto converts strings into numbers as well.
|
227
|
+
|
228
|
+
We can make a range simply by writing "!rn 1,5". It takes the number before the comma,
|
229
|
+
as the start of the range, and the one after as the end.
|
230
|
+
|
231
|
+
We can test this with the actual parse method:
|
232
|
+
|
233
|
+
```
|
234
|
+
> Reportinator.parse("!rn 1, 5")
|
235
|
+
=> (1..5)
|
236
|
+
```
|
237
|
+
|
238
|
+
Let's add this now as the target of our report:
|
239
|
+
|
240
|
+
```
|
241
|
+
[
|
242
|
+
{
|
243
|
+
"type": ":preset",
|
244
|
+
"params": {
|
245
|
+
"values": ["nx1","nx2","nx3","nx4","nx5"]
|
246
|
+
}
|
247
|
+
},
|
248
|
+
{
|
249
|
+
"type": ":model",
|
250
|
+
"params": {
|
251
|
+
"target": "!rn 1,5",
|
252
|
+
"method_list": [{"*": 1},{"*": 2},{"*": 3},{"*": 4},{"*": 5}]
|
253
|
+
}
|
254
|
+
}
|
255
|
+
]
|
256
|
+
```
|
257
|
+
|
258
|
+
Finally, rather than peering at the console to see if it worked,
|
259
|
+
lets put it into a csv.
|
260
|
+
|
261
|
+
```
|
262
|
+
> Reportinator.output("multiplication.csv","multiplication")
|
263
|
+
=> "multiplication.csv"
|
264
|
+
```
|
265
|
+
|
266
|
+
Open the csv up in your spreadsheet viewer of choice, and revel
|
267
|
+
in your brand new report!
|
data/lib/reportinator/base.rb
CHANGED
data/lib/reportinator/config.rb
CHANGED
@@ -6,10 +6,31 @@ module Reportinator
|
|
6
6
|
}
|
7
7
|
DEFAULT_REPORT_DIRS = ["reports", "app/reports"]
|
8
8
|
DEFAULT_REPORT_SUFFIXES = ["report.json", "json"]
|
9
|
+
DEFAULT_FUNCTIONS = [
|
10
|
+
"Reportinator::HelperArrayFunction",
|
11
|
+
"Reportinator::JoinArrayFunction",
|
12
|
+
"Reportinator::RangeArrayFunction",
|
13
|
+
"Reportinator::StringArrayFunction",
|
14
|
+
"Reportinator::SnippetArrayFunction",
|
15
|
+
"Reportinator::FlattenArrayFunction",
|
16
|
+
"Reportinator::MethodArrayFunction",
|
17
|
+
"Reportinator::AdditionStringFunction",
|
18
|
+
"Reportinator::ConstantStringFunction",
|
19
|
+
"Reportinator::DateStringFunction",
|
20
|
+
"Reportinator::JoinStringFunction",
|
21
|
+
"Reportinator::LogicalStringFunction",
|
22
|
+
"Reportinator::NumberStringFunction",
|
23
|
+
"Reportinator::RangeStringFunction",
|
24
|
+
"Reportinator::SymbolStringFunction",
|
25
|
+
"Reportinator::VariableStringFunction"
|
26
|
+
]
|
27
|
+
DEFAULT_UNPARSEDS = [:snippets]
|
9
28
|
|
10
29
|
attribute :report_directories, default: []
|
11
30
|
attribute :report_suffixes, default: []
|
12
31
|
attribute :report_types, default: {}
|
32
|
+
attribute :parser_functions, default: []
|
33
|
+
attribute :unparsed_metadata, default: []
|
13
34
|
attribute :output_directory, default: "reports"
|
14
35
|
|
15
36
|
def configured_directories
|
@@ -24,5 +45,14 @@ module Reportinator
|
|
24
45
|
types = DEFAULT_TYPES
|
25
46
|
types.merge(report_types)
|
26
47
|
end
|
48
|
+
|
49
|
+
def configured_functions
|
50
|
+
functions = DEFAULT_FUNCTIONS + parser_functions
|
51
|
+
functions.map { |function| function.constantize }
|
52
|
+
end
|
53
|
+
|
54
|
+
def configured_metadata
|
55
|
+
DEFAULT_UNPARSEDS + unparsed_metadata
|
56
|
+
end
|
27
57
|
end
|
28
58
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Function < Base
|
3
|
+
attribute :element
|
4
|
+
attribute :metadata, default: {}
|
5
|
+
|
6
|
+
def self.parse(element, metadata = {})
|
7
|
+
new(element: element, metadata: metadata).get
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_value(value)
|
11
|
+
ValueParser.parse(value, metadata)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_and_execute_value(target, value)
|
15
|
+
ValueParser.parse_and_execute(target, value, metadata)
|
16
|
+
end
|
17
|
+
|
18
|
+
def prefixes
|
19
|
+
self.class::PREFIXES
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_prefix(value)
|
25
|
+
raise "Value is not a string" unless value.instance_of? String
|
26
|
+
sorted_prefixes = prefixes.sort.reverse
|
27
|
+
sorted_prefixes.each do |prefix|
|
28
|
+
return prefix if value.start_with? prefix
|
29
|
+
end
|
30
|
+
raise "Value #{value} is incompatible with this function!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class HelperArrayFunction < ArrayFunction
|
3
|
+
PREFIXES = [">strf", ">offset", ">title", ">sum"]
|
4
|
+
|
5
|
+
INTERVALS = {
|
6
|
+
days: {start: "at_beginning_of_day", end: "at_end_of_day"},
|
7
|
+
weeks: {start: "at_beginning_of_week", end: "at_end_of_week"},
|
8
|
+
months: {start: "at_beginning_of_month", end: "at_end_of_month"},
|
9
|
+
years: {start: "at_beginning_of_year", end: "at_end_of_year"}
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_writer :parsed_target, :parsed_values
|
13
|
+
|
14
|
+
def output
|
15
|
+
return parse_strftime if prefix == ">strf"
|
16
|
+
return parse_offset if prefix == ">offset"
|
17
|
+
return parse_title if prefix == ">title"
|
18
|
+
return parse_sum if prefix == ">sum"
|
19
|
+
element
|
20
|
+
end
|
21
|
+
|
22
|
+
def target_to_time
|
23
|
+
parsed_target.to_s.to_time
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_strftime
|
27
|
+
time = target_to_time
|
28
|
+
return "Invalid Time" if time.nil?
|
29
|
+
return "Invalid Format" unless parsed_values[0].instance_of? String
|
30
|
+
time.strftime parsed_values[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_offset
|
34
|
+
time = target_to_time
|
35
|
+
return "Invalid Time" if time.nil?
|
36
|
+
offset = parsed_values[0]
|
37
|
+
return "Missing Offset" unless offset.present?
|
38
|
+
interval = parsed_values[1]
|
39
|
+
snap = parsed_values[2]
|
40
|
+
calculate_offset(time, offset, interval, snap)
|
41
|
+
end
|
42
|
+
|
43
|
+
def calculate_offset(time, offset, interval, snap)
|
44
|
+
interval = (interval.present? ? interval : :months)
|
45
|
+
interval = interval.to_s.pluralize.to_sym
|
46
|
+
return "Invalid Interval" unless INTERVALS.include? interval
|
47
|
+
interval_data = INTERVALS[interval]
|
48
|
+
snap = false unless interval_data.include? snap
|
49
|
+
output = time.advance({interval => offset})
|
50
|
+
output = output.send(interval_data[snap]) if snap.present?
|
51
|
+
output
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_title
|
55
|
+
to_join = [parsed_target] + parsed_values
|
56
|
+
to_join.join(" ").titleize
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_sum
|
60
|
+
sum_values = parsed_values.append parsed_target
|
61
|
+
sum_values.sum { |value| parse_value("!n #{value}") }
|
62
|
+
end
|
63
|
+
|
64
|
+
def parsed_target
|
65
|
+
@parsed_target ||= parse_target
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_target
|
69
|
+
formatted_target = (target.instance_of?(String) ? target.strip : target)
|
70
|
+
parse_value(formatted_target)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parsed_values
|
74
|
+
@parsed_values ||= values.map { |value| parse_value(value) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class JoinArrayFunction < ArrayFunction
|
3
|
+
PREFIXES = [">join"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
joiner = parse_value(target)
|
7
|
+
joiner = (joiner.instance_of?(String) ? joiner : target)
|
8
|
+
values.map { |value| parse_value(value) }.join(joiner)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class SnippetArrayFunction < ArrayFunction
|
3
|
+
PREFIXES = [">snippet"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
name = target
|
7
|
+
name.strip! if name.instance_of? String
|
8
|
+
parsed_name = parse_value(name)
|
9
|
+
snippet = find_snippet(parsed_name)
|
10
|
+
return "Missing Snippet" unless snippet.present?
|
11
|
+
parse_snippet(snippet)
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_snippet(name)
|
15
|
+
snippets = metadata[:snippets]
|
16
|
+
return false unless snippets.present?
|
17
|
+
return false unless snippets[name].present?
|
18
|
+
snippets[name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_snippet(snippet)
|
22
|
+
snippet_metadata = metadata.dup
|
23
|
+
snippet_metadata.delete :snippets
|
24
|
+
variables = values[0]
|
25
|
+
parsed_variables = parse_value(variables)
|
26
|
+
input_metadata = merge_hash(snippet_metadata, {variables: parsed_variables})
|
27
|
+
ValueParser.parse(snippet, input_metadata)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class ArrayFunction < Function
|
3
|
+
PREFIXES = []
|
4
|
+
|
5
|
+
attribute :prefix
|
6
|
+
attribute :target
|
7
|
+
attribute :values
|
8
|
+
|
9
|
+
def self.accepts? input
|
10
|
+
return false unless input.instance_of? Array
|
11
|
+
return false if self::PREFIXES.empty?
|
12
|
+
return false unless input[0].instance_of? String
|
13
|
+
self::PREFIXES.each do |prefix|
|
14
|
+
return true if input[0].start_with? prefix
|
15
|
+
end
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def get
|
20
|
+
raise "Function missing output!" unless respond_to? :output
|
21
|
+
if set_attributes
|
22
|
+
output
|
23
|
+
else
|
24
|
+
element
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_attributes
|
29
|
+
array = element
|
30
|
+
prefix = get_prefix(array[0])
|
31
|
+
target_value = array.delete_at(0).sub(prefix, "")
|
32
|
+
target_value = array.delete_at(0) if target_value.empty?
|
33
|
+
if target_value.to_s.empty?
|
34
|
+
false
|
35
|
+
else
|
36
|
+
self.prefix = prefix
|
37
|
+
self.target = target_value
|
38
|
+
self.values = array
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class AdditionStringFunction < StringFunction
|
3
|
+
PREFIXES = ["!a"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
values = body.split(",").map { |value| parse_value(value.strip) }
|
7
|
+
values.map! { |subvalue| NumberStringFunction.parse("!n #{subvalue}") }
|
8
|
+
values.sum(0)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|