reportinator 0.2.0 → 0.3.3
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 +51 -7
- data/Gemfile.lock +10 -0
- data/README.md +113 -22
- 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 +8 -8
- data/lib/reportinator/base.rb +2 -1
- data/lib/reportinator/config.rb +10 -0
- data/lib/reportinator/function.rb +5 -5
- data/lib/reportinator/functions/array/flatten.rb +12 -0
- data/lib/reportinator/functions/array/helper.rb +7 -1
- data/lib/reportinator/functions/array/join.rb +1 -1
- 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/string/number.rb +26 -4
- data/lib/reportinator/functions/string/variable.rb +4 -2
- data/lib/reportinator/helpers.rb +29 -0
- data/lib/reportinator/parsers/method.rb +5 -2
- data/lib/reportinator/parsers/value.rb +14 -13
- 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 +10 -5
- data/lib/reportinator/types/preset.rb +23 -2
- data/lib/reportinator/version.rb +1 -1
- data/lib/reportinator.rb +21 -11
- metadata +30 -5
- data/lib/reportinator/loader.rb +0 -120
@@ -1,11 +1,33 @@
|
|
1
1
|
module Reportinator
|
2
2
|
class NumberStringFunction < StringFunction
|
3
|
-
PREFIXES = ["!n"]
|
3
|
+
PREFIXES = ["!n", "!nf", "!ni"]
|
4
|
+
|
5
|
+
attr_writer :parsed_body
|
4
6
|
|
5
7
|
def output
|
6
|
-
|
7
|
-
return
|
8
|
-
|
8
|
+
return parse_float if prefix == "!nf"
|
9
|
+
return parse_integer if prefix == "!ni"
|
10
|
+
parse_number
|
11
|
+
end
|
12
|
+
|
13
|
+
def parsed_body
|
14
|
+
to_parse = body
|
15
|
+
to_parse.strip! if to_parse.instance_of? String
|
16
|
+
@parsed_body ||= parse_value(body).to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_float
|
20
|
+
parsed_body.to_f
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_integer
|
24
|
+
parsed_body.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_number
|
28
|
+
float = (parsed_body =~ /\d\.\d/)
|
29
|
+
return parse_float if float.present?
|
30
|
+
parse_integer
|
9
31
|
end
|
10
32
|
end
|
11
33
|
end
|
@@ -3,8 +3,10 @@ module Reportinator
|
|
3
3
|
PREFIXES = ["$"]
|
4
4
|
|
5
5
|
def output
|
6
|
-
|
7
|
-
|
6
|
+
variables = metadata[:variables]
|
7
|
+
variable = body.to_sym
|
8
|
+
return element unless variables.present? && variables.include?(variable)
|
9
|
+
variables[variable]
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Reportinator
|
2
|
+
module Helpers
|
3
|
+
def merge_hash(target, source)
|
4
|
+
target = target.present? ? target : {}
|
5
|
+
source = source.present? ? source : {}
|
6
|
+
merge_hash!(target, source)
|
7
|
+
end
|
8
|
+
|
9
|
+
def merge_hash!(target, source)
|
10
|
+
raise "Target: #{target} is not a hash" unless target.instance_of?(Hash)
|
11
|
+
raise "Source: #{source} is not a hash" unless source.instance_of?(Hash)
|
12
|
+
target.merge(source) do |key, old_value, new_value|
|
13
|
+
if old_value.instance_of?(Hash) && new_value.instance_of?(Hash)
|
14
|
+
merge_hash!(old_value, new_value)
|
15
|
+
elsif new_value.present?
|
16
|
+
new_value
|
17
|
+
else
|
18
|
+
old_value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def symbolize_attributes(target)
|
24
|
+
raise "Missing attributes" unless target.respond_to? :attributes
|
25
|
+
raise "Invalid attributes" unless target.attributes.instance_of? Hash
|
26
|
+
target.attributes.transform_keys { |key| key.to_sym }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -5,6 +5,9 @@ module Reportinator
|
|
5
5
|
|
6
6
|
def self.parse(target, method)
|
7
7
|
new(target: target, method: method).output
|
8
|
+
rescue => e
|
9
|
+
logger.error "[ERROR] #{e.class}: #{e}"
|
10
|
+
"Method Error"
|
8
11
|
end
|
9
12
|
|
10
13
|
def output
|
@@ -45,15 +48,15 @@ module Reportinator
|
|
45
48
|
private
|
46
49
|
|
47
50
|
def send_value(target, method, value = nil)
|
48
|
-
method = method.to_s
|
49
51
|
return nil unless target_has_method?(target, method)
|
52
|
+
method = method.to_s
|
50
53
|
return target.send(method) unless value.present?
|
51
54
|
return target.send(method, *value) if value.instance_of?(Array)
|
52
55
|
target.send(method, value)
|
53
56
|
end
|
54
57
|
|
55
58
|
def target_has_method?(target, method)
|
56
|
-
target.
|
59
|
+
target.respond_to?(method)
|
57
60
|
end
|
58
61
|
|
59
62
|
def parse_method(target, method)
|
@@ -1,25 +1,26 @@
|
|
1
1
|
module Reportinator
|
2
|
-
class ValueParser < Parser
|
2
|
+
class ValueParser < Parser
|
3
3
|
attribute :element
|
4
|
-
attribute :
|
4
|
+
attribute :metadata, default: {}
|
5
5
|
|
6
|
-
def self.parse(element,
|
7
|
-
|
8
|
-
|
6
|
+
def self.parse(element, metadata = {}, dup = true)
|
7
|
+
metadata = metadata.present? ? metadata : {}
|
8
|
+
input_element = (dup ? element.dup : element)
|
9
|
+
new(element: input_element, metadata: metadata).output
|
10
|
+
rescue => e
|
11
|
+
logger.error "[ERROR] #{e.class}: #{e}"
|
12
|
+
"Parsing Error"
|
9
13
|
end
|
10
14
|
|
11
|
-
def self.parse_and_execute(target, values,
|
12
|
-
parsed_target = target
|
13
|
-
|
14
|
-
parsed_target = parse(target, variables)
|
15
|
-
end
|
16
|
-
parsed_values = parse(values, variables)
|
15
|
+
def self.parse_and_execute(target, values, metadata = {})
|
16
|
+
parsed_target = parse(target, metadata, false)
|
17
|
+
parsed_values = parse(values, metadata)
|
17
18
|
MethodParser.parse(parsed_target, parsed_values)
|
18
19
|
end
|
19
20
|
|
20
21
|
def output
|
21
22
|
config.configured_functions.each do |function|
|
22
|
-
return function.parse(element,
|
23
|
+
return function.parse(element, metadata) if function.accepts? element
|
23
24
|
end
|
24
25
|
return parse_array if element_class == Array
|
25
26
|
return parse_hash if element_class == Hash
|
@@ -41,7 +42,7 @@ module Reportinator
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def parse_value(value)
|
44
|
-
self.class.parse(value,
|
45
|
+
self.class.parse(value, metadata)
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Column < Base
|
3
|
+
OUTPUT_TYPES = {
|
4
|
+
numeric: [Numeric],
|
5
|
+
date: [Date, Time],
|
6
|
+
string: [String],
|
7
|
+
hash: [Hash],
|
8
|
+
array: [Array]
|
9
|
+
}
|
10
|
+
|
11
|
+
attribute :data
|
12
|
+
attr_writer :output
|
13
|
+
|
14
|
+
def output
|
15
|
+
@output ||= ReportParser.parse(data)
|
16
|
+
end
|
17
|
+
|
18
|
+
OUTPUT_TYPES.each do |type, classes|
|
19
|
+
define_method(:"#{type}?") {
|
20
|
+
classes.each { |c| return true if output.is_a? c }
|
21
|
+
false
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class ReportLoader < Base
|
3
|
+
attribute :template
|
4
|
+
attribute :metadata
|
5
|
+
|
6
|
+
def self.load(template, metadata = {})
|
7
|
+
loader = new(metadata: metadata)
|
8
|
+
loader.template = Template.load(template: template, metadata: metadata)
|
9
|
+
loader
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_metadata
|
13
|
+
report_metadata = {}
|
14
|
+
template.parse(metadata) do |data, old_meta, new_meta|
|
15
|
+
meta = ValueParser.parse(new_meta, metadata)
|
16
|
+
report_metadata = merge_hash(meta, report_metadata) if meta.present?
|
17
|
+
end
|
18
|
+
report_metadata
|
19
|
+
end
|
20
|
+
|
21
|
+
def report
|
22
|
+
report = Report.new
|
23
|
+
reports = template.parse(metadata) do |data, old_meta, new_meta|
|
24
|
+
parse_metadata(data, old_meta, new_meta)
|
25
|
+
end
|
26
|
+
reports.compact.each do |report_template|
|
27
|
+
output = report_template.data
|
28
|
+
report.insert(output)
|
29
|
+
end
|
30
|
+
report
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_metadata(data, old_meta, new_meta)
|
34
|
+
meta = ValueParser.parse(old_meta, metadata)
|
35
|
+
if new_meta.instance_of? Hash
|
36
|
+
unparsed_meta = new_meta.select { |key| config.configured_metadata.include? key }
|
37
|
+
meta_to_parse = new_meta.reject { |key| config.configured_metadata.include? key }
|
38
|
+
parsing_meta = merge_hash(meta, unparsed_meta)
|
39
|
+
parsed_meta = ValueParser.parse(meta_to_parse, parsing_meta)
|
40
|
+
remerged_meta = merge_hash(parsed_meta, unparsed_meta)
|
41
|
+
else
|
42
|
+
remerged_meta = {}
|
43
|
+
end
|
44
|
+
report_meta = merge_hash(remerged_meta, meta)
|
45
|
+
report_from_data(data, report_meta)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def report_from_data(data, meta)
|
51
|
+
report_type = report_class_from_data(data, meta)
|
52
|
+
return nil unless report_type.present?
|
53
|
+
return report_type.new(ValueParser.parse(data[:params], meta)) if report_type::PARSE_PARAMS
|
54
|
+
report = report_type.new(data[:params])
|
55
|
+
report.metadata = meta
|
56
|
+
report
|
57
|
+
end
|
58
|
+
|
59
|
+
def report_class_from_data(data, meta)
|
60
|
+
type = ValueParser.parse(data[:type], meta)
|
61
|
+
return false unless type.present?
|
62
|
+
report_class_from_type(type)
|
63
|
+
end
|
64
|
+
|
65
|
+
def report_class_from_type(type)
|
66
|
+
types = config.configured_types
|
67
|
+
raise "Invalid type: #{type}" unless types.include? type
|
68
|
+
types[type].constantize
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Report < Base
|
3
|
+
attr_writer :rows
|
4
|
+
|
5
|
+
def rows
|
6
|
+
@rows ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def insert(row, position = :last)
|
10
|
+
return insert_row(row, position) if row.instance_of? Row
|
11
|
+
raise "Invalid row data: #{row}" unless row.instance_of? Array
|
12
|
+
row.each { |r| insert_row(r) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def insert_row(row, position = :last)
|
16
|
+
raise "Not a row" unless row.instance_of? Row
|
17
|
+
return rows.append(row) if position == :last
|
18
|
+
return rows.prepend(row) if position == :first
|
19
|
+
return rows.insert(position, row) if position.is_a? Numeric
|
20
|
+
raise "Invalid Position!"
|
21
|
+
end
|
22
|
+
|
23
|
+
def output
|
24
|
+
rows.map { |r| r.output }
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_csv
|
28
|
+
CSV.generate do |csv|
|
29
|
+
output.each { |row| csv << row }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Row < Base
|
3
|
+
attr_writer :columns
|
4
|
+
|
5
|
+
def columns
|
6
|
+
@columns ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.create(input)
|
10
|
+
row = new
|
11
|
+
if input.instance_of? Array
|
12
|
+
input.each { |value| row.insert value }
|
13
|
+
else
|
14
|
+
row.insert(input)
|
15
|
+
end
|
16
|
+
row
|
17
|
+
end
|
18
|
+
|
19
|
+
def insert(data, position = :last)
|
20
|
+
column = create_column(data)
|
21
|
+
return columns.prepend(column) if position == :first
|
22
|
+
return columns.insert(position, column) if position.is_a? Numeric
|
23
|
+
return columns.append(column) if position == :last
|
24
|
+
raise "Invalid Position!"
|
25
|
+
end
|
26
|
+
|
27
|
+
def total
|
28
|
+
numeric_columns = columns.select { |c| c.numeric? }
|
29
|
+
numeric_columns.sum { |c| c.output }
|
30
|
+
end
|
31
|
+
|
32
|
+
def output
|
33
|
+
columns.map { |c| c.output }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def create_column(data)
|
39
|
+
Column.new(data: data)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Reportinator
|
2
|
+
class Template < Base
|
3
|
+
attr_accessor :children
|
4
|
+
attribute :type
|
5
|
+
attribute :template
|
6
|
+
attribute :params
|
7
|
+
attribute :metadata
|
8
|
+
|
9
|
+
def self.load(params = {})
|
10
|
+
template = new(params)
|
11
|
+
template.register
|
12
|
+
end
|
13
|
+
|
14
|
+
def register
|
15
|
+
return load_template if template.present?
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(meta = {}, data = {})
|
20
|
+
output = []
|
21
|
+
new_meta = metadata
|
22
|
+
combine_meta = merge_hash(meta, new_meta)
|
23
|
+
new_data = attributes.transform_keys { |key| key.to_sym }
|
24
|
+
combine_data = merge_hash(new_data, data)
|
25
|
+
if children.present? && children.respond_to?(:to_ary)
|
26
|
+
children.each do |child|
|
27
|
+
output += child.parse(combine_meta, combine_data) do |combine_data, meta, new_meta|
|
28
|
+
yield(combine_data, meta, new_meta)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
else
|
32
|
+
output << yield(combine_data, meta, new_meta)
|
33
|
+
end
|
34
|
+
output
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def load_template
|
40
|
+
template_data = filter_template
|
41
|
+
data = if template_data.respond_to? :to_ary
|
42
|
+
template_data.map { |template| self.class.load(template) }
|
43
|
+
else
|
44
|
+
self.class.load(template_data)
|
45
|
+
end
|
46
|
+
self.children ||= []
|
47
|
+
if data.respond_to? :to_ary
|
48
|
+
self.children += data
|
49
|
+
else
|
50
|
+
self.children << data
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def filter_template
|
56
|
+
template_data = parse_template
|
57
|
+
if template_data.respond_to? :to_ary
|
58
|
+
template_data.map { |template| filter_params(template) }
|
59
|
+
else
|
60
|
+
filter_params(template_data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_template
|
65
|
+
raise "Template isn't a string" unless template.instance_of? String
|
66
|
+
suffixes = config.configured_suffixes
|
67
|
+
directories = config.configured_directories
|
68
|
+
template_files = suffixes.map { |suffix| (suffix.present? ? "#{template}.#{suffix}" : template) }
|
69
|
+
template_paths = directories.map { |dir| template_files.map { |file| "#{dir}/#{file}" } }
|
70
|
+
template_paths.flatten!
|
71
|
+
template_paths.each do |path|
|
72
|
+
return path if File.exist? path
|
73
|
+
end
|
74
|
+
raise "Missing template: #{template}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_template(json)
|
78
|
+
return true if Reportinator.schema.valid?(json)
|
79
|
+
raise "Template doesn't match schema: #{Reportinator.schema.validate(json).to_a}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse_template
|
83
|
+
file = read_template
|
84
|
+
begin
|
85
|
+
plain_json = JSON.parse(file)
|
86
|
+
symbolised_json = JSON.parse(file, symbolize_names: true)
|
87
|
+
rescue
|
88
|
+
raise "Error parsing template file: #{file}"
|
89
|
+
end
|
90
|
+
validate_template(plain_json)
|
91
|
+
symbolised_json
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_template
|
95
|
+
file = find_template
|
96
|
+
File.read(file)
|
97
|
+
end
|
98
|
+
|
99
|
+
def filter_params(params)
|
100
|
+
filtered_params = params.select { |param| attribute_names.include? param.to_s }
|
101
|
+
if params.size > filtered_params.size
|
102
|
+
invalid_params = (params.keys - filtered_params.keys).map { |key| key.to_s }
|
103
|
+
logger.warn "Invalid attributes found: #{invalid_params} Valid attributes are: #{attribute_names}"
|
104
|
+
end
|
105
|
+
filtered_params
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -1,13 +1,16 @@
|
|
1
1
|
module Reportinator
|
2
|
-
class ModelReport <
|
2
|
+
class ModelReport < ReportType
|
3
|
+
include Helpers
|
4
|
+
PARSE_PARAMS = false
|
3
5
|
attribute :target
|
4
6
|
attribute :method_list, default: []
|
5
7
|
|
6
8
|
validates :target, presence: true
|
7
9
|
|
8
10
|
def data
|
9
|
-
|
10
|
-
|
11
|
+
self.target = ValueParser.parse(target, metadata, false)
|
12
|
+
return Row.create(get_model_data(target)) unless target.respond_to? :each
|
13
|
+
records_data.map { |data| Row.create(data) }
|
11
14
|
end
|
12
15
|
|
13
16
|
def records_data
|
@@ -26,8 +29,10 @@ module Reportinator
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def parse_method(target, method)
|
29
|
-
|
30
|
-
|
32
|
+
parser_metadata = merge_hash(metadata, {variables: {target: target}})
|
33
|
+
parsed_method = ValueParser.parse(method, parser_metadata)
|
34
|
+
return parsed_method if parsed_method.instance_of? String
|
35
|
+
MethodParser.parse(target, parsed_method)
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -1,5 +1,26 @@
|
|
1
1
|
module Reportinator
|
2
|
-
class PresetReport <
|
3
|
-
attribute :
|
2
|
+
class PresetReport < ReportType
|
3
|
+
attribute :values
|
4
|
+
|
5
|
+
def data
|
6
|
+
split_values.map { |row| Row.create(row) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def split_values
|
10
|
+
data = values.instance_of?(Array) ? values : [values]
|
11
|
+
rows = []
|
12
|
+
temp = []
|
13
|
+
data.each do |col|
|
14
|
+
if col.instance_of?(Array)
|
15
|
+
rows << temp unless temp.empty?
|
16
|
+
temp = []
|
17
|
+
rows << col
|
18
|
+
else
|
19
|
+
temp << col
|
20
|
+
end
|
21
|
+
end
|
22
|
+
rows << temp unless temp.empty?
|
23
|
+
rows
|
24
|
+
end
|
4
25
|
end
|
5
26
|
end
|
data/lib/reportinator/version.rb
CHANGED
data/lib/reportinator.rb
CHANGED
@@ -6,14 +6,17 @@ require "fileutils"
|
|
6
6
|
require "active_support"
|
7
7
|
require "active_model"
|
8
8
|
require "require_all"
|
9
|
+
require "json_schemer"
|
9
10
|
require_relative "reportinator/version"
|
10
11
|
require_relative "reportinator/base"
|
11
12
|
|
12
13
|
module Reportinator
|
14
|
+
SCHEMA = "#{__dir__}/../data/schema/report_schema.json"
|
13
15
|
class Error < StandardError; end
|
14
16
|
class << self
|
15
17
|
attr_writer :config
|
16
18
|
attr_writer :logger
|
19
|
+
attr_writer :schema
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.config
|
@@ -24,28 +27,35 @@ module Reportinator
|
|
24
27
|
yield(config)
|
25
28
|
end
|
26
29
|
|
30
|
+
def self.schema
|
31
|
+
return @schema if @schema.instance_of? JSONSchemer
|
32
|
+
schema = JSON.parse(File.read(SCHEMA))
|
33
|
+
@schema = JSONSchemer.schema(schema)
|
34
|
+
end
|
35
|
+
|
27
36
|
def self.logger
|
28
37
|
@logger || ActiveSupport::Logger.new($stdout)
|
29
38
|
end
|
30
39
|
|
31
|
-
def self.parse(input,
|
32
|
-
ValueParser.parse(input,
|
40
|
+
def self.parse(input, metadata = {})
|
41
|
+
ValueParser.parse(input, metadata)
|
33
42
|
end
|
34
43
|
|
35
|
-
def self.report(template,
|
36
|
-
|
44
|
+
def self.report(template, metadata = {})
|
45
|
+
report = ReportLoader.load(template, metadata).report
|
46
|
+
report.output
|
37
47
|
end
|
38
48
|
|
39
|
-
def self.output(template,
|
49
|
+
def self.output(template, metadata = {}, filename = "")
|
40
50
|
filename = (filename.present? ? filename : "#{template}.csv")
|
41
51
|
path = "#{config.output_directory}/#{filename}"
|
42
52
|
FileUtils.mkdir_p(File.dirname(path))
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
53
|
+
report = ReportLoader.load(template, metadata).report
|
54
|
+
data = report.to_csv
|
55
|
+
if File.write(path, data)
|
56
|
+
path
|
57
|
+
else
|
58
|
+
raise "Error writing to: #{path}"
|
48
59
|
end
|
49
|
-
path
|
50
60
|
end
|
51
61
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reportinator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moxvallix
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json_schemer
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.2'
|
41
55
|
description: Behold! My Reportinator! Reportinator makes reports from JSON files.
|
42
56
|
email:
|
43
57
|
- dev@moxvallix.com
|
@@ -56,15 +70,21 @@ files:
|
|
56
70
|
- Rakefile
|
57
71
|
- app/reports/example.report.json
|
58
72
|
- app/reports/multiplication.report.json
|
73
|
+
- app/reports/multiplication_v2.report.json
|
74
|
+
- data/schema/report_schema.json
|
59
75
|
- docs/0_first_report.md
|
60
76
|
- lib/reportinator.rb
|
61
77
|
- lib/reportinator/base.rb
|
62
78
|
- lib/reportinator/config.rb
|
63
79
|
- lib/reportinator/function.rb
|
64
80
|
- lib/reportinator/functions/array.rb
|
81
|
+
- lib/reportinator/functions/array/flatten.rb
|
65
82
|
- lib/reportinator/functions/array/helper.rb
|
66
83
|
- lib/reportinator/functions/array/join.rb
|
67
84
|
- lib/reportinator/functions/array/method.rb
|
85
|
+
- lib/reportinator/functions/array/range.rb
|
86
|
+
- lib/reportinator/functions/array/snippet.rb
|
87
|
+
- lib/reportinator/functions/array/string.rb
|
68
88
|
- lib/reportinator/functions/string.rb
|
69
89
|
- lib/reportinator/functions/string/addition.rb
|
70
90
|
- lib/reportinator/functions/string/constant.rb
|
@@ -75,12 +95,17 @@ files:
|
|
75
95
|
- lib/reportinator/functions/string/range.rb
|
76
96
|
- lib/reportinator/functions/string/symbol.rb
|
77
97
|
- lib/reportinator/functions/string/variable.rb
|
78
|
-
- lib/reportinator/
|
98
|
+
- lib/reportinator/helpers.rb
|
79
99
|
- lib/reportinator/parser.rb
|
80
100
|
- lib/reportinator/parsers/method.rb
|
81
101
|
- lib/reportinator/parsers/report.rb
|
82
102
|
- lib/reportinator/parsers/value.rb
|
83
|
-
- lib/reportinator/report.rb
|
103
|
+
- lib/reportinator/report/column.rb
|
104
|
+
- lib/reportinator/report/loader.rb
|
105
|
+
- lib/reportinator/report/report.rb
|
106
|
+
- lib/reportinator/report/row.rb
|
107
|
+
- lib/reportinator/report/template.rb
|
108
|
+
- lib/reportinator/report_type.rb
|
84
109
|
- lib/reportinator/types/model.rb
|
85
110
|
- lib/reportinator/types/preset.rb
|
86
111
|
- lib/reportinator/version.rb
|
@@ -92,7 +117,7 @@ metadata:
|
|
92
117
|
rubygems_mfa_required: 'true'
|
93
118
|
homepage_uri: https://github.com/moxvallix/reportinator
|
94
119
|
source_code_uri: https://github.com/moxvallix/reportinator
|
95
|
-
changelog_uri: https://github.com/moxvallix/reportinator
|
120
|
+
changelog_uri: https://github.com/moxvallix/reportinator/blob/main/CHANGELOG.md
|
96
121
|
post_install_message:
|
97
122
|
rdoc_options: []
|
98
123
|
require_paths:
|