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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CONTRIBUTING.md +2 -2
  3. data/.github/workflows/test.yml +17 -5
  4. data/CHANGELOG.md +12 -1
  5. data/Dockerfile +1 -1
  6. data/Gemfile +0 -4
  7. data/README.md +4 -2
  8. data/gemfiles/prawn-2.2.gemfile +5 -0
  9. data/gemfiles/prawn-2.3.gemfile +5 -0
  10. data/gemfiles/prawn-2.4.gemfile +5 -0
  11. data/lib/thinreports.rb +5 -0
  12. data/lib/thinreports/core/shape.rb +2 -0
  13. data/lib/thinreports/core/shape/basic/format.rb +5 -0
  14. data/lib/thinreports/core/shape/stack_view.rb +17 -0
  15. data/lib/thinreports/core/shape/stack_view/format.rb +27 -0
  16. data/lib/thinreports/core/shape/stack_view/interface.rb +17 -0
  17. data/lib/thinreports/core/shape/stack_view/internal.rb +22 -0
  18. data/lib/thinreports/core/shape/stack_view/row_format.rb +39 -0
  19. data/lib/thinreports/core/shape/style/basic.rb +4 -1
  20. data/lib/thinreports/generate.rb +11 -0
  21. data/lib/thinreports/generator/pdf/document/draw_shape.rb +30 -9
  22. data/lib/thinreports/generator/pdf/document/graphics/image.rb +19 -1
  23. data/lib/thinreports/generator/pdf/document/graphics/text.rb +10 -5
  24. data/lib/thinreports/generator/pdf/document/page.rb +12 -0
  25. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +7 -13
  26. data/lib/thinreports/section_report/build.rb +32 -0
  27. data/lib/thinreports/section_report/builder/item_builder.rb +49 -0
  28. data/lib/thinreports/section_report/builder/report_builder.rb +82 -0
  29. data/lib/thinreports/section_report/builder/report_data.rb +13 -0
  30. data/lib/thinreports/section_report/builder/stack_view_builder.rb +55 -0
  31. data/lib/thinreports/section_report/builder/stack_view_data.rb +11 -0
  32. data/lib/thinreports/section_report/generate.rb +26 -0
  33. data/lib/thinreports/section_report/pdf/render.rb +23 -0
  34. data/lib/thinreports/section_report/pdf/renderer/draw_item.rb +68 -0
  35. data/lib/thinreports/section_report/pdf/renderer/group_renderer.rb +57 -0
  36. data/lib/thinreports/section_report/pdf/renderer/headers_renderer.rb +24 -0
  37. data/lib/thinreports/section_report/pdf/renderer/section_height.rb +100 -0
  38. data/lib/thinreports/section_report/pdf/renderer/section_renderer.rb +39 -0
  39. data/lib/thinreports/section_report/pdf/renderer/stack_view_renderer.rb +55 -0
  40. data/lib/thinreports/section_report/pdf/renderer/stack_view_row_renderer.rb +38 -0
  41. data/lib/thinreports/section_report/schema/loader.rb +28 -0
  42. data/lib/thinreports/section_report/schema/parser.rb +52 -0
  43. data/lib/thinreports/section_report/schema/report.rb +30 -0
  44. data/lib/thinreports/section_report/schema/section.rb +47 -0
  45. data/lib/thinreports/version.rb +1 -1
  46. data/thinreports.gemspec +8 -2
  47. metadata +103 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b53f36fac9af329499239b3db9313911fba89c82dd28cf81ac2e9942bcdce13a
4
- data.tar.gz: 38ce4e9d25a709240a1242948a33d96372e3cb6981b07e3121c88967279a3eed
3
+ metadata.gz: 9713f8331c7d6c97d17f0b30ba84124148f48ed40d3fde29f884503146415ed0
4
+ data.tar.gz: 0617cb86495f89090b6f751334aed7fd69c42b79357683992ac65d3ee0dc72e0
5
5
  SHA512:
6
- metadata.gz: 5db1f93781fd6be18f53424eb2853b6701449938f2dc2875f287be74720611361f5dc7b6f657ea9fd96ed83de8056efa92cd4ae7b5b8c0df3d11bb318a81f7d6
7
- data.tar.gz: 25d1cc37589223ea85f574f7c6cf007a9e5682dff6f59051286c3fe691b5ab9704d9c5e40e8b3b9b49134406af538aa4e688a74d5416aa1082f6bc1330de173a
6
+ metadata.gz: 37bd09438b27f1147c9803b0236bac461c0d5c08844bff920e7a183bd3f09912f157bf66c6ad246ece7a8c8041fd559a18495c56a22550459e15e357b60355c9
7
+ data.tar.gz: 43fd24534374c1c63162cece99c12622c5bdab0fce12c9f8c7b9e82d985ec50fc0b1fa388f1b67658ae3892e6b9d97350fada88ef6c48021c4dedecff128e910
@@ -1,2 +1,2 @@
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 Google Group](https://groups.google.com/forum/?hl=ja#!forum/thinreports).
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).
@@ -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: Build and test with Rake
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
@@ -1,4 +1,15 @@
1
- ## master
1
+ ## master (Unreleased)
2
+
3
+ ## 0.12.0
4
+
5
+ Breaking Changes:
6
+
7
+ * Drop Ruby 2.4 support #108, #109
8
+
9
+ Enhancements:
10
+
11
+ * Ruby 3.0 support #108, #109
12
+ * Prawn 2.4 support #108, #109
2
13
 
3
14
  ## 0.11.0
4
15
 
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.7.1
1
+ FROM ruby:3.0.0
2
2
 
3
3
  RUN apt-get update -qq && apt-get install -y build-essential xvfb
4
4
 
data/Gemfile CHANGED
@@ -4,7 +4,3 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'minitest', '>= 5.14.1'
8
- gem 'mocha', '>= 1.11.2'
9
- gem 'pdf-inspector', '>= 1.3.0'
10
- gem 'rake', '>= 13.0.1'
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://groups.google.com/forum/#!forum/thinreports)
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.4, 2.5, 2.6, 2.7
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
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'prawn', '~> 2.2.0'
4
+
5
+ gemspec path: '../'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'prawn', '~> 2.3.0'
4
+
5
+ gemspec path: '../'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'prawn', '~> 2.4.0'
4
+
5
+ gemspec path: '../'
@@ -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?
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'section_report/generate'
4
+
5
+ module Thinreports
6
+ class Generate
7
+ def call(report_params, filename: nil)
8
+ SectionReport::Generate.new.call(report_params, filename: filename)
9
+ end
10
+ end
11
+ end
@@ -5,20 +5,26 @@ module Thinreports
5
5
  class PDF
6
6
  module DrawShape
7
7
  # @param [Thinreports::Core::Shape::TextBlock::Internal] shape
8
- def draw_shape_tblock(shape)
9
- x, y, w, h = shape.format.attributes.values_at('x', 'y', 'width', 'height')
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
- pdf.bounding_box(pos(x, y), width: w, height: h) do
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)