proforma 1.0.0.pre.alpha

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