proforma 1.0.0.pre.alpha

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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +8 -0
  3. data/.gitignore +4 -0
  4. data/.rubocop.yml +11 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +20 -0
  7. data/CHANGELOG.md +7 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +105 -0
  10. data/Guardfile +16 -0
  11. data/LICENSE +7 -0
  12. data/README.md +328 -0
  13. data/bin/console +11 -0
  14. data/bin/render +68 -0
  15. data/lib/proforma.rb +38 -0
  16. data/lib/proforma/compiling.rb +12 -0
  17. data/lib/proforma/compiling/aggregation.rb +62 -0
  18. data/lib/proforma/compiling/compilable.rb +21 -0
  19. data/lib/proforma/compiling/counter.rb +35 -0
  20. data/lib/proforma/core_ext/hash.rb +21 -0
  21. data/lib/proforma/document.rb +38 -0
  22. data/lib/proforma/hash_evaluator.rb +40 -0
  23. data/lib/proforma/model_factory.rb +38 -0
  24. data/lib/proforma/modeling.rb +21 -0
  25. data/lib/proforma/modeling/banner.rb +64 -0
  26. data/lib/proforma/modeling/collection.rb +34 -0
  27. data/lib/proforma/modeling/data_table.rb +117 -0
  28. data/lib/proforma/modeling/data_table/aggregator.rb +43 -0
  29. data/lib/proforma/modeling/data_table/column.rb +94 -0
  30. data/lib/proforma/modeling/generic_container.rb +57 -0
  31. data/lib/proforma/modeling/grouping.rb +40 -0
  32. data/lib/proforma/modeling/header.rb +18 -0
  33. data/lib/proforma/modeling/pane.rb +40 -0
  34. data/lib/proforma/modeling/pane/column.rb +68 -0
  35. data/lib/proforma/modeling/pane/line.rb +42 -0
  36. data/lib/proforma/modeling/separator.rb +19 -0
  37. data/lib/proforma/modeling/spacer.rb +19 -0
  38. data/lib/proforma/modeling/table.rb +52 -0
  39. data/lib/proforma/modeling/table/cell.rb +49 -0
  40. data/lib/proforma/modeling/table/row.rb +24 -0
  41. data/lib/proforma/modeling/table/section.rb +23 -0
  42. data/lib/proforma/modeling/text.rb +37 -0
  43. data/lib/proforma/modeling/types.rb +10 -0
  44. data/lib/proforma/modeling/types/align.rb +22 -0
  45. data/lib/proforma/plain_text_renderer.rb +106 -0
  46. data/lib/proforma/prototype.rb +28 -0
  47. data/lib/proforma/template.rb +65 -0
  48. data/lib/proforma/type_factory.rb +44 -0
  49. data/lib/proforma/version.rb +12 -0
  50. data/proforma.gemspec +34 -0
  51. data/spec/fixtures/snapshots/custom_table.yml +55 -0
  52. data/spec/fixtures/snapshots/user_details.yml +101 -0
  53. data/spec/fixtures/snapshots/user_list.yml +143 -0
  54. data/spec/proforma/hash_evaluator_spec.rb +26 -0
  55. data/spec/proforma/modeling/table/cell_spec.rb +26 -0
  56. data/spec/proforma/modeling/table/row_spec.rb +42 -0
  57. data/spec/proforma_spec.rb +230 -0
  58. data/spec/spec_helper.rb +25 -0
  59. metadata +211 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Proforma
11
+ module Modeling
12
+ # A general purpose grouping of modeling objects. When compiled, they will each be
13
+ # compiled once then their output(s) are combined and flattened.
14
+ class Collection
15
+ acts_as_hashable
16
+
17
+ attr_writer :children
18
+
19
+ def initialize(children: [])
20
+ @children = ModelFactory.array(children)
21
+ end
22
+
23
+ def children
24
+ Array(@children)
25
+ end
26
+
27
+ def compile(data, evaluator)
28
+ children.map do |section|
29
+ section.respond_to?(:compile) ? section.compile(data, evaluator) : section
30
+ end.flatten
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'data_table/aggregator'
11
+ require_relative 'data_table/column'
12
+
13
+ module Proforma
14
+ module Modeling
15
+ # A table that understands how to be compiled against a data source.
16
+ class DataTable
17
+ include Compiling::Compilable
18
+ acts_as_hashable
19
+
20
+ attr_accessor :property
21
+
22
+ attr_writer :aggregators,
23
+ :columns,
24
+ :empty_message
25
+
26
+ def initialize(
27
+ aggregators: [],
28
+ columns: [],
29
+ empty_message: '',
30
+ property: nil
31
+ )
32
+ @aggregators = Aggregator.array(aggregators)
33
+ @columns = Column.array(columns)
34
+ @empty_message = empty_message
35
+ @property = property
36
+ end
37
+
38
+ def empty_message
39
+ @empty_message.to_s
40
+ end
41
+
42
+ def aggregators
43
+ Array(@aggregators)
44
+ end
45
+
46
+ def columns
47
+ Array(@columns)
48
+ end
49
+
50
+ def compile(data, evaluator)
51
+ records = array(evaluator.value(data, property))
52
+
53
+ return Text.new(value: empty_message) if show_empty_message?(records)
54
+
55
+ meta_data = make_aggregator_meta_data(records, evaluator)
56
+
57
+ Table.new(
58
+ body: make_body(records, evaluator),
59
+ footer: make_footer(meta_data, evaluator),
60
+ header: make_header({}, evaluator)
61
+ )
62
+ end
63
+
64
+ private
65
+
66
+ def make_aggregator_meta_data(records, evaluator)
67
+ Compiling::Aggregation.new(aggregators, evaluator).add(records).to_hash
68
+ end
69
+
70
+ def footer?
71
+ columns.select(&:footer?).any?
72
+ end
73
+
74
+ def header?
75
+ columns.select(&:header?).any?
76
+ end
77
+
78
+ def show_empty_message?(records)
79
+ records.empty? && !empty_message.empty?
80
+ end
81
+
82
+ def make_footer(data, evaluator)
83
+ make(footer?, :compile_footer_cell, data, evaluator)
84
+ end
85
+
86
+ def make_header(data, evaluator)
87
+ make(header?, :compile_header_cell, data, evaluator)
88
+ end
89
+
90
+ def make(visible, row_compile_method, data, evaluator)
91
+ return Table::Section.new unless visible
92
+
93
+ rows = [
94
+ make_row(row_compile_method, data, evaluator)
95
+ ]
96
+
97
+ Table::Section.new(rows: rows)
98
+ end
99
+
100
+ def make_body(records, evaluator)
101
+ rows = records.map do |record|
102
+ make_row(:compile_body_cell, record, evaluator)
103
+ end
104
+
105
+ Table::Section.new(rows: rows)
106
+ end
107
+
108
+ def make_row(method, record, evaluator)
109
+ cells = columns.map do |column|
110
+ column.send(method, record, evaluator)
111
+ end
112
+
113
+ Table::Row.new(cells: cells)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Proforma
11
+ module Modeling
12
+ class DataTable
13
+ # An Aggregator is a table aggregator function configuration.
14
+ class Aggregator
15
+ acts_as_hashable
16
+
17
+ module Function
18
+ SUM = :sum
19
+ AVE = :ave
20
+ end
21
+ include Function
22
+
23
+ attr_accessor :property
24
+
25
+ attr_writer :function, :name
26
+
27
+ def initialize(function: SUM, name: '', property: nil)
28
+ @function = function
29
+ @name = name
30
+ @property = property
31
+ end
32
+
33
+ def function
34
+ @function || SUM
35
+ end
36
+
37
+ def name
38
+ @name.to_s
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Proforma
11
+ module Modeling
12
+ class DataTable
13
+ # An explicit table column that understands how to compile header, body, and footer cells
14
+ # from records.
15
+ class Column
16
+ include Modeling::Types::Align
17
+ include Compiling::Compilable
18
+ acts_as_hashable
19
+
20
+ attr_writer :align,
21
+ :body,
22
+ :footer,
23
+ :header,
24
+ :width
25
+
26
+ def initialize(
27
+ align: LEFT,
28
+ body: '',
29
+ footer: '',
30
+ header: '',
31
+ width: nil
32
+ )
33
+ @align = align
34
+ @body = body
35
+ @footer = footer
36
+ @header = header
37
+ @width = width
38
+ end
39
+
40
+ def align
41
+ @align || LEFT
42
+ end
43
+
44
+ def body
45
+ @body.to_s
46
+ end
47
+
48
+ def footer
49
+ @footer.to_s
50
+ end
51
+
52
+ def header
53
+ @header.to_s
54
+ end
55
+
56
+ def width
57
+ @width ? @width.to_f : nil
58
+ end
59
+
60
+ def compile_header_cell(record, evaluator)
61
+ Modeling::Table::Cell.new(
62
+ align: align,
63
+ text: evaluator.text(record, header),
64
+ width: width
65
+ )
66
+ end
67
+
68
+ def compile_body_cell(record, evaluator)
69
+ Modeling::Table::Cell.new(
70
+ align: align,
71
+ text: evaluator.text(record, body),
72
+ width: width
73
+ )
74
+ end
75
+
76
+ def compile_footer_cell(record, evaluator)
77
+ Modeling::Table::Cell.new(
78
+ align: align,
79
+ text: evaluator.text(record, footer),
80
+ width: width
81
+ )
82
+ end
83
+
84
+ def footer?
85
+ !footer.to_s.empty?
86
+ end
87
+
88
+ def header?
89
+ !header.to_s.empty?
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Proforma
11
+ module Modeling
12
+ # This can be used as a super-class for models which are basically containers for
13
+ # simple arrays of elements
14
+ class GenericContainer
15
+ def initialize(child_key, child_class, children = [])
16
+ raise ArgumentError, 'child_key is required' unless child_key
17
+ raise ArgumentError, 'child_class is required' unless child_class
18
+
19
+ @child_class = child_class
20
+ @child_key = child_key.to_s.to_sym
21
+ @children = child_class.array(children)
22
+ end
23
+
24
+ def respond_to_missing?(method_name, include_private = false)
25
+ method_name.to_s == child_key.to_s ||
26
+ method_name.to_s == child_setter_name ||
27
+ super
28
+ end
29
+
30
+ def method_missing(method_name, *args, &block)
31
+ if method_name.to_s == child_key.to_s
32
+ Array(children)
33
+ elsif method_name.to_s == child_setter_name
34
+ @children = args
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def compile(data, evaluator)
41
+ compiled_children = children.map { |child| child.compile(data, evaluator) }
42
+
43
+ args = {}.tap { |hash| hash[child_key] = compiled_children }
44
+
45
+ self.class.new(args)
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :child_class, :child_key, :children
51
+
52
+ def child_setter_name
53
+ "#{child_key}="
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Proforma
11
+ module Modeling
12
+ # A grouping is an inverted collection, meaning, it iterates each child once per record
13
+ # instead of only one time. It also provides a mechanic to traverse data to tap
14
+ # nested child data (through the property attribute.)
15
+ class Grouping
16
+ include Compiling::Compilable
17
+ acts_as_hashable
18
+
19
+ attr_accessor :property
20
+
21
+ attr_writer :children
22
+
23
+ def initialize(children: [], property: nil)
24
+ @children = ModelFactory.array(children)
25
+ @property = property
26
+ end
27
+
28
+ def children
29
+ Array(@children)
30
+ end
31
+
32
+ def compile(data, evaluator)
33
+ records = array(evaluator.value(data, property))
34
+
35
+ records.map { |record| Collection.new(children: children).compile(record, evaluator) }
36
+ .flatten
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'text'
11
+
12
+ module Proforma
13
+ module Modeling
14
+ # A Header is an object representation of an important text-based title.
15
+ class Header < Text
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'pane/column'
11
+ require_relative 'pane/line'
12
+
13
+ module Proforma
14
+ module Modeling
15
+ # Think of a pane like a pivoted table. It has columns but not in the same respect as
16
+ # a table's columns. For a pane, it makes up a vertical section. Each column (section)
17
+ # then has a number of lines which holds the label:value pairs that facilitates data
18
+ # rendering.
19
+ class Pane
20
+ include Compiling::Compilable
21
+ acts_as_hashable
22
+
23
+ attr_writer :columns
24
+
25
+ def initialize(columns: [])
26
+ @columns = Column.array(columns)
27
+ end
28
+
29
+ def columns
30
+ Array(@columns)
31
+ end
32
+
33
+ def compile(data, evaluator)
34
+ compiled_columns = columns.map { |column| column.compile(data, evaluator) }
35
+
36
+ self.class.new(columns: compiled_columns)
37
+ end
38
+ end
39
+ end
40
+ end