magic-report 0.6.0 → 0.7.1
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/lib/magic_report/general_report.rb +30 -0
- data/lib/magic_report/report/builder/field.rb +43 -0
- data/lib/magic_report/report/builder/has_many.rb +21 -0
- data/lib/magic_report/report/builder/has_one.rb +55 -0
- data/lib/magic_report/report/csv.rb +10 -15
- data/lib/magic_report/report/reflection.rb +29 -0
- data/lib/magic_report/report/row.rb +30 -40
- data/lib/magic_report/report.rb +95 -67
- data/lib/magic_report/version.rb +1 -1
- data/lib/magic_report.rb +10 -4
- metadata +22 -7
- data/lib/magic_report/report/class_helpers.rb +0 -23
- data/lib/magic_report/report/configuration.rb +0 -57
- data/lib/magic_report/report/process.rb +0 -59
- data/lib/magic_report/utils.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88305b9a5045e8cd60e96f3ebc8f7991726303f6461cd8de483ccbb483dba5f4
|
4
|
+
data.tar.gz: fb088083b95b0aeff7ca7fd4e92fa567e2685ff566ee8c6459582ed1e1876e6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe1a63c8856265ff39b9651474218014a7700da961efb7a5c4adc42106463dd096e30770d520aec072e4df311482c7520c74d141d8448ff8fb948d806e712ad2
|
7
|
+
data.tar.gz: f55df1275d2f7efb325e3329e77b0ccc20eba2a5b682d02f80d156188cbf34740ce7053efe2a96b3c3ced63fcfbe1338adafb33377c3cf68ae851e3d60a17c06
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicReport
|
4
|
+
class GeneralReport
|
5
|
+
attr_reader :models, :report_klass, :csv, :fill
|
6
|
+
|
7
|
+
def initialize(input, report_klass, options = {})
|
8
|
+
@models = input.is_a?(Enumerable) ? input : [input]
|
9
|
+
@report_klass = report_klass
|
10
|
+
@csv = ::MagicReport::Report::Csv.new(self)
|
11
|
+
@fill = options[:fill] || false
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
models.find_each.with_index do |model, index|
|
16
|
+
report = report_klass.new(model, fill)
|
17
|
+
|
18
|
+
csv.add_headings(report) if index.zero?
|
19
|
+
report.rows.each { |row| csv.add_row(row) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_attachment
|
24
|
+
@as_attachment ||= {
|
25
|
+
mime_type: "text/csv",
|
26
|
+
content: csv.io.read
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicReport
|
4
|
+
class Report
|
5
|
+
class Builder
|
6
|
+
class Field
|
7
|
+
def self.build(report, name, processor, options)
|
8
|
+
new(report, name, processor, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :report, :name, :processor, :is_primary
|
12
|
+
|
13
|
+
def initialize(report, name, processor, options)
|
14
|
+
@report = report
|
15
|
+
@name = name
|
16
|
+
@processor = processor
|
17
|
+
@is_primary = options.fetch(:primary, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(model)
|
21
|
+
value = extract_value(model)
|
22
|
+
|
23
|
+
if processor.is_a? Proc
|
24
|
+
processor.call(model, value)
|
25
|
+
elsif processor.is_a? Symbol
|
26
|
+
# Refactor
|
27
|
+
report.new(nil).send(processor, model, value)
|
28
|
+
else
|
29
|
+
value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def extract_value(model)
|
36
|
+
model.send(name)
|
37
|
+
rescue
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicReport
|
4
|
+
class Report
|
5
|
+
class Builder
|
6
|
+
class HasMany < HasOne
|
7
|
+
def process_rows(model, row, is_fill)
|
8
|
+
extract_relation(model).flat_map.with_index do |rel, idx|
|
9
|
+
# If we're on a first entry, then we should fill first row
|
10
|
+
# Otherwise will be created a new row
|
11
|
+
if idx.zero?
|
12
|
+
options[:class].new(rel, is_fill, row).rows
|
13
|
+
else
|
14
|
+
options[:class].new(rel, is_fill).rows
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicReport
|
4
|
+
class Report
|
5
|
+
class Builder
|
6
|
+
class HasOne
|
7
|
+
def self.build(report, name, options, &extension)
|
8
|
+
new(report, name, options, extension)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :report, :name, :options, :extension, :prefix
|
12
|
+
|
13
|
+
def initialize(report, name, options, extension)
|
14
|
+
@report = report
|
15
|
+
@name = name
|
16
|
+
@options = options
|
17
|
+
@extension = extension
|
18
|
+
@prefix = I18n.t!("#{report.i18n_scope}.#{report.i18n_key}.#{name}_relation")
|
19
|
+
|
20
|
+
unless options[:class]
|
21
|
+
klass = ::MagicReport::Report.clone
|
22
|
+
klass.define_singleton_method(:name) { "#{report.name}/#{name}" }
|
23
|
+
klass.class_eval(&extension)
|
24
|
+
|
25
|
+
options[:class] = klass
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def process(model)
|
30
|
+
relation = extract_relation(model)
|
31
|
+
|
32
|
+
# Refactor here values method call
|
33
|
+
options[:class].new(relation, is_fill).values
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_rows(model, row, is_fill)
|
37
|
+
relation = extract_relation(model)
|
38
|
+
|
39
|
+
# Refactor here values method call
|
40
|
+
options[:class].new(relation, is_fill, row).rows
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_row
|
44
|
+
options[:class].build_row(prefix)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def extract_relation(model)
|
50
|
+
model.send(name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -8,7 +8,6 @@ module MagicReport
|
|
8
8
|
attr_reader :report, :file, :csv
|
9
9
|
|
10
10
|
def initialize(report)
|
11
|
-
@report = report
|
12
11
|
@file = Tempfile.new
|
13
12
|
@csv = ::CSV.new(@file, write_headers: true)
|
14
13
|
end
|
@@ -16,17 +15,19 @@ module MagicReport
|
|
16
15
|
def generate
|
17
16
|
write_headers
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
if value.is_a?(Array)
|
23
|
-
value.each { |nested_row| csv << nested_row.values }
|
24
|
-
else
|
25
|
-
csv << value.values
|
26
|
-
end
|
18
|
+
report.rows.each do |row|
|
19
|
+
csv << row.to_a
|
27
20
|
end
|
28
21
|
end
|
29
22
|
|
23
|
+
def add_headings(report)
|
24
|
+
csv << report.headings
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_row(row)
|
28
|
+
csv << row.to_a
|
29
|
+
end
|
30
|
+
|
30
31
|
# Don't forget to unlink in production code
|
31
32
|
def unlink
|
32
33
|
file.close
|
@@ -38,12 +39,6 @@ module MagicReport
|
|
38
39
|
io.rewind
|
39
40
|
io
|
40
41
|
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def write_headers
|
45
|
-
csv << report.headings
|
46
|
-
end
|
47
42
|
end
|
48
43
|
end
|
49
44
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicReport
|
4
|
+
class Report
|
5
|
+
module Reflection
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :_fields, instance_writer: false, default: {}
|
10
|
+
class_attribute :_has_one, instance_writer: false, default: {}
|
11
|
+
class_attribute :_has_many, instance_writer: false, default: {}
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def add_field(klass, name, reflection)
|
16
|
+
klass._fields = klass._fields.except(name).merge!(name => reflection)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_has_one(klass, name, reflection)
|
20
|
+
klass._has_one = klass._has_one.except(name).merge!(name => reflection)
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_has_many(klass, name, reflection)
|
24
|
+
klass._has_many = klass._has_many.except(name).merge!(name => reflection)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -3,61 +3,51 @@
|
|
3
3
|
module MagicReport
|
4
4
|
class Report
|
5
5
|
class Row
|
6
|
-
|
6
|
+
class Column
|
7
|
+
attr_reader :key, :heading, :is_primary, :prefix, :value
|
8
|
+
|
9
|
+
def initialize(key, heading, is_primary, prefix)
|
10
|
+
@key = key
|
11
|
+
@heading = heading
|
12
|
+
@is_primary = is_primary
|
13
|
+
@prefix = prefix
|
14
|
+
@value = nil
|
15
|
+
end
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@nested_rows = {}
|
12
|
-
end
|
17
|
+
def assign_value(value)
|
18
|
+
@value = value
|
19
|
+
end
|
13
20
|
|
14
|
-
|
15
|
-
|
21
|
+
def full_heading
|
22
|
+
prefix.present? ? "#{prefix} #{heading}" : heading
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
|
-
|
19
|
-
inner_rows[field] = row
|
20
|
-
end
|
26
|
+
attr_reader :columns, :nested_rows
|
21
27
|
|
22
|
-
def
|
23
|
-
|
24
|
-
nested_rows
|
28
|
+
def initialize
|
29
|
+
@columns = []
|
30
|
+
@nested_rows = {}
|
25
31
|
end
|
26
32
|
|
27
|
-
def
|
28
|
-
|
33
|
+
def add_column_value(key:, value:)
|
34
|
+
@columns.find { |column| column.key == key }.assign_value(value)
|
29
35
|
end
|
30
36
|
|
31
|
-
def
|
32
|
-
nested_rows
|
37
|
+
def add_nested_row(key:, row:)
|
38
|
+
nested_rows[key] = row
|
33
39
|
end
|
34
40
|
|
35
|
-
def
|
36
|
-
|
37
|
-
nested_rows[key].map do |nested_row|
|
38
|
-
block.call(nested_row)
|
39
|
-
end
|
40
|
-
end
|
41
|
+
def register_column(key, heading, is_primary, prefix = nil)
|
42
|
+
@columns << Column.new(key, heading, is_primary, prefix)
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
44
|
-
|
45
|
-
block.call(inner_row)
|
46
|
-
end
|
45
|
+
def headings
|
46
|
+
(columns.map(&:full_heading) + nested_rows.values.map(&:headings)).flatten
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
50
|
-
|
51
|
-
original_hash = inner_rows.any? ? data.merge(each_inner_row { |inner_row| inner_row.to_h }.reduce({}, :merge)) : data
|
52
|
-
|
53
|
-
if complex?
|
54
|
-
each_nested_row do |nested_row|
|
55
|
-
original_hash.merge(nested_row.to_h)
|
56
|
-
end
|
57
|
-
else
|
58
|
-
original_hash
|
59
|
-
end
|
60
|
-
end
|
49
|
+
def to_a
|
50
|
+
(columns.map(&:value) + nested_rows.values.map(&:to_a)).flatten
|
61
51
|
end
|
62
52
|
end
|
63
53
|
end
|
data/lib/magic_report/report.rb
CHANGED
@@ -2,107 +2,135 @@
|
|
2
2
|
|
3
3
|
module MagicReport
|
4
4
|
class Report
|
5
|
-
include
|
5
|
+
include Reflection
|
6
6
|
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :model, :row, :is_fill
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@name = name || name_from_class
|
14
|
-
|
15
|
-
@prefix = prefix
|
16
|
-
@nested_field = nested_field
|
9
|
+
def initialize(model, is_fill = false, row = nil)
|
10
|
+
@model = model
|
11
|
+
@row = row || self.class.build_row
|
12
|
+
@is_fill = is_fill
|
17
13
|
end
|
18
14
|
|
19
|
-
def
|
20
|
-
@
|
21
|
-
|
15
|
+
def rows
|
16
|
+
@rows ||= begin
|
17
|
+
rows = []
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
csv.generate
|
19
|
+
_fields.each_value do |field|
|
20
|
+
row.add_column_value(key: field.name, value: field.process(model))
|
21
|
+
end
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
_has_one.each_value do |has_one|
|
24
|
+
simple_row = row.nested_rows[has_one.name]
|
25
|
+
|
26
|
+
has_one.process_rows(model, simple_row, is_fill)
|
27
|
+
end
|
28
|
+
|
29
|
+
rows.push(row)
|
30
|
+
|
31
|
+
_has_many.each_value do |has_many|
|
32
|
+
simple_row = row.nested_rows[has_many.name]
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
resik = has_many.process_rows(model, simple_row, is_fill)
|
35
|
+
|
36
|
+
resik.map.with_index do |resik_row, index|
|
37
|
+
if index.zero?
|
38
|
+
# rows.push(new_row)
|
39
|
+
else
|
40
|
+
new_row = self.class.build_row
|
41
|
+
|
42
|
+
copy_primary_fields(row, new_row)
|
43
|
+
# TODO: copy ID here
|
44
|
+
# copy_primary_attributes(new_row, row)
|
45
|
+
new_row.nested_rows[has_many.name] = resik_row
|
46
|
+
|
47
|
+
rows.push(new_row)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
rows
|
53
|
+
end
|
37
54
|
end
|
38
55
|
|
39
56
|
def headings
|
40
|
-
|
57
|
+
row.headings
|
41
58
|
end
|
42
59
|
|
43
|
-
|
44
|
-
|
45
|
-
|
60
|
+
def copy_primary_fields(old_row, new_row)
|
61
|
+
old_row.columns.each do |column|
|
62
|
+
if column.is_primary || is_fill
|
63
|
+
new_row.add_column_value(key: column.key, value: column.value)
|
64
|
+
end
|
46
65
|
end
|
47
66
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
67
|
+
if is_fill
|
68
|
+
old_row.nested_rows.each do |key, nested_row|
|
69
|
+
nested_row.columns.each do |column|
|
70
|
+
new_row.nested_rows[key].add_column_value(key: column.key, value: column.value)
|
71
|
+
end
|
53
72
|
end
|
54
73
|
end
|
74
|
+
end
|
55
75
|
|
56
|
-
|
57
|
-
|
76
|
+
class << self
|
77
|
+
# Default i18n scope for locales
|
78
|
+
#
|
79
|
+
# en:
|
80
|
+
# magic_report:
|
81
|
+
#
|
82
|
+
def i18n_scope
|
83
|
+
:magic_report
|
84
|
+
end
|
58
85
|
|
59
|
-
|
60
|
-
|
86
|
+
def i18n_key
|
87
|
+
name.underscore.tr("/", ".").to_sym
|
61
88
|
end
|
62
89
|
|
63
|
-
def
|
64
|
-
|
90
|
+
def field(*args)
|
91
|
+
options = args.extract_options!
|
92
|
+
name, processor = args
|
65
93
|
|
66
|
-
|
94
|
+
reflection = Builder::Field.build(self, name, processor, options)
|
67
95
|
|
68
|
-
|
96
|
+
Reflection.add_field(self, name, reflection)
|
97
|
+
end
|
69
98
|
|
70
|
-
|
99
|
+
def fields(*names)
|
100
|
+
names.each { |name| field(name) }
|
101
|
+
end
|
71
102
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
103
|
+
def has_one(name, **options, &extension)
|
104
|
+
reflection = Builder::HasOne.build(self, name, options, &extension)
|
75
105
|
|
76
|
-
|
106
|
+
Reflection.add_has_one(self, name, reflection)
|
77
107
|
end
|
78
108
|
|
79
|
-
def has_many(
|
80
|
-
|
109
|
+
def has_many(name, **options, &extension)
|
110
|
+
reflection = Builder::HasMany.build(self, name, options, &extension)
|
81
111
|
|
82
|
-
|
83
|
-
|
84
|
-
klass = ::MagicReport::Utils.derive_class(opts, &block)
|
112
|
+
Reflection.add_has_many(self, name, reflection)
|
113
|
+
end
|
85
114
|
|
86
|
-
|
115
|
+
# Building empty row for current report
|
116
|
+
# This row doesn't include outer reports
|
117
|
+
def build_row(prefix = nil)
|
118
|
+
row = ::MagicReport::Report::Row.new
|
87
119
|
|
88
|
-
|
89
|
-
|
120
|
+
_fields.each_value do |field|
|
121
|
+
row.register_column(field.name, I18n.t!("#{i18n_scope}.#{i18n_key}.#{field.name}".tr("/", ".")), field.is_primary, prefix)
|
90
122
|
end
|
91
123
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
def resolve_path(key)
|
97
|
-
nested_field ? "#{nested_field}.#{key}".to_sym : key
|
98
|
-
end
|
99
|
-
|
100
|
-
private
|
124
|
+
_has_one.each_value do |has_one|
|
125
|
+
row.add_nested_row(key: has_one.name, row: has_one.build_row)
|
126
|
+
end
|
101
127
|
|
102
|
-
|
103
|
-
|
128
|
+
_has_many.each_value do |has_many|
|
129
|
+
row.add_nested_row(key: has_many.name, row: has_many.build_row)
|
130
|
+
end
|
104
131
|
|
105
|
-
|
132
|
+
row
|
133
|
+
end
|
106
134
|
end
|
107
135
|
end
|
108
136
|
end
|
data/lib/magic_report/version.rb
CHANGED
data/lib/magic_report.rb
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
require "dry-types"
|
4
4
|
require "i18n"
|
5
5
|
|
6
|
+
require "active_support"
|
7
|
+
require "active_support/core_ext/class/attribute"
|
8
|
+
require "active_support/core_ext/array/extract_options"
|
9
|
+
require "active_support/inflector"
|
10
|
+
|
6
11
|
require "magic_report/version"
|
7
12
|
|
8
13
|
module MagicReport
|
@@ -14,12 +19,13 @@ module MagicReport
|
|
14
19
|
SymbolArray = Array.of(Types::Coercible::Symbol)
|
15
20
|
end
|
16
21
|
|
17
|
-
require "magic_report/
|
22
|
+
require "magic_report/report/builder/field"
|
23
|
+
require "magic_report/report/builder/has_one"
|
24
|
+
require "magic_report/report/builder/has_many"
|
18
25
|
|
19
|
-
require "magic_report/report/
|
20
|
-
require "magic_report/report/configuration"
|
21
|
-
require "magic_report/report/process"
|
26
|
+
require "magic_report/report/reflection"
|
22
27
|
require "magic_report/report/row"
|
23
28
|
require "magic_report/report/csv"
|
24
29
|
require "magic_report/report"
|
30
|
+
require "magic_report/general_report"
|
25
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magic-report
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Pankratev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-types
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: i18n
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,13 +60,14 @@ extra_rdoc_files: []
|
|
46
60
|
files:
|
47
61
|
- README.md
|
48
62
|
- lib/magic_report.rb
|
63
|
+
- lib/magic_report/general_report.rb
|
49
64
|
- lib/magic_report/report.rb
|
50
|
-
- lib/magic_report/report/
|
51
|
-
- lib/magic_report/report/
|
65
|
+
- lib/magic_report/report/builder/field.rb
|
66
|
+
- lib/magic_report/report/builder/has_many.rb
|
67
|
+
- lib/magic_report/report/builder/has_one.rb
|
52
68
|
- lib/magic_report/report/csv.rb
|
53
|
-
- lib/magic_report/report/
|
69
|
+
- lib/magic_report/report/reflection.rb
|
54
70
|
- lib/magic_report/report/row.rb
|
55
|
-
- lib/magic_report/utils.rb
|
56
71
|
- lib/magic_report/version.rb
|
57
72
|
homepage: https://github.com/thefaded/magic-report
|
58
73
|
licenses:
|
@@ -73,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
88
|
- !ruby/object:Gem::Version
|
74
89
|
version: '0'
|
75
90
|
requirements: []
|
76
|
-
rubygems_version: 3.
|
91
|
+
rubygems_version: 3.4.19
|
77
92
|
signing_key:
|
78
93
|
specification_version: 4
|
79
94
|
summary: An easy way to export data to CSV
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MagicReport
|
4
|
-
class Report
|
5
|
-
module ClassHelpers
|
6
|
-
def name_from_class
|
7
|
-
::MagicReport::Utils.underscore(self.class.name)
|
8
|
-
end
|
9
|
-
|
10
|
-
def fields_from_class
|
11
|
-
self.class.instance_variable_get(:@fields) || []
|
12
|
-
end
|
13
|
-
|
14
|
-
def has_one_from_class
|
15
|
-
self.class.instance_variable_get(:@has_one) || []
|
16
|
-
end
|
17
|
-
|
18
|
-
def has_many_from_class
|
19
|
-
self.class.instance_variable_get(:@has_many) || []
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MagicReport
|
4
|
-
class Report
|
5
|
-
module Configuration
|
6
|
-
class Field
|
7
|
-
attr_reader :key, :processor
|
8
|
-
|
9
|
-
def initialize(key:, processor: nil)
|
10
|
-
@key = key
|
11
|
-
@processor = processor
|
12
|
-
end
|
13
|
-
|
14
|
-
def process(entity)
|
15
|
-
processor ? processor.call(entity) : entity.send(key)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class HasOne
|
20
|
-
attr_reader :klass, :opts, :prefix, :key
|
21
|
-
|
22
|
-
def initialize(klass:, opts:, key:)
|
23
|
-
@klass = klass
|
24
|
-
@prefix = opts[:prefix]
|
25
|
-
@key = key
|
26
|
-
@opts = opts
|
27
|
-
end
|
28
|
-
|
29
|
-
def process_entity(entity)
|
30
|
-
report.process(entity)
|
31
|
-
end
|
32
|
-
|
33
|
-
def report
|
34
|
-
@report ||= init_report
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# { class: Exports::Supplier, prefix: lambda }
|
40
|
-
|
41
|
-
def init_report
|
42
|
-
klass.new(report_params)
|
43
|
-
end
|
44
|
-
|
45
|
-
def report_opts
|
46
|
-
opts
|
47
|
-
end
|
48
|
-
|
49
|
-
def report_params
|
50
|
-
opts.reject { |k, v| %i[class].include? k }.merge(nested_field: key)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class HasMany < HasOne; end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MagicReport
|
4
|
-
class Report
|
5
|
-
class Process
|
6
|
-
attr_reader :report
|
7
|
-
|
8
|
-
def initialize(report)
|
9
|
-
@report = report
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(input)
|
13
|
-
if input.is_a? Enumerable
|
14
|
-
input.map do |entity|
|
15
|
-
process_entity(entity)
|
16
|
-
end
|
17
|
-
else
|
18
|
-
process_entity(input)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def process_entity(entity)
|
25
|
-
row = Row.new
|
26
|
-
|
27
|
-
process_fields(entity, row)
|
28
|
-
process_has_one(entity, row)
|
29
|
-
process_has_many(entity, row)
|
30
|
-
|
31
|
-
row
|
32
|
-
end
|
33
|
-
|
34
|
-
def process_fields(entity, row)
|
35
|
-
report.fields.each do |field|
|
36
|
-
row.add(field: report.resolve_path(field.key), value: field.process(entity))
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def process_has_one(entity, row)
|
41
|
-
report.has_one.each do |association|
|
42
|
-
inner_row = association.process_entity(entity.send(association.key))
|
43
|
-
|
44
|
-
row.add_inner_row(field: report.resolve_path(association.key), row: inner_row)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def process_has_many(entity, row)
|
49
|
-
report.has_many.each do |association|
|
50
|
-
entity.send(association.key).each do |entity|
|
51
|
-
nested_row = association.process_entity(entity)
|
52
|
-
|
53
|
-
row.add_nested_row(field: report.resolve_path(association.key), row: nested_row)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/magic_report/utils.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MagicReport
|
4
|
-
module Utils
|
5
|
-
def underscore(klass)
|
6
|
-
return "ded" unless klass
|
7
|
-
|
8
|
-
klass.gsub(/::/, "/")
|
9
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
10
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
11
|
-
.tr("-", "_")
|
12
|
-
.tr("/", ".")
|
13
|
-
.downcase
|
14
|
-
end
|
15
|
-
|
16
|
-
def derive_class(opts, &block)
|
17
|
-
if block
|
18
|
-
raise "name option must be provided" unless opts[:name]
|
19
|
-
|
20
|
-
cloned_klass = ::MagicReport::Report.clone
|
21
|
-
cloned_klass.define_singleton_method(:name) { opts[:name] }
|
22
|
-
cloned_klass.class_eval(&block)
|
23
|
-
cloned_klass
|
24
|
-
else
|
25
|
-
opts[:class]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param name is the report name
|
30
|
-
# @key is a field
|
31
|
-
def t(name:, key:)
|
32
|
-
I18n.translate!("magic_report.#{name}.#{key}")
|
33
|
-
end
|
34
|
-
|
35
|
-
module_function :underscore
|
36
|
-
module_function :derive_class
|
37
|
-
module_function :t
|
38
|
-
end
|
39
|
-
end
|