thinreports 0.11.0 → 0.12.0

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