reportinator 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|