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,68 @@
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 Pane
13
+ # A Pane Column is a list of lines that understands how to compile itself against a
14
+ # data source.
15
+ class Column
16
+ extend Forwardable
17
+ include Types::Align
18
+ acts_as_hashable
19
+
20
+ attr_writer :align,
21
+ :label_width,
22
+ :lines,
23
+ :value_width
24
+
25
+ def_delegator :lines, :length, :line_count
26
+
27
+ def initialize(
28
+ align: LEFT,
29
+ label_width: nil,
30
+ lines: [],
31
+ value_width: nil
32
+ )
33
+ @align = align
34
+ @label_width = label_width
35
+ @lines = Line.array(lines)
36
+ @value_width = value_width
37
+ end
38
+
39
+ def align
40
+ @align || LEFT
41
+ end
42
+
43
+ def label_width
44
+ @label_width ? @label_width.to_f : nil
45
+ end
46
+
47
+ def value_width
48
+ @value_width ? @value_width.to_f : nil
49
+ end
50
+
51
+ def lines
52
+ Array(@lines)
53
+ end
54
+
55
+ def compile(record, evaluator)
56
+ compiled_lines = lines.map { |line| line.compile(record, evaluator) }
57
+
58
+ self.class.new(
59
+ align: align,
60
+ label_width: label_width,
61
+ lines: compiled_lines,
62
+ value_width: value_width
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,42 @@
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 Pane
13
+ # A line is a single label:value entry in a pane.
14
+ class Line
15
+ include Compiling::Compilable
16
+ acts_as_hashable
17
+
18
+ attr_writer :label, :value
19
+
20
+ def initialize(label: '', value: '')
21
+ @label = label
22
+ @value = value
23
+ end
24
+
25
+ def label
26
+ @label.to_s
27
+ end
28
+
29
+ def value
30
+ @value.to_s
31
+ end
32
+
33
+ def compile(record, evaluator)
34
+ self.class.new(
35
+ label: evaluator.text(record, label),
36
+ value: evaluator.text(record, value)
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
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
+ # An object modeling of the notion of separation of two other models/sections.
13
+ class Separator
14
+ acts_as_hashable
15
+
16
+ def initialize(*); end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
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
+ # An object modeling of the notion of spacing between two other models/sections.
13
+ class Spacer
14
+ acts_as_hashable
15
+
16
+ def initialize(*); end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,52 @@
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 'table/cell'
11
+ require_relative 'table/row'
12
+ require_relative 'table/section'
13
+
14
+ module Proforma
15
+ module Modeling
16
+ # A basic table structure modeled off of an HTML table:
17
+ # A table has three sections: header, body, footer.
18
+ # Each section has rows.
19
+ # Each row has cells.
20
+ class Table
21
+ acts_as_hashable
22
+
23
+ attr_writer :body, :footer, :header
24
+
25
+ def initialize(body: Section.new, footer: Section.new, header: Section.new)
26
+ @body = Section.make(body)
27
+ @footer = Section.make(footer)
28
+ @header = Section.make(header)
29
+ end
30
+
31
+ def body
32
+ @body || Section.new
33
+ end
34
+
35
+ def footer
36
+ @footer || Section.new
37
+ end
38
+
39
+ def header
40
+ @header || Section.new
41
+ end
42
+
43
+ def compile(data, evaluator)
44
+ self.class.new(
45
+ body: body.compile(data, evaluator),
46
+ footer: footer.compile(data, evaluator),
47
+ header: header.compile(data, evaluator)
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,49 @@
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 Table
13
+ # The lowest unit of a table. Each row is comprised of zero or more cells.
14
+ class Cell
15
+ include Compiling::Compilable
16
+ include Types::Align
17
+ acts_as_hashable
18
+
19
+ attr_writer :align, :text, :width
20
+
21
+ def initialize(align: LEFT, text: '', width: nil)
22
+ @align = align
23
+ @text = text
24
+ @width = width
25
+ end
26
+
27
+ def align
28
+ @align || LEFT
29
+ end
30
+
31
+ def text
32
+ @text.to_s
33
+ end
34
+
35
+ def width
36
+ @width ? @width.to_f : nil
37
+ end
38
+
39
+ def compile(data, evaluator)
40
+ self.class.new(
41
+ align: align,
42
+ text: evaluator.text(data, text),
43
+ width: width
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
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 Table
13
+ # The second lowest unit of a table. A table's header, body, and footer is each
14
+ # composed of zero or more rows.
15
+ class Row < GenericContainer
16
+ acts_as_hashable
17
+
18
+ def initialize(cells: [])
19
+ super(:cells, Cell, cells)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
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 Table
13
+ # A table section has zero or more rows.
14
+ class Section < GenericContainer
15
+ acts_as_hashable
16
+
17
+ def initialize(rows: [])
18
+ super(:rows, Row, rows)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
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
+ # Emit and render basic text against a record.
13
+ class Text
14
+ include Compiling::Compilable
15
+ extend Forwardable
16
+ acts_as_hashable
17
+
18
+ def_delegator :value, :empty?, :empty?
19
+
20
+ attr_writer :value
21
+
22
+ def initialize(value: '')
23
+ @value = value
24
+ end
25
+
26
+ def value
27
+ @value.to_s
28
+ end
29
+
30
+ def compile(data, evaluator)
31
+ self.class.new(
32
+ value: evaluator.text(data, value)
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
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 'types/align'
@@ -0,0 +1,22 @@
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
+ module Types
13
+ # Abstract positioning. Describes how to position something (somewhere).
14
+ # Most likely use-case is for vertial/horizontal text alignment.
15
+ module Align
16
+ LEFT = :left
17
+ CENTER = :center
18
+ RIGHT = :right
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,106 @@
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
+ # A basic rendering engine that will output plain-text. It is meant to serve as
12
+ # an example of how to create a rendering engine for this library.
13
+ class PlainTextRenderer
14
+ EXTENSION = '.txt'
15
+ RENDER_PREFIX = 'render_'
16
+
17
+ private_constant :EXTENSION, :RENDER_PREFIX
18
+
19
+ attr_reader :column_separator, :line_length, :pane_separator
20
+
21
+ def initialize(column_separator: ', ', line_length: 40, pane_separator: ': ')
22
+ @column_separator = column_separator.to_s
23
+ @line_length = line_length.to_i
24
+ @pane_separator = pane_separator.to_s
25
+ end
26
+
27
+ def render(prototype)
28
+ @writer = StringIO.new
29
+
30
+ prototype.children.each do |child|
31
+ method_name = child_method_name(child)
32
+
33
+ raise ArgumentError, "Cannot render: #{method_name}" unless respond_to?(method_name, true)
34
+
35
+ send(method_name, child)
36
+ end
37
+
38
+ Document.new(
39
+ contents: writer.string,
40
+ extension: EXTENSION,
41
+ title: prototype.title
42
+ )
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :writer
48
+
49
+ def render_banner(banner)
50
+ write_line(line('='))
51
+ write_line(banner.title)
52
+ write_line(line('='))
53
+ write_line(banner.details)
54
+ write_line(line('='))
55
+ end
56
+
57
+ def render_header(header)
58
+ write_line(header.value.to_s.upcase)
59
+ end
60
+
61
+ def render_text(text)
62
+ write_line(text.value)
63
+ end
64
+
65
+ def render_separator(_separator)
66
+ write_line(line('-'))
67
+ end
68
+
69
+ def render_spacer(_separator)
70
+ write_line
71
+ end
72
+
73
+ def render_table(table)
74
+ write_section(table.header)
75
+ write_section(table.body)
76
+ write_section(table.footer)
77
+ end
78
+
79
+ def render_pane(pane)
80
+ pane.columns.each do |column|
81
+ column.lines.each do |line|
82
+ write_line("#{line.label}#{pane_separator}#{line.value}")
83
+ end
84
+ end
85
+ end
86
+
87
+ def child_method_name(child)
88
+ name = child.class.name.split('::').last.downcase
89
+ "#{RENDER_PREFIX}#{name}"
90
+ end
91
+
92
+ def write_line(text = '')
93
+ writer.puts(text)
94
+ end
95
+
96
+ def line(char)
97
+ char * line_length
98
+ end
99
+
100
+ def write_section(section)
101
+ section.rows.each do |row|
102
+ write_line(row.cells.map(&:text).join(column_separator))
103
+ end
104
+ end
105
+ end
106
+ end