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.
- checksums.yaml +7 -0
- data/.editorconfig +8 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +11 -0
- data/.ruby-version +1 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +105 -0
- data/Guardfile +16 -0
- data/LICENSE +7 -0
- data/README.md +328 -0
- data/bin/console +11 -0
- data/bin/render +68 -0
- data/lib/proforma.rb +38 -0
- data/lib/proforma/compiling.rb +12 -0
- data/lib/proforma/compiling/aggregation.rb +62 -0
- data/lib/proforma/compiling/compilable.rb +21 -0
- data/lib/proforma/compiling/counter.rb +35 -0
- data/lib/proforma/core_ext/hash.rb +21 -0
- data/lib/proforma/document.rb +38 -0
- data/lib/proforma/hash_evaluator.rb +40 -0
- data/lib/proforma/model_factory.rb +38 -0
- data/lib/proforma/modeling.rb +21 -0
- data/lib/proforma/modeling/banner.rb +64 -0
- data/lib/proforma/modeling/collection.rb +34 -0
- data/lib/proforma/modeling/data_table.rb +117 -0
- data/lib/proforma/modeling/data_table/aggregator.rb +43 -0
- data/lib/proforma/modeling/data_table/column.rb +94 -0
- data/lib/proforma/modeling/generic_container.rb +57 -0
- data/lib/proforma/modeling/grouping.rb +40 -0
- data/lib/proforma/modeling/header.rb +18 -0
- data/lib/proforma/modeling/pane.rb +40 -0
- data/lib/proforma/modeling/pane/column.rb +68 -0
- data/lib/proforma/modeling/pane/line.rb +42 -0
- data/lib/proforma/modeling/separator.rb +19 -0
- data/lib/proforma/modeling/spacer.rb +19 -0
- data/lib/proforma/modeling/table.rb +52 -0
- data/lib/proforma/modeling/table/cell.rb +49 -0
- data/lib/proforma/modeling/table/row.rb +24 -0
- data/lib/proforma/modeling/table/section.rb +23 -0
- data/lib/proforma/modeling/text.rb +37 -0
- data/lib/proforma/modeling/types.rb +10 -0
- data/lib/proforma/modeling/types/align.rb +22 -0
- data/lib/proforma/plain_text_renderer.rb +106 -0
- data/lib/proforma/prototype.rb +28 -0
- data/lib/proforma/template.rb +65 -0
- data/lib/proforma/type_factory.rb +44 -0
- data/lib/proforma/version.rb +12 -0
- data/proforma.gemspec +34 -0
- data/spec/fixtures/snapshots/custom_table.yml +55 -0
- data/spec/fixtures/snapshots/user_details.yml +101 -0
- data/spec/fixtures/snapshots/user_list.yml +143 -0
- data/spec/proforma/hash_evaluator_spec.rb +26 -0
- data/spec/proforma/modeling/table/cell_spec.rb +26 -0
- data/spec/proforma/modeling/table/row_spec.rb +42 -0
- data/spec/proforma_spec.rb +230 -0
- data/spec/spec_helper.rb +25 -0
- 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
|