thinreports 0.10.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 (191) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CONTRIBUTING.md +2 -2
  3. data/.github/workflows/test.yml +51 -0
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +49 -0
  6. data/Dockerfile +12 -0
  7. data/Gemfile +2 -1
  8. data/README.md +46 -21
  9. data/Rakefile +13 -29
  10. data/gemfiles/prawn-2.2.gemfile +5 -0
  11. data/gemfiles/prawn-2.3.gemfile +5 -0
  12. data/gemfiles/prawn-2.4.gemfile +5 -0
  13. data/lib/thinreports.rb +5 -0
  14. data/lib/thinreports/core/shape.rb +4 -3
  15. data/lib/thinreports/core/shape/base/interface.rb +0 -1
  16. data/lib/thinreports/core/shape/basic/format.rb +5 -0
  17. data/lib/thinreports/core/shape/image_block.rb +1 -1
  18. data/lib/thinreports/core/shape/list.rb +1 -1
  19. data/lib/thinreports/core/shape/list/manager.rb +1 -4
  20. data/lib/thinreports/core/shape/list/page.rb +2 -5
  21. data/lib/thinreports/core/shape/manager/internal.rb +0 -1
  22. data/lib/thinreports/core/shape/page_number.rb +1 -1
  23. data/lib/thinreports/core/shape/page_number/internal.rb +0 -1
  24. data/lib/thinreports/core/shape/stack_view.rb +17 -0
  25. data/lib/thinreports/core/shape/stack_view/format.rb +27 -0
  26. data/lib/thinreports/core/shape/stack_view/interface.rb +17 -0
  27. data/lib/thinreports/core/shape/stack_view/internal.rb +22 -0
  28. data/lib/thinreports/core/shape/stack_view/row_format.rb +39 -0
  29. data/lib/thinreports/core/shape/style/basic.rb +4 -1
  30. data/lib/thinreports/core/shape/text.rb +1 -1
  31. data/lib/thinreports/core/shape/text_block.rb +1 -1
  32. data/lib/thinreports/core/shape/text_block/formatter/number.rb +21 -9
  33. data/lib/thinreports/core/shape/text_block/internal.rb +0 -2
  34. data/lib/thinreports/core/utils.rb +6 -3
  35. data/lib/thinreports/generate.rb +11 -0
  36. data/lib/thinreports/generator/pdf/document/draw_shape.rb +31 -11
  37. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +1 -2
  38. data/lib/thinreports/generator/pdf/document/font.rb +16 -10
  39. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +0 -1
  40. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +0 -1
  41. data/lib/thinreports/generator/pdf/document/graphics/image.rb +19 -1
  42. data/lib/thinreports/generator/pdf/document/graphics/text.rb +10 -8
  43. data/lib/thinreports/generator/pdf/document/page.rb +13 -4
  44. data/lib/thinreports/generator/pdf/drawer/list.rb +0 -1
  45. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +1 -3
  46. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +7 -7
  47. data/lib/thinreports/layout/base.rb +2 -4
  48. data/lib/thinreports/layout/format.rb +0 -1
  49. data/lib/thinreports/layout/legacy_schema.rb +2 -6
  50. data/lib/thinreports/layout/version.rb +1 -1
  51. data/lib/thinreports/report/internal.rb +4 -4
  52. data/lib/thinreports/report/page.rb +2 -7
  53. data/lib/thinreports/section_report/build.rb +32 -0
  54. data/lib/thinreports/section_report/builder/item_builder.rb +49 -0
  55. data/lib/thinreports/section_report/builder/report_builder.rb +82 -0
  56. data/lib/thinreports/section_report/builder/report_data.rb +13 -0
  57. data/lib/thinreports/section_report/builder/stack_view_builder.rb +55 -0
  58. data/lib/thinreports/section_report/builder/stack_view_data.rb +11 -0
  59. data/lib/thinreports/section_report/generate.rb +26 -0
  60. data/lib/thinreports/section_report/pdf/render.rb +23 -0
  61. data/lib/thinreports/section_report/pdf/renderer/draw_item.rb +68 -0
  62. data/lib/thinreports/section_report/pdf/renderer/group_renderer.rb +57 -0
  63. data/lib/thinreports/section_report/pdf/renderer/headers_renderer.rb +24 -0
  64. data/lib/thinreports/section_report/pdf/renderer/section_height.rb +100 -0
  65. data/lib/thinreports/section_report/pdf/renderer/section_renderer.rb +39 -0
  66. data/lib/thinreports/section_report/pdf/renderer/stack_view_renderer.rb +55 -0
  67. data/lib/thinreports/section_report/pdf/renderer/stack_view_row_renderer.rb +38 -0
  68. data/lib/thinreports/section_report/schema/loader.rb +28 -0
  69. data/lib/thinreports/section_report/schema/parser.rb +52 -0
  70. data/lib/thinreports/section_report/schema/report.rb +30 -0
  71. data/lib/thinreports/section_report/schema/section.rb +47 -0
  72. data/lib/thinreports/version.rb +1 -1
  73. data/thinreports.gemspec +11 -11
  74. metadata +48 -164
  75. data/.rubocop.yml +0 -41
  76. data/.travis.yml +0 -17
  77. data/examples/character_spacing/character_spacing.rb +0 -8
  78. data/examples/character_spacing/character_spacing.tlf +0 -293
  79. data/examples/dynamic_image/dynamic_image.rb +0 -31
  80. data/examples/dynamic_image/dynamic_image.tlf +0 -661
  81. data/examples/dynamic_image/img200x100.png +0 -0
  82. data/examples/dynamic_image/img50x50.png +0 -0
  83. data/examples/dynamic_style/dynamic_style.rb +0 -150
  84. data/examples/dynamic_style/dynamic_style.tlf +0 -1835
  85. data/examples/dynamic_style/dynamic_style_in_list.tlf +0 -344
  86. data/examples/dynamic_style/image.png +0 -0
  87. data/examples/eudc/eudc.rb +0 -20
  88. data/examples/eudc/eudc.tlf +0 -180
  89. data/examples/eudc/eudc.ttf +0 -0
  90. data/examples/helper.rb +0 -50
  91. data/examples/hidden_shapes/hidden_shapes.rb +0 -9
  92. data/examples/hidden_shapes/hidden_shapes.tlf +0 -449
  93. data/examples/list_events/list_events.rb +0 -32
  94. data/examples/list_events/list_events.tlf +0 -361
  95. data/examples/list_manual_generation/list_manual_generation.rb +0 -22
  96. data/examples/list_manual_generation/list_manual_generation.tlf +0 -132
  97. data/examples/list_page_number/list_page_number.rb +0 -17
  98. data/examples/list_page_number/list_page_number.tlf +0 -254
  99. data/examples/page_number/page_number.rb +0 -33
  100. data/examples/page_number/page_number.tlf +0 -215
  101. data/examples/palleted_png/palleted_png.png +0 -0
  102. data/examples/palleted_png/palleted_png.rb +0 -9
  103. data/examples/palleted_png/palleted_png.tlf +0 -47
  104. data/examples/password_setting/password_setting.rb +0 -10
  105. data/examples/password_setting/password_setting.tlf +0 -45
  106. data/examples/report_callbacks/report_callbacks.rb +0 -14
  107. data/examples/report_callbacks/report_callbacks.tlf +0 -147
  108. data/examples/single_line_tblock/single_line_tblock.rb +0 -13
  109. data/examples/single_line_tblock/single_line_tblock.tlf +0 -170
  110. data/examples/tblock_overflow/tblock_overflow.rb +0 -20
  111. data/examples/tblock_overflow/tblock_overflow.tlf +0 -538
  112. data/examples/tblock_styles/font_size.tlf +0 -383
  113. data/examples/tblock_styles/tblock_styles.rb +0 -43
  114. data/examples/tblock_styles/tblock_styles.tlf +0 -889
  115. data/examples/text_align/text_align.rb +0 -8
  116. data/examples/text_align/text_align.tlf +0 -241
  117. data/examples/typeB_page_size/B4_ISO.tlf +0 -45
  118. data/examples/typeB_page_size/B4_JIS.tlf +0 -45
  119. data/examples/typeB_page_size/typeB_page_size.rb +0 -17
  120. data/examples/word_wrap/word_wrap.rb +0 -26
  121. data/examples/word_wrap/word_wrap.tlf +0 -297
  122. data/test/data/font.ttf +0 -0
  123. data/test/data/image_normal.jpg +0 -0
  124. data/test/data/image_normal.png +0 -0
  125. data/test/data/image_normal_jpg_noext +0 -0
  126. data/test/data/image_normal_png_noext +0 -0
  127. data/test/data/image_pallete_based.png +0 -0
  128. data/test/data/legacy_layout/all-items.tlf +0 -1
  129. data/test/schema_helper.rb +0 -122
  130. data/test/test_helper.rb +0 -48
  131. data/test/tmp/.gitkeep +0 -0
  132. data/test/unit/core/format/test_base.rb +0 -152
  133. data/test/unit/core/shape/base/test_internal.rb +0 -87
  134. data/test/unit/core/shape/basic/test_block_format.rb +0 -23
  135. data/test/unit/core/shape/basic/test_block_interface.rb +0 -29
  136. data/test/unit/core/shape/basic/test_block_internal.rb +0 -55
  137. data/test/unit/core/shape/basic/test_format.rb +0 -37
  138. data/test/unit/core/shape/basic/test_interface.rb +0 -108
  139. data/test/unit/core/shape/basic/test_internal.rb +0 -55
  140. data/test/unit/core/shape/image_block/test_interface.rb +0 -24
  141. data/test/unit/core/shape/image_block/test_internal.rb +0 -31
  142. data/test/unit/core/shape/list/test_format.rb +0 -111
  143. data/test/unit/core/shape/list/test_manager.rb +0 -67
  144. data/test/unit/core/shape/list/test_page.rb +0 -82
  145. data/test/unit/core/shape/list/test_page_state.rb +0 -31
  146. data/test/unit/core/shape/list/test_section_format.rb +0 -36
  147. data/test/unit/core/shape/list/test_section_interface.rb +0 -75
  148. data/test/unit/core/shape/list/test_section_internal.rb +0 -50
  149. data/test/unit/core/shape/manager/test_format.rb +0 -38
  150. data/test/unit/core/shape/manager/test_internal.rb +0 -132
  151. data/test/unit/core/shape/manager/test_target.rb +0 -140
  152. data/test/unit/core/shape/page_number/test_format.rb +0 -55
  153. data/test/unit/core/shape/page_number/test_interface.rb +0 -33
  154. data/test/unit/core/shape/page_number/test_internal.rb +0 -81
  155. data/test/unit/core/shape/styles/test_base.rb +0 -191
  156. data/test/unit/core/shape/styles/test_basic.rb +0 -24
  157. data/test/unit/core/shape/styles/test_graphic.rb +0 -50
  158. data/test/unit/core/shape/styles/test_text.rb +0 -97
  159. data/test/unit/core/shape/text/test_format.rb +0 -44
  160. data/test/unit/core/shape/text/test_internal.rb +0 -20
  161. data/test/unit/core/shape/text_block/formatter/test_basic.rb +0 -24
  162. data/test/unit/core/shape/text_block/formatter/test_datetime.rb +0 -49
  163. data/test/unit/core/shape/text_block/formatter/test_number.rb +0 -76
  164. data/test/unit/core/shape/text_block/formatter/test_padding.rb +0 -77
  165. data/test/unit/core/shape/text_block/test_format.rb +0 -169
  166. data/test/unit/core/shape/text_block/test_formatter.rb +0 -28
  167. data/test/unit/core/shape/text_block/test_interface.rb +0 -63
  168. data/test/unit/core/shape/text_block/test_internal.rb +0 -128
  169. data/test/unit/core/test_shape.rb +0 -52
  170. data/test/unit/core/test_utils.rb +0 -68
  171. data/test/unit/generator/pdf/document/graphics/test_attributes.rb +0 -135
  172. data/test/unit/generator/pdf/document/graphics/test_basic.rb +0 -46
  173. data/test/unit/generator/pdf/document/graphics/test_image.rb +0 -46
  174. data/test/unit/generator/pdf/document/graphics/test_text.rb +0 -171
  175. data/test/unit/generator/pdf/document/test_font.rb +0 -84
  176. data/test/unit/generator/pdf/document/test_graphics.rb +0 -42
  177. data/test/unit/generator/pdf/document/test_page.rb +0 -122
  178. data/test/unit/generator/pdf/document/test_parse_color.rb +0 -30
  179. data/test/unit/generator/pdf/prawn_ext/test_calc_image_dimensions.rb +0 -41
  180. data/test/unit/generator/pdf/prawn_ext/test_width_of.rb +0 -22
  181. data/test/unit/generator/pdf/test_document.rb +0 -22
  182. data/test/unit/generator/test_pdf.rb +0 -26
  183. data/test/unit/layout/test_base.rb +0 -41
  184. data/test/unit/layout/test_format.rb +0 -100
  185. data/test/unit/layout/test_legacy_schema.rb +0 -574
  186. data/test/unit/layout/test_version.rb +0 -26
  187. data/test/unit/report/test_base.rb +0 -248
  188. data/test/unit/report/test_internal.rb +0 -206
  189. data/test/unit/test_config.rb +0 -36
  190. data/test/unit/test_layout.rb +0 -12
  191. data/test/unit/test_report.rb +0 -18
@@ -23,7 +23,6 @@ module Thinreports
23
23
  # @yield [attrs]
24
24
  # @yieldparam [Hash] attrs
25
25
  # @return [Hash]
26
- # rubocop:disable Metrics/AbcSize
27
26
  def build_text_attributes(style, &block)
28
27
  text_attributes = {
29
28
  font: font_family(style['font-family']),
@@ -65,7 +65,6 @@ module Thinreports
65
65
  end
66
66
 
67
67
  # @param [Hash] attrs
68
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
69
68
  def with_graphic_styles(attrs, &block)
70
69
  stroke = build_stroke_styles(attrs)
71
70
  fill = build_fill_styles(attrs)
@@ -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)
@@ -22,7 +22,7 @@ module Thinreports
22
22
  # @option attrs [Boolean] :single (false)
23
23
  # @option attrs [:trancate, :shrink_to_fit, :expand] :overflow (:trancate)
24
24
  # @option attrs [:none, :break_word] :word_wrap (:none)
25
- def text_box(content, x, y, w, h, attrs = {})
25
+ def text_box(content, x, y, w, h, attrs = {}, &block)
26
26
  w, h = s2f(w, h)
27
27
 
28
28
  box_attrs = text_box_attrs(
@@ -35,12 +35,16 @@ module Thinreports
35
35
  content = text_without_line_wrap(content) if attrs[:word_wrap] == :none
36
36
 
37
37
  with_text_styles(attrs) do |built_attrs, font_styles|
38
- pdf.formatted_text_box(
39
- [{ text: content, styles: font_styles }],
40
- built_attrs.merge(box_attrs)
41
- )
38
+ if block
39
+ block.call [{ text: content, styles: font_styles }],
40
+ built_attrs.merge(box_attrs)
41
+ else
42
+ pdf.formatted_text_box(
43
+ [{ text: content, styles: font_styles }],
44
+ built_attrs.merge(box_attrs)
45
+ )
46
+ end
42
47
  end
43
- # rubocop:disable Lint/HandleExceptions
44
48
  rescue Prawn::Errors::CannotFit
45
49
  # Nothing to do.
46
50
  #
@@ -81,7 +85,6 @@ module Thinreports
81
85
  # @yield [built_attrs, font_styles]
82
86
  # @yieldparam [Hash] built_attrs The finalized attributes.
83
87
  # @yieldparam [Array] font_styles The finalized styles.
84
- # rubocop:disable Metrics/AbcSize
85
88
  def with_text_styles(attrs, &block)
86
89
  # When no color is given, do not draw.
87
90
  return unless attrs.key?(:color) && attrs[:color] != 'none'
@@ -139,7 +142,6 @@ module Thinreports
139
142
  # @yield [attributes, styles]
140
143
  # @yieldparam [Hash] modified_attrs
141
144
  # @yieldparam [Array] styles
142
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
143
145
  def with_font_styles(attrs, font, &block)
144
146
  # Building font styles.
145
147
  styles = attrs.delete(:styles)
@@ -10,16 +10,13 @@ module Thinreports
10
10
  }.freeze
11
11
 
12
12
  # @param [Thinreports::Layout::Format] format
13
- # rubocop:disable Metrics/AbcSize
14
13
  def start_new_page(format)
15
14
  format_id =
16
15
  if change_page_format?(format)
17
16
  pdf.start_new_page(new_basic_page_options(format))
18
17
  @current_page_format = format
19
18
 
20
- unless format_stamp_registry.include?(format.identifier)
21
- create_format_stamp(format)
22
- end
19
+ create_format_stamp(format) unless format_stamp_registry.include?(format.identifier)
23
20
  format.identifier
24
21
  else
25
22
  pdf.start_new_page(new_basic_page_options(current_page_format))
@@ -29,6 +26,18 @@ module Thinreports
29
26
  stamp(format_id.to_s)
30
27
  end
31
28
 
29
+ def start_new_page_for_section_report(format)
30
+ @current_page_format = format
31
+ pdf.start_new_page(new_basic_page_options(current_page_format).merge(
32
+ top_margin: current_page_format.page_margin[0],
33
+ bottom_margin: current_page_format.page_margin[2]
34
+ ))
35
+ end
36
+
37
+ def max_content_height
38
+ pdf.margin_box.height
39
+ end
40
+
32
41
  def add_blank_page
33
42
  pdf.start_new_page(pdf.page_count.zero? ? { size: 'A4' } : {})
34
43
  end
@@ -12,7 +12,6 @@ module Thinreports
12
12
  end
13
13
 
14
14
  # @param [Thinreports::Core::Shape::List::PageState] list_page
15
- # rubocop:disable Metrics/AbcSize
16
15
  def draw(list_page)
17
16
  draw_section(list_page.header) if list_page.header
18
17
  list_page.rows.each do |row|
@@ -20,9 +20,7 @@ module Thinreports
20
20
 
21
21
  box_width, box_height = options.delete(:auto_fit)
22
22
 
23
- if image_width > box_width || image_height > box_height
24
- options[:fit] = [box_width, box_height]
25
- end
23
+ options[:fit] = [box_width, box_height] if image_width > box_width || image_height > box_height
26
24
  end
27
25
  super(options)
28
26
  end
@@ -4,16 +4,13 @@ module Thinreports
4
4
  module Generator
5
5
  module PrawnExt
6
6
  module WidthOf
7
- # Subtract the width of one character space from the string width calculation result.
7
+ # This patch fixes the character_spacing effect on text width calculation.
8
8
  #
9
- # The original Prawn::Document#width_of returns the following result:
10
- #
11
- # Width of Character is 1
12
- # Width of Character Space is 1
9
+ # The original #width_of:
13
10
  #
14
11
  # width_of('abcd') #=> 4 + 4 = 8
15
12
  #
16
- # In this width_of, returns the following result:
13
+ # The #width_of in this patch:
17
14
  #
18
15
  # width_of('abcd') #=> 4 + 3 = 7
19
16
  #
@@ -26,4 +23,7 @@ module Thinreports
26
23
  end
27
24
  end
28
25
 
29
- Prawn::Document.prepend Thinreports::Generator::PrawnExt::WidthOf
26
+ # Prawn v2.3 and later includes this patch by https://github.com/prawnpdf/prawn/pull/1117.
27
+ if Prawn::VERSION < '2.3.0'
28
+ Prawn::Document.prepend Thinreports::Generator::PrawnExt::WidthOf
29
+ end
@@ -3,7 +3,7 @@
3
3
  module Thinreports
4
4
  module Layout
5
5
  class Base
6
- EXT_NAME = 'tlf'.freeze
6
+ EXT_NAME = 'tlf'
7
7
  include Utils
8
8
 
9
9
  class << self
@@ -14,9 +14,7 @@ module Thinreports
14
14
  def load_format(filename)
15
15
  filename += ".#{EXT_NAME}" unless filename =~ /\.#{EXT_NAME}$/
16
16
 
17
- unless File.exist?(filename)
18
- raise Thinreports::Errors::LayoutFileNotFound
19
- end
17
+ raise Thinreports::Errors::LayoutFileNotFound unless File.exist?(filename)
20
18
  # Build format.
21
19
  Thinreports::Layout::Format.build(filename)
22
20
  end
@@ -13,7 +13,6 @@ module Thinreports
13
13
  page_orientation: %w[report orientation]
14
14
 
15
15
  class << self
16
- # rubocop:disable Metrics/AbcSize
17
16
  def build(filename)
18
17
  schema = JSON.parse(read_file(filename))
19
18
  schema_version = Layout::Version.new(schema['version'])
@@ -5,7 +5,6 @@ require 'rexml/document'
5
5
 
6
6
  module Thinreports
7
7
  module Layout
8
- # rubocop:disable Metrics/ClassLength
9
8
  class LegacySchema
10
9
  include Utils
11
10
 
@@ -17,7 +16,6 @@ module Thinreports
17
16
  @legacy_svg = cleanup_svg(@legacy_svg)
18
17
  end
19
18
 
20
- # rubocop:disable Metrics/AbcSize
21
19
  def upgrade
22
20
  config = legacy_schema['config']
23
21
  page_config = config['page']
@@ -48,7 +46,6 @@ module Thinreports
48
46
  build_item_schemas_from_svg(svg.elements['/svg/g'])
49
47
  end
50
48
 
51
- # rubocop:disable Metrics/CyclomaticComplexity
52
49
  def build_item_schemas_from_svg(svg_elements)
53
50
  return [] unless svg_elements
54
51
 
@@ -107,6 +104,7 @@ module Thinreports
107
104
  'width' => attributes['width'].to_f,
108
105
  'height' => attributes['height'].to_f,
109
106
  'display' => display(attributes['x-display']),
107
+ 'border-radius' => attributes['rx'].to_i,
110
108
  'style' => {
111
109
  'border-width' => attributes['stroke-width'].to_f,
112
110
  'border-color' => attributes['stroke'],
@@ -277,9 +275,7 @@ module Thinreports
277
275
  'footer' => footer
278
276
  }
279
277
 
280
- if page_footer['enabled']
281
- page_footer['translate']['y'] += detail['height']
282
- end
278
+ page_footer['translate']['y'] += detail['height'] if page_footer['enabled']
283
279
 
284
280
  if footer['enabled']
285
281
  footer['translate']['y'] += detail['height']
@@ -4,7 +4,7 @@ module Thinreports
4
4
  module Layout
5
5
  class Version
6
6
  COMPATIBLE_RULES = ['>= 0.8.0', '< 1.0.0'].freeze
7
- NEW_SCHEMA_FROM = '0.9.0'.freeze
7
+ NEW_SCHEMA_FROM = '0.9.0'
8
8
 
9
9
  class << self
10
10
  def compatible_rules
@@ -33,9 +33,7 @@ module Thinreports
33
33
  else
34
34
  id = options[:id].to_sym
35
35
 
36
- if layout_registry.key?(id)
37
- raise ArgumentError, "Id :#{id} is already in use."
38
- end
36
+ raise ArgumentError, "Id :#{id} is already in use." if layout_registry.key?(id)
39
37
  layout_registry[id] = init_layout(layout, id)
40
38
  end
41
39
  end
@@ -74,7 +72,7 @@ module Thinreports
74
72
  raise ArgumentError, 'Invalid argument for layout.'
75
73
  end
76
74
 
77
- @default_layout = layout unless @default_layout
75
+ @default_layout ||= layout
78
76
  layout
79
77
  end
80
78
 
@@ -98,6 +96,8 @@ module Thinreports
98
96
  end
99
97
 
100
98
  def init_layout(filename, id = nil)
99
+ filename = filename.to_path if filename.is_a?(Pathname)
100
+
101
101
  Thinreports::Layout.new(filename, id: id)
102
102
  end
103
103
  end
@@ -64,7 +64,6 @@ module Thinreports
64
64
  false
65
65
  end
66
66
 
67
- # rubocop:disable Metrics/AbcSize
68
67
  def copy
69
68
  new_page = self.class.new(report, layout, count: count?)
70
69
 
@@ -72,9 +71,7 @@ module Thinreports
72
71
  new_shape = shape.copy(new_page)
73
72
  new_page.manager.shapes[id] = new_shape
74
73
 
75
- if new_shape.internal.type_of?(Core::Shape::List::TYPE_NAME)
76
- new_page.manager.lists[id] = new_shape
77
- end
74
+ new_page.manager.lists[id] = new_shape if new_shape.internal.type_of?(Core::Shape::List::TYPE_NAME)
78
75
  end
79
76
  new_page
80
77
  end
@@ -85,9 +82,7 @@ module Thinreports
85
82
  at = options[:at] || :create
86
83
 
87
84
  # For list shapes.
88
- if at == :create
89
- manager.lists.values.each { |list| list.manager.finalize }
90
- end
85
+ manager.lists.each_value { |list| list.manager.finalize } if at == :create
91
86
 
92
87
  @finalized = true
93
88
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'schema/loader'
4
+ require_relative 'builder/report_builder'
5
+
6
+ module Thinreports
7
+ module SectionReport
8
+ class Build
9
+ def call(report_params)
10
+ schema = load_schema(report_params)
11
+ params = report_params[:params] || {}
12
+
13
+ Builder::ReportBuilder.new(schema).build(params)
14
+ end
15
+
16
+ private
17
+
18
+ def load_schema(report_params)
19
+ loader = Schema::Loader.new
20
+
21
+ case
22
+ when report_params[:layout_file]
23
+ loader.load_from_file(report_params[:layout_file])
24
+ when report_params[:layout_data]
25
+ loader.load_from_data(report_params[:layout_data])
26
+ else
27
+ raise Errors::LayoutFileNotFound
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'stack_view_builder'
4
+
5
+ module Thinreports
6
+ module SectionReport
7
+ module Builder
8
+ class ItemBuilder
9
+ Context = Struct.new(:parent_schema)
10
+
11
+ def initialize(item_schema, parent_schema)
12
+ @item = Core::Shape::Interface(nil, item_schema)
13
+ @parent_schema = parent_schema
14
+ end
15
+
16
+ def build(item_params)
17
+ params = build_params(item_params)
18
+
19
+ item.visible(params[:display]) if params.key?(:display)
20
+ item.value(params[:value]) if params.key?(:value)
21
+ item.styles(params[:styles]) if params.key?(:styles)
22
+
23
+ if item.internal.format.attributes['type'] == Core::Shape::StackView::TYPE_NAME
24
+ StackViewBuilder.new(item).update(params)
25
+ end
26
+
27
+ item
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :item, :parent_schema
33
+
34
+ def build_params(params)
35
+ return {} unless params
36
+
37
+ case params
38
+ when Hash
39
+ params
40
+ when Proc
41
+ params.call(Context.new(parent_schema))
42
+ else
43
+ { value: params }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'report_data'
4
+ require_relative 'item_builder'
5
+
6
+ module Thinreports
7
+ module SectionReport
8
+ module Builder
9
+ class ReportBuilder
10
+ def initialize(schema)
11
+ @schema = schema
12
+ end
13
+
14
+ def build(params)
15
+ ReportData::Main.new(
16
+ schema,
17
+ build_groups(params[:groups])
18
+ )
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :schema
24
+
25
+ def build_groups(groups_params)
26
+ return [] unless groups_params
27
+
28
+ groups_params.map do |group_params|
29
+ ReportData::Group.new(
30
+ build_sections(:header, group_params[:headers] || {}),
31
+ build_detail_sections(group_params[:details] || []),
32
+ build_sections(:footer, group_params[:footers] || {})
33
+ )
34
+ end
35
+ end
36
+
37
+ def build_sections(section_type, sections_params)
38
+ sections_schemas =
39
+ case section_type
40
+ when :header then schema.headers
41
+ when :footer then schema.footers
42
+ end
43
+
44
+ sections_schemas.each_with_object([]) do |(section_id, section_schema), sections|
45
+ section_params = sections_params[section_id.to_sym] || {}
46
+ next unless section_enabled?(section_schema, section_params)
47
+
48
+ items = build_items(section_schema, section_params[:items] || {})
49
+ sections << ReportData::Section.new(section_schema, items, section_params[:min_height])
50
+ end
51
+ end
52
+
53
+ def build_detail_sections(details_params)
54
+ details_params.each_with_object([]) do |detail_params, details|
55
+ detail_id = detail_params[:id].to_sym
56
+ detail_schema = schema.details[detail_id]
57
+
58
+ next unless detail_schema
59
+
60
+ items = build_items(detail_schema, detail_params[:items] || {})
61
+ details << ReportData::Section.new(detail_schema, items, detail_params[:min_height])
62
+ end
63
+ end
64
+
65
+ def build_items(section_schema, items_params)
66
+ section_schema.items.each_with_object([]) do |item_schema, items|
67
+ item = ItemBuilder.new(item_schema, section_schema).build(items_params[item_schema.id&.to_sym])
68
+ items << item if item.visible?
69
+ end
70
+ end
71
+
72
+ def section_enabled?(section_schema, section_params)
73
+ if section_params.key?(:display)
74
+ section_params[:display]
75
+ else
76
+ section_schema.display?
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end