reportinator 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -2
- data/Gemfile.lock +1 -1
- data/README.md +127 -308
- data/docs/0_first_report.md +267 -0
- data/lib/reportinator/base.rb +24 -0
- data/lib/reportinator/config.rb +20 -0
- data/lib/reportinator/function.rb +33 -0
- data/lib/reportinator/functions/array/helper.rb +71 -0
- data/lib/reportinator/functions/array/join.rb +11 -0
- data/lib/reportinator/functions/array/method.rb +9 -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 +11 -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 +10 -0
- data/lib/reportinator/functions/string.rb +29 -0
- data/lib/reportinator/loader.rb +11 -3
- data/lib/reportinator/parser.rb +25 -0
- data/lib/reportinator/parsers/method.rb +5 -3
- data/lib/reportinator/parsers/report.rb +47 -0
- data/lib/reportinator/parsers/value.rb +5 -102
- data/lib/reportinator/types/model.rb +8 -5
- data/lib/reportinator/version.rb +1 -1
- data/lib/reportinator.rb +6 -24
- metadata +21 -2
@@ -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
|
+
"data": []
|
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
|
+
"data": ["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 "data":
|
63
|
+
|
64
|
+
```
|
65
|
+
{
|
66
|
+
"type": ":preset",
|
67
|
+
"params": {
|
68
|
+
"data": [
|
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
|
+
"data": ["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
|
+
"data": ["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
|
+
"data": ["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
|
+
"data": ["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!
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Base
|
3
|
+
include ActiveModel::API
|
4
|
+
include ActiveModel::Attributes
|
5
|
+
|
6
|
+
require_rel "."
|
7
|
+
|
8
|
+
def self.config
|
9
|
+
Reportinator.config
|
10
|
+
end
|
11
|
+
|
12
|
+
def config
|
13
|
+
self.class.config
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.logger
|
17
|
+
Reportinator.logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def logger
|
21
|
+
self.class.logger
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/reportinator/config.rb
CHANGED
@@ -6,10 +6,25 @@ 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::MethodArrayFunction",
|
13
|
+
"Reportinator::AdditionStringFunction",
|
14
|
+
"Reportinator::ConstantStringFunction",
|
15
|
+
"Reportinator::DateStringFunction",
|
16
|
+
"Reportinator::JoinStringFunction",
|
17
|
+
"Reportinator::LogicalStringFunction",
|
18
|
+
"Reportinator::NumberStringFunction",
|
19
|
+
"Reportinator::RangeStringFunction",
|
20
|
+
"Reportinator::SymbolStringFunction",
|
21
|
+
"Reportinator::VariableStringFunction"
|
22
|
+
]
|
9
23
|
|
10
24
|
attribute :report_directories, default: []
|
11
25
|
attribute :report_suffixes, default: []
|
12
26
|
attribute :report_types, default: {}
|
27
|
+
attribute :parser_functions, default: []
|
13
28
|
attribute :output_directory, default: "reports"
|
14
29
|
|
15
30
|
def configured_directories
|
@@ -24,5 +39,10 @@ module Reportinator
|
|
24
39
|
types = DEFAULT_TYPES
|
25
40
|
types.merge(report_types)
|
26
41
|
end
|
42
|
+
|
43
|
+
def configured_functions
|
44
|
+
functions = DEFAULT_FUNCTIONS + parser_functions
|
45
|
+
functions.map { |function| function.constantize }
|
46
|
+
end
|
27
47
|
end
|
28
48
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Function < Base
|
3
|
+
attribute :element
|
4
|
+
attribute :variables, default: {}
|
5
|
+
|
6
|
+
def self.parse(element, variables = {})
|
7
|
+
new(element: element, variables: variables).get
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_value(value)
|
11
|
+
ValueParser.parse(value, variables)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_and_execute_value(target, value)
|
15
|
+
ValueParser.parse_and_execute(target, value, variables)
|
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,71 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class HelperArrayFunction < ArrayFunction
|
3
|
+
PREFIXES = [">strf", ">offset", ">title"]
|
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
|
+
element
|
19
|
+
end
|
20
|
+
|
21
|
+
def target_to_time
|
22
|
+
parsed_target.to_s.to_time
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_strftime
|
26
|
+
time = target_to_time
|
27
|
+
return "Invalid Time" if time.nil?
|
28
|
+
return "Invalid Format" unless parsed_values[0].instance_of? String
|
29
|
+
time.strftime parsed_values[0]
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_offset
|
33
|
+
time = target_to_time
|
34
|
+
return "Invalid Time" if time.nil?
|
35
|
+
offset = parsed_values[0]
|
36
|
+
return "Missing Offset" unless offset.present?
|
37
|
+
interval = parsed_values[1]
|
38
|
+
snap = parsed_values[2]
|
39
|
+
calculate_offset(time, offset, interval, snap)
|
40
|
+
end
|
41
|
+
|
42
|
+
def calculate_offset(time, offset, interval, snap)
|
43
|
+
interval = (interval.present? ? interval : :months)
|
44
|
+
interval = interval.to_s.pluralize.to_sym
|
45
|
+
return "Invalid Interval" unless INTERVALS.include? interval
|
46
|
+
interval_data = INTERVALS[interval]
|
47
|
+
snap = false unless interval_data.include? snap
|
48
|
+
output = time.advance({interval => offset})
|
49
|
+
output = output.send(interval_data[snap]) if snap.present?
|
50
|
+
output
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_title
|
54
|
+
to_join = [parsed_target] + parsed_values
|
55
|
+
to_join.join(" ").titleize
|
56
|
+
end
|
57
|
+
|
58
|
+
def parsed_target
|
59
|
+
@parsed_target ||= parse_target
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_target
|
63
|
+
formatted_target = (target.instance_of?(String) ? target.strip : target)
|
64
|
+
parse_value(formatted_target)
|
65
|
+
end
|
66
|
+
|
67
|
+
def parsed_values
|
68
|
+
@parsed_values ||= values.map { |value| parse_value(value) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class JoinArrayFunction < ArrayFunction
|
3
|
+
PREFIXES = [">join"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
joiner = ValueParser.parse(target, variables)
|
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,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
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class LogicalStringFunction < StringFunction
|
3
|
+
PREFIXES = ["@true", "@false", "@nil", "@null"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
case prefix
|
7
|
+
when "@true" then true
|
8
|
+
when "@false" then false
|
9
|
+
when "@nil", "@null" then nil
|
10
|
+
else element
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class RangeStringFunction < StringFunction
|
3
|
+
PREFIXES = ["!r", "!rd", "!rn"]
|
4
|
+
|
5
|
+
def output
|
6
|
+
values = body.split(",").map { |value| parse_value(value.strip) }
|
7
|
+
case prefix
|
8
|
+
when "!rn" then values.map! { |subvalue| NumberStringFunction.parse("!n #{subvalue}") }
|
9
|
+
when "!rd" then values.map! { |subvalue| DateStringFunction.parse("!d #{subvalue}") }
|
10
|
+
end
|
11
|
+
Range.new(*values)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class StringFunction < Function
|
3
|
+
PREFIXES = []
|
4
|
+
|
5
|
+
attribute :prefix
|
6
|
+
attribute :body
|
7
|
+
|
8
|
+
def self.accepts? input
|
9
|
+
return false unless input.instance_of? String
|
10
|
+
return false if self::PREFIXES.empty?
|
11
|
+
self::PREFIXES.each do |prefix|
|
12
|
+
return true if input.start_with? prefix
|
13
|
+
end
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def get
|
18
|
+
raise "Function missing output!" unless respond_to? :output
|
19
|
+
set_attributes
|
20
|
+
output
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_attributes
|
24
|
+
prefix = get_prefix(element)
|
25
|
+
self.prefix = prefix
|
26
|
+
self.body = element.sub(prefix, "")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/reportinator/loader.rb
CHANGED
@@ -7,10 +7,13 @@ module Reportinator
|
|
7
7
|
|
8
8
|
def self.data_from_template(template, additional_params = {})
|
9
9
|
template_data = load_template(template, additional_params)
|
10
|
-
|
10
|
+
unless template_data.instance_of?(Array)
|
11
|
+
output = split_rows(template_data.data)
|
12
|
+
return ReportParser.parse(output)
|
13
|
+
end
|
11
14
|
output = []
|
12
|
-
template_data.each { |report| output += report.data }
|
13
|
-
|
15
|
+
template_data.each { |report| output += split_rows(report.data) }
|
16
|
+
ReportParser.parse(output)
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.load_template(template, additional_params = {})
|
@@ -24,6 +27,11 @@ module Reportinator
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def self.load_singular(data, additional_params)
|
30
|
+
parent_variables = additional_params[:variables]
|
31
|
+
child_variables = data[:variables]
|
32
|
+
if child_variables.present?
|
33
|
+
data[:variables] = ValueParser.parse(child_variables, parent_variables)
|
34
|
+
end
|
27
35
|
data.merge!(additional_params) { |key, old_value, new_value| merge_values(new_value, old_value) }
|
28
36
|
filtered_data = filter_params(data, attribute_names)
|
29
37
|
variables = filtered_data[:variables]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Parser < Base
|
3
|
+
cattr_writer :prefix_list
|
4
|
+
|
5
|
+
def self.get_prefix_list
|
6
|
+
config.configured_functions.map { |function| function::PREFIXES }.flatten
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.prefix_list
|
10
|
+
@prefix_list ||= get_prefix_list
|
11
|
+
end
|
12
|
+
|
13
|
+
def prefix_list
|
14
|
+
self.class.prefix_list
|
15
|
+
end
|
16
|
+
|
17
|
+
def escape_value(value)
|
18
|
+
return value unless value.is_a? String
|
19
|
+
prefix_list.each do |escape|
|
20
|
+
return value.prepend("?/") if value.strip.start_with?(escape)
|
21
|
+
end
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|