thinreports 0.11.0 → 0.12.0
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/.github/CONTRIBUTING.md +2 -2
- data/.github/workflows/test.yml +17 -5
- data/CHANGELOG.md +12 -1
- data/Dockerfile +1 -1
- data/Gemfile +0 -4
- data/README.md +4 -2
- data/gemfiles/prawn-2.2.gemfile +5 -0
- data/gemfiles/prawn-2.3.gemfile +5 -0
- data/gemfiles/prawn-2.4.gemfile +5 -0
- data/lib/thinreports.rb +5 -0
- data/lib/thinreports/core/shape.rb +2 -0
- data/lib/thinreports/core/shape/basic/format.rb +5 -0
- data/lib/thinreports/core/shape/stack_view.rb +17 -0
- data/lib/thinreports/core/shape/stack_view/format.rb +27 -0
- data/lib/thinreports/core/shape/stack_view/interface.rb +17 -0
- data/lib/thinreports/core/shape/stack_view/internal.rb +22 -0
- data/lib/thinreports/core/shape/stack_view/row_format.rb +39 -0
- data/lib/thinreports/core/shape/style/basic.rb +4 -1
- data/lib/thinreports/generate.rb +11 -0
- data/lib/thinreports/generator/pdf/document/draw_shape.rb +30 -9
- data/lib/thinreports/generator/pdf/document/graphics/image.rb +19 -1
- data/lib/thinreports/generator/pdf/document/graphics/text.rb +10 -5
- data/lib/thinreports/generator/pdf/document/page.rb +12 -0
- data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +7 -13
- data/lib/thinreports/section_report/build.rb +32 -0
- data/lib/thinreports/section_report/builder/item_builder.rb +49 -0
- data/lib/thinreports/section_report/builder/report_builder.rb +82 -0
- data/lib/thinreports/section_report/builder/report_data.rb +13 -0
- data/lib/thinreports/section_report/builder/stack_view_builder.rb +55 -0
- data/lib/thinreports/section_report/builder/stack_view_data.rb +11 -0
- data/lib/thinreports/section_report/generate.rb +26 -0
- data/lib/thinreports/section_report/pdf/render.rb +23 -0
- data/lib/thinreports/section_report/pdf/renderer/draw_item.rb +68 -0
- data/lib/thinreports/section_report/pdf/renderer/group_renderer.rb +57 -0
- data/lib/thinreports/section_report/pdf/renderer/headers_renderer.rb +24 -0
- data/lib/thinreports/section_report/pdf/renderer/section_height.rb +100 -0
- data/lib/thinreports/section_report/pdf/renderer/section_renderer.rb +39 -0
- data/lib/thinreports/section_report/pdf/renderer/stack_view_renderer.rb +55 -0
- data/lib/thinreports/section_report/pdf/renderer/stack_view_row_renderer.rb +38 -0
- data/lib/thinreports/section_report/schema/loader.rb +28 -0
- data/lib/thinreports/section_report/schema/parser.rb +52 -0
- data/lib/thinreports/section_report/schema/report.rb +30 -0
- data/lib/thinreports/section_report/schema/section.rb +47 -0
- data/lib/thinreports/version.rb +1 -1
- data/thinreports.gemspec +8 -2
- metadata +103 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9713f8331c7d6c97d17f0b30ba84124148f48ed40d3fde29f884503146415ed0
|
4
|
+
data.tar.gz: 0617cb86495f89090b6f751334aed7fd69c42b79357683992ac65d3ee0dc72e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37bd09438b27f1147c9803b0236bac461c0d5c08844bff920e7a183bd3f09912f157bf66c6ad246ece7a8c8041fd559a18495c56a22550459e15e357b60355c9
|
7
|
+
data.tar.gz: 43fd24534374c1c63162cece99c12622c5bdab0fce12c9f8c7b9e82d985ec50fc0b1fa388f1b67658ae3892e6b9d97350fada88ef6c48021c4dedecff128e910
|
data/.github/CONTRIBUTING.md
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
If you have a support question about how to use thinreports, please [ask on
|
1
|
+
We only accept bug reports and pull requests in GitHub.
|
2
|
+
If you have a support question about how to use thinreports, please [ask on GitHub Discussions](https://github.com/thinreports/thinreports/discussions).
|
data/.github/workflows/test.yml
CHANGED
@@ -1,19 +1,28 @@
|
|
1
1
|
name: Test
|
2
2
|
|
3
|
-
on: push
|
3
|
+
on: [push, pull_request]
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
test:
|
7
|
-
name: Test against ${{ matrix.ruby }}
|
7
|
+
name: Test against ruby ${{ matrix.ruby }} and prawn ${{ matrix.prawn }}
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
strategy:
|
10
10
|
matrix:
|
11
11
|
ruby:
|
12
|
-
- 2.4
|
13
12
|
- 2.5
|
14
13
|
- 2.6
|
15
14
|
- 2.7
|
15
|
+
- 3.0
|
16
16
|
- jruby
|
17
|
+
prawn:
|
18
|
+
- 2.2
|
19
|
+
- 2.3
|
20
|
+
- 2.4
|
21
|
+
exclude:
|
22
|
+
- ruby: 3.0
|
23
|
+
prawn: 2.2
|
24
|
+
- ruby: 3.0
|
25
|
+
prawn: 2.3
|
17
26
|
|
18
27
|
steps:
|
19
28
|
- uses: actions/checkout@v1
|
@@ -31,9 +40,12 @@ jobs:
|
|
31
40
|
with:
|
32
41
|
ruby-version: ${{ matrix.ruby }}
|
33
42
|
|
34
|
-
- name:
|
43
|
+
- name: Install dependencies
|
35
44
|
run: |
|
36
45
|
gem install bundler
|
37
|
-
bundle install --jobs 4 --retry 3
|
46
|
+
bundle install --gemfile gemfiles/prawn-${{ matrix.prawn }}.gemfile --jobs 4 --retry 3
|
47
|
+
|
48
|
+
- name: Run tests
|
49
|
+
run: |
|
38
50
|
bundle exec rake test:units
|
39
51
|
bundle exec rake test:features
|
data/CHANGELOG.md
CHANGED
data/Dockerfile
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -15,11 +15,13 @@
|
|
15
15
|
* [Quick Start Guide](http://www.thinreports.org/documentation/getting-started/quickstart.html)
|
16
16
|
* [Examples](https://github.com/thinreports/thinreports-examples)
|
17
17
|
* [Changelog](https://github.com/thinreports/thinreports-generator/blob/master/CHANGELOG.md)
|
18
|
-
* [Discussion Group](https://
|
18
|
+
* [Discussion Group (GitHub Discussions)](https://github.com/thinreports/thinreports/discussions)
|
19
|
+
* [Discussion Group (Google Groups)](https://groups.google.com/forum/#!forum/thinreports)
|
19
20
|
|
20
21
|
## Supported versions
|
21
22
|
|
22
|
-
* Ruby 2.
|
23
|
+
* Ruby 2.5, 2.6, 2.7, 3.0
|
24
|
+
* Prawn 2.2, 2.3, 2.4
|
23
25
|
* JRuby 9.2
|
24
26
|
|
25
27
|
## Quick Reference
|
data/lib/thinreports.rb
CHANGED
@@ -6,6 +6,10 @@ module Thinreports
|
|
6
6
|
def self.root
|
7
7
|
@root ||= Pathname.new(__FILE__).join('..', '..')
|
8
8
|
end
|
9
|
+
|
10
|
+
def self.generate(report_params, filename: nil)
|
11
|
+
Generate.new.call(report_params, filename: filename)
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
require_relative 'thinreports/version'
|
@@ -18,3 +22,4 @@ require_relative 'thinreports/core/utils'
|
|
18
22
|
require_relative 'thinreports/report'
|
19
23
|
require_relative 'thinreports/layout'
|
20
24
|
require_relative 'thinreports/generator/pdf'
|
25
|
+
require_relative 'thinreports/generate'
|
@@ -18,6 +18,7 @@ module Thinreports
|
|
18
18
|
when TextBlock::TYPE_NAME then TextBlock
|
19
19
|
when ImageBlock::TYPE_NAME then ImageBlock
|
20
20
|
when List::TYPE_NAME then List
|
21
|
+
when StackView::TYPE_NAME then StackView
|
21
22
|
when Text::TYPE_NAME then Text
|
22
23
|
when PageNumber::TYPE_NAME then PageNumber
|
23
24
|
when *Basic::TYPE_NAMES then Basic
|
@@ -37,4 +38,5 @@ require_relative 'shape/text'
|
|
37
38
|
require_relative 'shape/text_block'
|
38
39
|
require_relative 'shape/image_block'
|
39
40
|
require_relative 'shape/list'
|
41
|
+
require_relative 'shape/stack_view'
|
40
42
|
require_relative 'shape/page_number'
|
@@ -10,6 +10,11 @@ module Thinreports
|
|
10
10
|
config_reader :type, :id
|
11
11
|
config_reader :style
|
12
12
|
config_checker true, :display
|
13
|
+
config_reader follow_stretch: %w[follow-stretch]
|
14
|
+
|
15
|
+
def affect_bottom_margin?
|
16
|
+
attributes.fetch('affect-bottom-margin', true)
|
17
|
+
end
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thinreports
|
4
|
+
module Core
|
5
|
+
module Shape
|
6
|
+
module StackView
|
7
|
+
TYPE_NAME = 'stack-view'.freeze
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require_relative 'stack_view/format'
|
14
|
+
require_relative 'stack_view/interface'
|
15
|
+
require_relative 'stack_view/internal'
|
16
|
+
|
17
|
+
require_relative 'stack_view/row_format'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thinreports
|
4
|
+
module Core
|
5
|
+
module Shape
|
6
|
+
module StackView
|
7
|
+
class Format < Basic::Format
|
8
|
+
attr_reader :rows
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
initialize_rows
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def initialize_rows
|
18
|
+
@rows = []
|
19
|
+
attributes['rows'].each do |row|
|
20
|
+
@rows << StackView::RowFormat.new(row)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thinreports
|
4
|
+
module Core
|
5
|
+
module Shape
|
6
|
+
module StackView
|
7
|
+
class Interface < Basic::Interface
|
8
|
+
private
|
9
|
+
|
10
|
+
def init_internal(parent, format)
|
11
|
+
StackView::Internal.new(parent, format)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thinreports
|
4
|
+
module Core
|
5
|
+
module Shape
|
6
|
+
module StackView
|
7
|
+
class Internal < Basic::Internal
|
8
|
+
def initialize(parent, format)
|
9
|
+
super
|
10
|
+
@rows = []
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :rows
|
14
|
+
|
15
|
+
def type_of?(type_name)
|
16
|
+
type_name == StackView::TYPE_NAME
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Thinreports
|
4
|
+
module Core
|
5
|
+
module Shape
|
6
|
+
module StackView
|
7
|
+
class RowFormat < Core::Format::Base
|
8
|
+
config_reader :id
|
9
|
+
config_reader :height
|
10
|
+
config_checker true, :display
|
11
|
+
config_checker true, auto_stretch: 'auto-stretch'
|
12
|
+
|
13
|
+
attr_reader :items
|
14
|
+
|
15
|
+
def initialize(*)
|
16
|
+
super
|
17
|
+
@items = []
|
18
|
+
@item_with_ids = {}
|
19
|
+
initialize_items(attributes['items'])
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_item(id)
|
23
|
+
@item_with_ids[id.to_sym]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def initialize_items(item_schemas)
|
29
|
+
item_schemas.each do |item_schema|
|
30
|
+
item = Core::Shape::Format(item_schema['type']).new(item_schema)
|
31
|
+
@items << item
|
32
|
+
@item_with_ids[item.id.to_sym] = item unless item.id.empty?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -5,9 +5,12 @@ module Thinreports
|
|
5
5
|
module Shape
|
6
6
|
module Style
|
7
7
|
class Basic < Style::Base
|
8
|
-
style_accessible :visible
|
8
|
+
style_accessible :visible, :offset_x, :offset_y
|
9
9
|
attr_accessor :visible
|
10
10
|
|
11
|
+
style_accessor :offset_x, 'offset-x'
|
12
|
+
style_accessor :offset_y, 'offset-y'
|
13
|
+
|
11
14
|
def initialize(*args)
|
12
15
|
super
|
13
16
|
@visible = @format.display?
|
@@ -5,20 +5,26 @@ module Thinreports
|
|
5
5
|
class PDF
|
6
6
|
module DrawShape
|
7
7
|
# @param [Thinreports::Core::Shape::TextBlock::Internal] shape
|
8
|
-
|
9
|
-
|
8
|
+
# @param [Numeric] height (nil) It will be used as rendering height if present.
|
9
|
+
# Otherwise, the rendering height is the height of schema.
|
10
|
+
# @param [:truncate, :shrink_to_fit, :expand] overflow (nil) It will be set the overflow attribute if present.
|
11
|
+
def draw_shape_tblock(shape, height: nil, overflow: nil, &block)
|
12
|
+
x, y, w = shape.format.attributes.values_at('x', 'y', 'width')
|
13
|
+
|
14
|
+
h = height || shape.format.attributes['height']
|
10
15
|
|
11
16
|
content = shape.real_value.to_s
|
12
17
|
return if content.empty?
|
13
18
|
|
14
19
|
attrs = build_text_attributes(shape.style.finalized_styles)
|
20
|
+
attrs[:overflow] = overflow if overflow
|
15
21
|
|
16
22
|
unless shape.multiple?
|
17
23
|
content = content.tr("\n", ' ')
|
18
24
|
attrs[:single] = true
|
19
25
|
end
|
20
26
|
|
21
|
-
text_box(content, x, y, w, h, attrs)
|
27
|
+
text_box(content, x, y, w, h, attrs, &block)
|
22
28
|
end
|
23
29
|
|
24
30
|
def draw_shape_pageno(shape, page_no, page_count)
|
@@ -44,6 +50,21 @@ module Thinreports
|
|
44
50
|
style = shape.style.finalized_styles
|
45
51
|
|
46
52
|
image_box(
|
53
|
+
shape.src, x, y, w, h,
|
54
|
+
position_x: image_position_x(style['position-x']),
|
55
|
+
position_y: image_position_y(style['position-y']),
|
56
|
+
offset_x: style['offset-x'],
|
57
|
+
offset_y: style['offset-y']
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def shape_iblock_dimenions(shape)
|
62
|
+
return nil if blank_value?(shape.src)
|
63
|
+
|
64
|
+
x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
|
65
|
+
style = shape.style.finalized_styles
|
66
|
+
|
67
|
+
image_dimensions(
|
47
68
|
shape.src, x, y, w, h,
|
48
69
|
position_x: image_position_x(style['position-x']),
|
49
70
|
position_y: image_position_y(style['position-y'])
|
@@ -51,10 +72,10 @@ module Thinreports
|
|
51
72
|
end
|
52
73
|
|
53
74
|
# @param [Thinreports::Core::Shape::Text::Internal] shape
|
54
|
-
def draw_shape_text(shape)
|
75
|
+
def draw_shape_text(shape, dheight = 0)
|
55
76
|
x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
|
56
77
|
text(
|
57
|
-
shape.texts.join("\n"), x, y, w, h,
|
78
|
+
shape.texts.join("\n"), x, y, w, h + dheight,
|
58
79
|
build_text_attributes(shape.style.finalized_styles)
|
59
80
|
)
|
60
81
|
end
|
@@ -66,18 +87,18 @@ module Thinreports
|
|
66
87
|
end
|
67
88
|
|
68
89
|
# @param [Thinreports::Core::Shape::Basic::Internal] shape
|
69
|
-
def draw_shape_line(shape)
|
90
|
+
def draw_shape_line(shape, dy1 = 0, dy2 = 0)
|
70
91
|
x1, y1, x2, y2 = shape.format.attributes.values_at('x1', 'y1', 'x2', 'y2')
|
71
|
-
line(x1, y1, x2, y2, build_graphic_attributes(shape.style.finalized_styles))
|
92
|
+
line(x1, y1 + dy1, x2, y2 + dy2, build_graphic_attributes(shape.style.finalized_styles))
|
72
93
|
end
|
73
94
|
|
74
95
|
# @param [Thinreports::Core::Shape::Basic::Internal] shape
|
75
|
-
def draw_shape_rect(shape)
|
96
|
+
def draw_shape_rect(shape, dheight = 0)
|
76
97
|
x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
|
77
98
|
rect_attributes = build_graphic_attributes(shape.style.finalized_styles) do |attrs|
|
78
99
|
attrs[:radius] = shape.format.attributes['border-radius']
|
79
100
|
end
|
80
|
-
rect(x, y, w, h, rect_attributes)
|
101
|
+
rect(x, y, w, h + dheight, rect_attributes)
|
81
102
|
end
|
82
103
|
end
|
83
104
|
end
|
@@ -39,9 +39,16 @@ module Thinreports
|
|
39
39
|
# @param [Hash] options
|
40
40
|
# @option options [:left, :center, :right] :position_x (:left)
|
41
41
|
# @option options [:top, :center, :bottom] :position_y (:top)
|
42
|
+
# @option options [Numeric] :offset_x
|
43
|
+
# @option options [Numeric] :offset_y
|
42
44
|
def image_box(filename_or_io, x, y, w, h, options = {})
|
43
45
|
w, h = s2f(w, h)
|
44
|
-
|
46
|
+
|
47
|
+
computed_position = pos(
|
48
|
+
x + (options[:offset_x] || 0),
|
49
|
+
y + (options[:offset_y] || 0)
|
50
|
+
)
|
51
|
+
pdf.bounding_box(computed_position, width: w, height: h) do
|
45
52
|
pdf.image(
|
46
53
|
filename_or_io,
|
47
54
|
position: options[:position_x] || :left,
|
@@ -51,6 +58,17 @@ module Thinreports
|
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
61
|
+
def image_dimensions(filename_or_io, x, y, w, h, options = {})
|
62
|
+
w, h = s2f(w, h)
|
63
|
+
# XXX: Calling @private method
|
64
|
+
_pdf_obj, info = pdf.build_image_object(filename_or_io)
|
65
|
+
info.calc_image_dimensions(
|
66
|
+
position: options[:position_x] || :left,
|
67
|
+
vposition: options[:position_y] || :top,
|
68
|
+
auto_fit: [w, h]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
54
72
|
def clean_temp_images
|
55
73
|
temp_image_registry.each_value do |image_path|
|
56
74
|
File.delete(image_path) if File.exist?(image_path)
|