thinreports 0.12.1 → 0.13.1

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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +3 -3
  3. data/.github/workflows/test.yml +28 -36
  4. data/.gitignore +1 -1
  5. data/CHANGELOG.md +25 -1
  6. data/Gemfile +11 -0
  7. data/README.md +12 -17
  8. data/Rakefile +17 -11
  9. data/lib/thinreports/basic_report/core/errors.rb +62 -0
  10. data/lib/thinreports/basic_report/core/format/base.rb +91 -0
  11. data/lib/thinreports/basic_report/core/shape/base/interface.rb +42 -0
  12. data/lib/thinreports/basic_report/core/shape/base/internal.rb +53 -0
  13. data/lib/thinreports/basic_report/core/shape/basic/block_format.rb +15 -0
  14. data/lib/thinreports/basic_report/core/shape/basic/block_interface.rb +34 -0
  15. data/lib/thinreports/basic_report/core/shape/basic/block_internal.rb +36 -0
  16. data/lib/thinreports/basic_report/core/shape/basic/format.rb +24 -0
  17. data/lib/thinreports/basic_report/core/shape/basic/interface.rb +87 -0
  18. data/lib/thinreports/basic_report/core/shape/basic/internal.rb +28 -0
  19. data/lib/thinreports/{core → basic_report/core}/shape/basic.rb +6 -4
  20. data/lib/thinreports/basic_report/core/shape/image_block/format.rb +14 -0
  21. data/lib/thinreports/basic_report/core/shape/image_block/interface.rb +25 -0
  22. data/lib/thinreports/basic_report/core/shape/image_block/internal.rb +19 -0
  23. data/lib/thinreports/{core → basic_report/core}/shape/image_block.rb +6 -4
  24. data/lib/thinreports/basic_report/core/shape/list/format.rb +92 -0
  25. data/lib/thinreports/basic_report/core/shape/list/manager.rb +231 -0
  26. data/lib/thinreports/basic_report/core/shape/list/page.rb +112 -0
  27. data/lib/thinreports/basic_report/core/shape/list/page_state.rb +50 -0
  28. data/lib/thinreports/basic_report/core/shape/list/section_format.rb +37 -0
  29. data/lib/thinreports/basic_report/core/shape/list/section_interface.rb +51 -0
  30. data/lib/thinreports/basic_report/core/shape/list/section_internal.rb +33 -0
  31. data/lib/thinreports/{core → basic_report/core}/shape/list.rb +6 -4
  32. data/lib/thinreports/basic_report/core/shape/manager/format.rb +33 -0
  33. data/lib/thinreports/basic_report/core/shape/manager/internal.rb +109 -0
  34. data/lib/thinreports/basic_report/core/shape/manager/target.rb +114 -0
  35. data/lib/thinreports/basic_report/core/shape/page_number/format.rb +32 -0
  36. data/lib/thinreports/basic_report/core/shape/page_number/interface.rb +31 -0
  37. data/lib/thinreports/basic_report/core/shape/page_number/internal.rb +57 -0
  38. data/lib/thinreports/{core → basic_report/core}/shape/page_number.rb +6 -4
  39. data/lib/thinreports/basic_report/core/shape/stack_view/format.rb +29 -0
  40. data/lib/thinreports/basic_report/core/shape/stack_view/interface.rb +19 -0
  41. data/lib/thinreports/basic_report/core/shape/stack_view/internal.rb +24 -0
  42. data/lib/thinreports/basic_report/core/shape/stack_view/row_format.rb +41 -0
  43. data/lib/thinreports/{core → basic_report/core}/shape/stack_view.rb +6 -4
  44. data/lib/thinreports/basic_report/core/shape/style/base.rb +149 -0
  45. data/lib/thinreports/basic_report/core/shape/style/basic.rb +24 -0
  46. data/lib/thinreports/basic_report/core/shape/style/graphic.rb +43 -0
  47. data/lib/thinreports/basic_report/core/shape/style/text.rb +122 -0
  48. data/lib/thinreports/basic_report/core/shape/text/format.rb +17 -0
  49. data/lib/thinreports/basic_report/core/shape/text/interface.rb +20 -0
  50. data/lib/thinreports/basic_report/core/shape/text/internal.rb +24 -0
  51. data/lib/thinreports/{core → basic_report/core}/shape/text.rb +6 -4
  52. data/lib/thinreports/basic_report/core/shape/text_block/format.rb +43 -0
  53. data/lib/thinreports/basic_report/core/shape/text_block/formatter/basic.rb +41 -0
  54. data/lib/thinreports/basic_report/core/shape/text_block/formatter/datetime.rb +25 -0
  55. data/lib/thinreports/basic_report/core/shape/text_block/formatter/number.rb +69 -0
  56. data/lib/thinreports/basic_report/core/shape/text_block/formatter/padding.rb +27 -0
  57. data/lib/thinreports/basic_report/core/shape/text_block/formatter.rb +38 -0
  58. data/lib/thinreports/basic_report/core/shape/text_block/interface.rb +37 -0
  59. data/lib/thinreports/basic_report/core/shape/text_block/internal.rb +75 -0
  60. data/lib/thinreports/{core → basic_report/core}/shape/text_block.rb +6 -4
  61. data/lib/thinreports/basic_report/core/shape.rb +44 -0
  62. data/lib/thinreports/basic_report/core/utils.rb +47 -0
  63. data/lib/thinreports/basic_report/generator/pdf/document/draw_shape.rb +108 -0
  64. data/lib/thinreports/basic_report/generator/pdf/document/draw_template_items.rb +71 -0
  65. data/lib/thinreports/basic_report/generator/pdf/document/font.rb +90 -0
  66. data/lib/thinreports/basic_report/generator/pdf/document/graphics/attributes.rb +149 -0
  67. data/lib/thinreports/basic_report/generator/pdf/document/graphics/basic.rb +137 -0
  68. data/lib/thinreports/basic_report/generator/pdf/document/graphics/image.rb +99 -0
  69. data/lib/thinreports/basic_report/generator/pdf/document/graphics/text.rb +180 -0
  70. data/lib/thinreports/basic_report/generator/pdf/document/graphics.rb +42 -0
  71. data/lib/thinreports/basic_report/generator/pdf/document/page.rb +96 -0
  72. data/lib/thinreports/basic_report/generator/pdf/document/parse_color.rb +51 -0
  73. data/lib/thinreports/basic_report/generator/pdf/document.rb +132 -0
  74. data/lib/thinreports/basic_report/generator/pdf/drawer/base.rb +50 -0
  75. data/lib/thinreports/basic_report/generator/pdf/drawer/list.rb +65 -0
  76. data/lib/thinreports/basic_report/generator/pdf/drawer/list_section.rb +51 -0
  77. data/lib/thinreports/basic_report/generator/pdf/drawer/page.rb +127 -0
  78. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/calc_image_dimensions.rb +34 -0
  79. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/width_of.rb +31 -0
  80. data/lib/thinreports/basic_report/generator/pdf.rb +66 -0
  81. data/lib/thinreports/basic_report/layout/base.rb +48 -0
  82. data/lib/thinreports/basic_report/layout/format.rb +67 -0
  83. data/lib/thinreports/basic_report/layout/legacy_schema.rb +383 -0
  84. data/lib/thinreports/basic_report/layout/version.rb +41 -0
  85. data/lib/thinreports/{layout.rb → basic_report/layout.rb} +6 -4
  86. data/lib/thinreports/basic_report/report/base.rb +174 -0
  87. data/lib/thinreports/basic_report/report/internal.rb +107 -0
  88. data/lib/thinreports/basic_report/report/page.rb +97 -0
  89. data/lib/thinreports/basic_report/report.rb +26 -0
  90. data/lib/thinreports/basic_report.rb +15 -0
  91. data/lib/thinreports/config.rb +1 -1
  92. data/lib/thinreports/section_report.rb +12 -0
  93. data/lib/thinreports/version.rb +1 -1
  94. data/lib/thinreports.rb +2 -13
  95. data/thinreports.gemspec +3 -7
  96. metadata +97 -154
  97. data/gemfiles/prawn-2.2.gemfile +0 -5
  98. data/gemfiles/prawn-2.3.gemfile +0 -5
  99. data/gemfiles/prawn-2.4.gemfile +0 -5
  100. data/lib/thinreports/core/errors.rb +0 -60
  101. data/lib/thinreports/core/format/base.rb +0 -89
  102. data/lib/thinreports/core/shape/base/interface.rb +0 -40
  103. data/lib/thinreports/core/shape/base/internal.rb +0 -51
  104. data/lib/thinreports/core/shape/basic/block_format.rb +0 -13
  105. data/lib/thinreports/core/shape/basic/block_interface.rb +0 -32
  106. data/lib/thinreports/core/shape/basic/block_internal.rb +0 -34
  107. data/lib/thinreports/core/shape/basic/format.rb +0 -22
  108. data/lib/thinreports/core/shape/basic/interface.rb +0 -85
  109. data/lib/thinreports/core/shape/basic/internal.rb +0 -26
  110. data/lib/thinreports/core/shape/image_block/format.rb +0 -12
  111. data/lib/thinreports/core/shape/image_block/interface.rb +0 -23
  112. data/lib/thinreports/core/shape/image_block/internal.rb +0 -17
  113. data/lib/thinreports/core/shape/list/format.rb +0 -90
  114. data/lib/thinreports/core/shape/list/manager.rb +0 -229
  115. data/lib/thinreports/core/shape/list/page.rb +0 -110
  116. data/lib/thinreports/core/shape/list/page_state.rb +0 -48
  117. data/lib/thinreports/core/shape/list/section_format.rb +0 -35
  118. data/lib/thinreports/core/shape/list/section_interface.rb +0 -49
  119. data/lib/thinreports/core/shape/list/section_internal.rb +0 -31
  120. data/lib/thinreports/core/shape/manager/format.rb +0 -31
  121. data/lib/thinreports/core/shape/manager/internal.rb +0 -107
  122. data/lib/thinreports/core/shape/manager/target.rb +0 -112
  123. data/lib/thinreports/core/shape/page_number/format.rb +0 -30
  124. data/lib/thinreports/core/shape/page_number/interface.rb +0 -29
  125. data/lib/thinreports/core/shape/page_number/internal.rb +0 -55
  126. data/lib/thinreports/core/shape/stack_view/format.rb +0 -27
  127. data/lib/thinreports/core/shape/stack_view/interface.rb +0 -17
  128. data/lib/thinreports/core/shape/stack_view/internal.rb +0 -22
  129. data/lib/thinreports/core/shape/stack_view/row_format.rb +0 -39
  130. data/lib/thinreports/core/shape/style/base.rb +0 -146
  131. data/lib/thinreports/core/shape/style/basic.rb +0 -22
  132. data/lib/thinreports/core/shape/style/graphic.rb +0 -41
  133. data/lib/thinreports/core/shape/style/text.rb +0 -120
  134. data/lib/thinreports/core/shape/text/format.rb +0 -15
  135. data/lib/thinreports/core/shape/text/interface.rb +0 -18
  136. data/lib/thinreports/core/shape/text/internal.rb +0 -22
  137. data/lib/thinreports/core/shape/text_block/format.rb +0 -41
  138. data/lib/thinreports/core/shape/text_block/formatter/basic.rb +0 -39
  139. data/lib/thinreports/core/shape/text_block/formatter/datetime.rb +0 -23
  140. data/lib/thinreports/core/shape/text_block/formatter/number.rb +0 -67
  141. data/lib/thinreports/core/shape/text_block/formatter/padding.rb +0 -25
  142. data/lib/thinreports/core/shape/text_block/formatter.rb +0 -34
  143. data/lib/thinreports/core/shape/text_block/interface.rb +0 -35
  144. data/lib/thinreports/core/shape/text_block/internal.rb +0 -73
  145. data/lib/thinreports/core/shape.rb +0 -42
  146. data/lib/thinreports/core/utils.rb +0 -45
  147. data/lib/thinreports/generate.rb +0 -11
  148. data/lib/thinreports/generator/pdf/document/draw_shape.rb +0 -106
  149. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +0 -69
  150. data/lib/thinreports/generator/pdf/document/font.rb +0 -88
  151. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +0 -147
  152. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +0 -135
  153. data/lib/thinreports/generator/pdf/document/graphics/image.rb +0 -98
  154. data/lib/thinreports/generator/pdf/document/graphics/text.rb +0 -178
  155. data/lib/thinreports/generator/pdf/document/graphics.rb +0 -40
  156. data/lib/thinreports/generator/pdf/document/page.rb +0 -94
  157. data/lib/thinreports/generator/pdf/document/parse_color.rb +0 -49
  158. data/lib/thinreports/generator/pdf/document.rb +0 -130
  159. data/lib/thinreports/generator/pdf/drawer/base.rb +0 -48
  160. data/lib/thinreports/generator/pdf/drawer/list.rb +0 -63
  161. data/lib/thinreports/generator/pdf/drawer/list_section.rb +0 -49
  162. data/lib/thinreports/generator/pdf/drawer/page.rb +0 -125
  163. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +0 -32
  164. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +0 -29
  165. data/lib/thinreports/generator/pdf.rb +0 -63
  166. data/lib/thinreports/layout/base.rb +0 -46
  167. data/lib/thinreports/layout/format.rb +0 -65
  168. data/lib/thinreports/layout/legacy_schema.rb +0 -381
  169. data/lib/thinreports/layout/version.rb +0 -39
  170. data/lib/thinreports/report/base.rb +0 -169
  171. data/lib/thinreports/report/internal.rb +0 -105
  172. data/lib/thinreports/report/page.rb +0 -95
  173. data/lib/thinreports/report.rb +0 -24
  174. /data/lib/thinreports/{core → basic_report/core}/shape/base.rb +0 -0
  175. /data/lib/thinreports/{core → basic_report/core}/shape/manager.rb +0 -0
  176. /data/lib/thinreports/{core → basic_report/core}/shape/style.rb +0 -0
  177. /data/lib/thinreports/{generator → basic_report/generator}/pdf/prawn_ext.rb +0 -0
@@ -0,0 +1,383 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'rexml/document'
5
+
6
+ module Thinreports
7
+ module BasicReport
8
+ module Layout
9
+ class LegacySchema
10
+ include Utils
11
+
12
+ def initialize(legacy_schema)
13
+ @legacy_schema = legacy_schema
14
+ @legacy_svg = legacy_schema['svg'].dup
15
+ @legacy_item_schemas = extract_legacy_item_schemas(legacy_svg)
16
+
17
+ @legacy_svg = cleanup_svg(@legacy_svg)
18
+ end
19
+
20
+ def upgrade
21
+ config = legacy_schema['config']
22
+ page_config = config['page']
23
+
24
+ {
25
+ 'version' => legacy_schema['version'],
26
+ 'title' => legacy_schema['config']['title'],
27
+ 'report' => {
28
+ 'paper-type' => page_config['paper-type'],
29
+ 'width' => page_config['width'].to_f,
30
+ 'height' => page_config['height'].to_f,
31
+ 'orientation' => page_config['orientation'],
32
+ 'margin' => page_config.values_at(
33
+ 'margin-top',
34
+ 'margin-right',
35
+ 'margin-bottom',
36
+ 'margin-left'
37
+ ).map(&:to_f)
38
+ },
39
+ 'items' => item_schemas
40
+ }
41
+ end
42
+
43
+ attr_reader :legacy_schema, :legacy_svg, :legacy_item_schemas
44
+
45
+ def item_schemas
46
+ svg = REXML::Document.new(legacy_svg)
47
+ build_item_schemas_from_svg(svg.elements['/svg/g'])
48
+ end
49
+
50
+ def build_item_schemas_from_svg(svg_elements)
51
+ return [] unless svg_elements
52
+
53
+ items = []
54
+
55
+ svg_elements.each do |item_element|
56
+ item_attributes = item_element.attributes
57
+
58
+ items <<
59
+ case item_element.attributes['class']
60
+ when 's-text' then text_item_schema(item_attributes, extract_texts_from(item_element))
61
+ when 's-image' then image_item_schema(item_attributes)
62
+ when 's-rect' then rect_item_schema(item_attributes)
63
+ when 's-ellipse' then ellipse_item_schema(item_attributes)
64
+ when 's-line' then line_item_schema(item_attributes)
65
+ when 's-tblock' then text_block_item_schema(item_attributes)
66
+ when 's-iblock' then image_block_item_schema(item_attributes)
67
+ when 's-pageno' then page_number_item_schema(item_attributes)
68
+ when 's-list' then list_item_schema(item_element)
69
+ else raise 'Unknown item type'
70
+ end
71
+ end
72
+
73
+ items
74
+ end
75
+
76
+ def text_item_schema(attributes, texts)
77
+ {
78
+ 'id' => attributes['x-id'],
79
+ 'type' => Core::Shape::Text::TYPE_NAME,
80
+ 'x' => attributes['x-left'].to_f,
81
+ 'y' => attributes['x-top'].to_f,
82
+ 'width' => attributes['x-width'].to_f,
83
+ 'height' => attributes['x-height'].to_f,
84
+ 'display' => display(attributes['x-display']),
85
+ 'texts' => texts,
86
+ 'style' => {
87
+ 'font-family' => [attributes['font-family']],
88
+ 'font-size' => attributes['font-size'].to_f,
89
+ 'color' => attributes['fill'],
90
+ 'font-style' => font_style(attributes),
91
+ 'text-align' => text_align(attributes['text-anchor']),
92
+ 'vertical-align' => vertical_align(attributes['x-valign']),
93
+ 'line-height' => line_height(attributes['x-line-height']),
94
+ 'letter-spacing' => letter_spacing(attributes['kerning'])
95
+ }
96
+ }
97
+ end
98
+
99
+ def rect_item_schema(attributes)
100
+ {
101
+ 'id' => attributes['x-id'],
102
+ 'type' => 'rect',
103
+ 'x' => attributes['x'].to_f,
104
+ 'y' => attributes['y'].to_f,
105
+ 'width' => attributes['width'].to_f,
106
+ 'height' => attributes['height'].to_f,
107
+ 'display' => display(attributes['x-display']),
108
+ 'border-radius' => attributes['rx'].to_i,
109
+ 'style' => {
110
+ 'border-width' => attributes['stroke-width'].to_f,
111
+ 'border-color' => attributes['stroke'],
112
+ 'border-style' => attributes['x-stroke-type'],
113
+ 'fill-color' => attributes['fill']
114
+ }
115
+ }
116
+ end
117
+
118
+ def line_item_schema(attributes)
119
+ {
120
+ 'id' => attributes['x-id'],
121
+ 'type' => 'line',
122
+ 'x1' => attributes['x1'].to_f,
123
+ 'y1' => attributes['y1'].to_f,
124
+ 'x2' => attributes['x2'].to_f,
125
+ 'y2' => attributes['y2'].to_f,
126
+ 'display' => display(attributes['x-display']),
127
+ 'style' => {
128
+ 'border-width' => attributes['stroke-width'].to_f,
129
+ 'border-color' => attributes['stroke'],
130
+ 'border-style' => attributes['x-stroke-type']
131
+ }
132
+ }
133
+ end
134
+
135
+ def ellipse_item_schema(attributes)
136
+ {
137
+ 'id' => attributes['x-id'],
138
+ 'type' => 'ellipse',
139
+ 'cx' => attributes['cx'].to_f,
140
+ 'cy' => attributes['cy'].to_f,
141
+ 'rx' => attributes['rx'].to_f,
142
+ 'ry' => attributes['ry'].to_f,
143
+ 'display' => display(attributes['x-display']),
144
+ 'style' => {
145
+ 'border-width' => attributes['stroke-width'].to_f,
146
+ 'border-color' => attributes['stroke'],
147
+ 'border-style' => attributes['x-stroke-type'],
148
+ 'fill-color' => attributes['fill']
149
+ }
150
+ }
151
+ end
152
+
153
+ def image_item_schema(attributes)
154
+ _, image_type, image_data = attributes['xlink:href'].match(%r{^data:(image/[a-z]+?);base64,(.+)}).to_a
155
+
156
+ {
157
+ 'id' => attributes['x-id'],
158
+ 'type' => 'image',
159
+ 'x' => attributes['x'].to_f,
160
+ 'y' => attributes['y'].to_f,
161
+ 'width' => attributes['width'].to_f,
162
+ 'height' => attributes['height'].to_f,
163
+ 'display' => display(attributes['x-display']),
164
+ 'data' => {
165
+ 'mime-type' => image_type,
166
+ 'base64' => image_data
167
+ }
168
+ }
169
+ end
170
+
171
+ def page_number_item_schema(attributes)
172
+ {
173
+ 'id' => attributes['x-id'],
174
+ 'type' => Core::Shape::PageNumber::TYPE_NAME,
175
+ 'x' => attributes['x-left'].to_f,
176
+ 'y' => attributes['x-top'].to_f,
177
+ 'width' => attributes['x-width'].to_f,
178
+ 'height' => attributes['x-height'].to_f,
179
+ 'format' => attributes['x-format'],
180
+ 'target' => attributes['x-target'],
181
+ 'display' => display(attributes['x-display']),
182
+ 'style' => {
183
+ 'font-family' => [attributes['font-family']],
184
+ 'font-size' => attributes['font-size'].to_f,
185
+ 'color' => attributes['fill'],
186
+ 'font-style' => font_style(attributes),
187
+ 'text-align' => text_align(attributes['text-anchor']),
188
+ 'overflow' => attributes['x-overflow']
189
+ }
190
+ }
191
+ end
192
+
193
+ def image_block_item_schema(attributes)
194
+ {
195
+ 'id' => attributes['x-id'],
196
+ 'type' => Core::Shape::ImageBlock::TYPE_NAME,
197
+ 'x' => attributes['x-left'].to_f,
198
+ 'y' => attributes['x-top'].to_f,
199
+ 'width' => attributes['x-width'].to_f,
200
+ 'height' => attributes['x-height'].to_f,
201
+ 'display' => display(attributes['x-display']),
202
+ 'style' => {
203
+ 'position-x' => attributes['x-position-x'],
204
+ 'position-y' => image_position_y(attributes['x-position-y'])
205
+ }
206
+ }
207
+ end
208
+
209
+ def text_block_item_schema(attributes)
210
+ text_format = {
211
+ 'base' => attributes['x-format-base'],
212
+ 'type' => attributes['x-format-type']
213
+ }
214
+ case text_format['type']
215
+ when 'datetime'
216
+ text_format['datetime'] = {
217
+ 'format' => attributes['x-format-datetime-format']
218
+ }
219
+ when 'number'
220
+ text_format['number'] = {
221
+ 'delimiter' => attributes['x-format-number-delimiter'],
222
+ 'precision' => attributes['x-format-number-precision'].to_i
223
+ }
224
+ when 'padding'
225
+ text_format['padding'] = {
226
+ 'length' => attributes['x-format-padding-length'].to_i,
227
+ 'char' => attributes['x-format-padding-char'],
228
+ 'direction' => attributes['x-format-padding-direction']
229
+ }
230
+ end
231
+
232
+ {
233
+ 'id' => attributes['x-id'],
234
+ 'type' => Core::Shape::TextBlock::TYPE_NAME,
235
+ 'x' => attributes['x-left'].to_f,
236
+ 'y' => attributes['x-top'].to_f,
237
+ 'width' => attributes['x-width'].to_f,
238
+ 'height' => attributes['x-height'].to_f,
239
+ 'display' => display(attributes['x-display']),
240
+ 'value' => attributes['x-value'],
241
+ 'multiple-line' => attributes['x-multiple'] == 'true',
242
+ 'format' => text_format,
243
+ 'reference-id' => attributes['x-ref-id'],
244
+ 'style' => {
245
+ 'font-family' => [attributes['font-family']],
246
+ 'font-size' => attributes['font-size'].to_f,
247
+ 'color' => attributes['fill'],
248
+ 'font-style' => font_style(attributes),
249
+ 'text-align' => text_align(attributes['text-anchor']),
250
+ 'vertical-align' => vertical_align(attributes['x-valign']),
251
+ 'line-height' => line_height(attributes['x-line-height']),
252
+ 'letter-spacing' => letter_spacing(attributes['kerning']),
253
+ 'overflow' => attributes['x-overflow'],
254
+ 'word-wrap' => attributes['x-word-wrap'] || ''
255
+ }
256
+ }
257
+ end
258
+
259
+ def list_item_schema(legacy_element)
260
+ legacy_schema = legacy_item_schemas[legacy_element.attributes['x-id']]
261
+
262
+ header = list_section_schema('header', legacy_element, legacy_schema)
263
+ detail = list_section_schema('detail', legacy_element, legacy_schema)
264
+ page_footer = list_section_schema('page-footer', legacy_element, legacy_schema)
265
+ footer = list_section_schema('footer', legacy_element, legacy_schema)
266
+
267
+ schema = {
268
+ 'id' => legacy_schema['id'],
269
+ 'type' => Core::Shape::List::TYPE_NAME,
270
+ 'content-height' => legacy_schema['content-height'].to_f,
271
+ 'auto-page-break' => legacy_schema['page-break'] == 'true',
272
+ 'display' => display(legacy_schema['display']),
273
+ 'header' => header,
274
+ 'detail' => detail,
275
+ 'page-footer' => page_footer,
276
+ 'footer' => footer
277
+ }
278
+
279
+ page_footer['translate']['y'] += detail['height'] if page_footer['enabled']
280
+
281
+ if footer['enabled']
282
+ footer['translate']['y'] += detail['height']
283
+ footer['translate']['y'] += page_footer['height'] if page_footer['enabled']
284
+ end
285
+ schema
286
+ end
287
+
288
+ def list_section_schema(section_name, legacy_list_element, legacy_list_schema)
289
+ legacy_section_schema = legacy_list_schema[section_name]
290
+ return {} if legacy_section_schema.empty?
291
+
292
+ section_item_elements = legacy_list_element.elements["g[@class='s-list-#{section_name}']"]
293
+
294
+ section_schema = {
295
+ 'height' => legacy_section_schema['height'].to_f,
296
+ 'translate' => {
297
+ 'x' => legacy_section_schema['translate']['x'].to_f,
298
+ 'y' => legacy_section_schema['translate']['y'].to_f
299
+ },
300
+ 'items' => build_item_schemas_from_svg(section_item_elements)
301
+ }
302
+
303
+ unless section_name == 'detail'
304
+ section_schema['enabled'] = legacy_list_schema["#{section_name}-enabled"] == 'true'
305
+ end
306
+ section_schema
307
+ end
308
+
309
+ def extract_texts_from(text_item_element)
310
+ [].tap do |texts|
311
+ text_item_element.each_element('text') { |e| texts << e.text }
312
+ end
313
+ end
314
+
315
+ def image_position_y(legacy_position_y)
316
+ case legacy_position_y
317
+ when 'top' then 'top'
318
+ when 'center' then 'middle'
319
+ when 'bottom' then 'bottom'
320
+ end
321
+ end
322
+
323
+ def display(legacy_display)
324
+ legacy_display == 'true'
325
+ end
326
+
327
+ def font_style(attributes)
328
+ style = []
329
+ style << 'bold' if attributes['font-weight'] == 'bold'
330
+ style << 'italic' if attributes['font-style'] == 'italic'
331
+ style << 'underline' if attributes['text-decoration'].include?('underline')
332
+ style << 'linethrough' if attributes['text-decoration'].include?('line-through')
333
+ style
334
+ end
335
+
336
+ def text_align(legacy_text_align)
337
+ case legacy_text_align
338
+ when 'start' then 'left'
339
+ when 'middle' then 'center'
340
+ when 'end' then 'right'
341
+ else 'left'
342
+ end
343
+ end
344
+
345
+ def vertical_align(legacy_vertical_align)
346
+ return '' unless legacy_vertical_align
347
+
348
+ case legacy_vertical_align
349
+ when 'top' then 'top'
350
+ when 'center' then 'middle'
351
+ when 'bottom' then 'bottom'
352
+ else 'top'
353
+ end
354
+ end
355
+
356
+ def line_height(legacy_line_height)
357
+ blank_value?(legacy_line_height) ? '' : legacy_line_height.to_f
358
+ end
359
+
360
+ def letter_spacing(legacy_letter_spacing)
361
+ case legacy_letter_spacing
362
+ when 'auto', '' then ''
363
+ else legacy_letter_spacing.to_f
364
+ end
365
+ end
366
+
367
+ def extract_legacy_item_schemas(svg)
368
+ items = {}
369
+ svg.scan(/<!--SHAPE(.*?)SHAPE-->/) do |(item_schema_json)|
370
+ item_schema = JSON.parse(item_schema_json)
371
+ items[item_schema['id']] = item_schema
372
+ end
373
+ items
374
+ end
375
+
376
+ def cleanup_svg(svg)
377
+ cleaned_svg = svg.gsub(/<!--SHAPE.*?SHAPE-->/, '')
378
+ cleaned_svg.gsub(/<!--LAYOUT(.*?)LAYOUT-->/) { $1 }
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Layout
6
+ class Version
7
+ COMPATIBLE_RULES = ['>= 0.8.0', '< 1.0.0'].freeze
8
+ NEW_SCHEMA_FROM = '0.9.0'
9
+
10
+ class << self
11
+ def compatible_rules
12
+ COMPATIBLE_RULES
13
+ end
14
+ end
15
+
16
+ def initialize(schema_version)
17
+ @schema_version = normalize_version(schema_version)
18
+ end
19
+
20
+ def compatible?
21
+ self.class.compatible_rules.all? do |rule|
22
+ op, ver = rule.split(' ')
23
+ schema_version.send(op.to_sym, normalize_version(ver))
24
+ end
25
+ end
26
+
27
+ def legacy?
28
+ @schema_version < normalize_version(NEW_SCHEMA_FROM)
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :schema_version
34
+
35
+ def normalize_version(version)
36
+ Gem::Version.create(version)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Thinreports
4
- module Layout
5
- # @see Thinreports::Layout::Base#initialize
6
- def self.new(filename, options = {})
7
- Base.new(filename, options)
4
+ module BasicReport
5
+ module Layout
6
+ # @see Thinreports::BasicReport::Layout::Base#initialize
7
+ def self.new(filename, options = {})
8
+ Base.new(filename, options)
9
+ end
8
10
  end
9
11
  end
10
12
  end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Report
6
+ class Base
7
+ extend Forwardable
8
+ include Utils
9
+
10
+ class << self
11
+ # @param options (see #initialize)
12
+ # @option options (see #initialize)
13
+ # @yield [report]
14
+ # @yieldparam [Thinreports::BasicReport::Report::Base] report
15
+ # @return [Thinreports::BasicReport::Report::Base]
16
+ def create(options = {}, &block)
17
+ raise ArgumentError, '#create requires a block' unless block_given?
18
+
19
+ report = new(options)
20
+ call_block_in(report, &block)
21
+ report.finalize
22
+
23
+ report
24
+ end
25
+
26
+ # @param layout (see #initialize)
27
+ # @param filename (see #generate)
28
+ # @param security (see #generate)
29
+ # @param title (see #generate)
30
+ # @param [Hash] report ({}) DEPRECATED. Options for Report.
31
+ # @param [Hash] generator ({}) DEPRECATED. Options for Generator.
32
+ # @yield (see .create)
33
+ # @yieldparam (see .create)
34
+ # @return [String]
35
+ def generate(layout: nil, filename: nil, security: nil, title: nil, report: {}, generator: {}, &block)
36
+ raise ArgumentError, '#generate requires a block' unless block_given?
37
+
38
+ if report.any? || generator.any?
39
+ warn '[DEPRECATION] :report and :generator argument has been deprecated. ' \
40
+ 'Use :layout and :filename, :security argument instead.'
41
+ end
42
+
43
+ layout ||= report[:layout]
44
+ filename ||= generator[:filename]
45
+ security ||= generator[:security]
46
+
47
+ report = create(layout: layout, &block)
48
+ report.generate(filename: filename, security: security, title: title)
49
+ end
50
+ end
51
+
52
+ # @return [Thinreports::BasicReport::Report::Internal]
53
+ attr_reader :internal
54
+
55
+ # @return [Integer]
56
+ attr_reader :start_page_number
57
+
58
+ # @return [Thinreports::BasicReport::Report::Page]
59
+ def_delegator :internal, :page
60
+
61
+ # @return [Integer]
62
+ def_delegator :internal, :page_count
63
+
64
+ # @return [Array<Thinreports::BasicReport::Report::Page>]
65
+ def_delegator :internal, :pages
66
+
67
+ # @return [Thinreports::BasicReport::Layout::Base]
68
+ def_delegator :internal, :default_layout
69
+
70
+ # @param [Hash] options
71
+ # @option options [String, nil] :layout (nil)
72
+ def initialize(options = {})
73
+ @internal = Report::Internal.new(self, options)
74
+ @start_page_number = 1
75
+ end
76
+
77
+ # @yield [page]
78
+ # @yieldparam [Thinreports::BasicReport::Report::Page] page
79
+ # @example
80
+ # report.on_page_create do |page|
81
+ # page.item(:header_title).value = 'Title'
82
+ # end
83
+ def on_page_create(&block)
84
+ internal.page_create_handler = block
85
+ end
86
+
87
+ # @param [Integer] page_number
88
+ def start_page_number_from(page_number)
89
+ @start_page_number = page_number
90
+ end
91
+
92
+ # @param [String] layout filename of layout file
93
+ # @param [Hash] options
94
+ # @option options [Boolean] :default (true)
95
+ # @option options [Symbol] :id (nil)
96
+ # @example
97
+ # report.use_layout '/path/to/default_layout.tlf' # Default layout
98
+ # report.use_layout '/path/to/default_layout.tlf', default: true
99
+ # report.use_layout '/path/to/other_layout', id: :other_layout
100
+ def use_layout(layout, options = {})
101
+ internal.register_layout(layout, options)
102
+ end
103
+
104
+ # @example
105
+ # page = report.start_new_page
106
+ #
107
+ # report.start_new_page do |page|
108
+ # page.item(:text).value = 'value'
109
+ # end
110
+ #
111
+ # report.use_layout 'foo.tlf', default: true
112
+ # report.use_layout 'bar.tlf', id: :bar
113
+ #
114
+ # report.start_new_page # Use 'foo.tlf'
115
+ # report.start_new_page layout: :bar # Use 'bar.tlf'
116
+ # report.start_new_page layout: 'boo.tlf' # Use 'boo.tlf'
117
+ # @param [Hash] options
118
+ # @option options [String, Symbol] :layout (nil)
119
+ # @option options [Boolean] :count (true)
120
+ # @yield [page]
121
+ # @yieldparam [Thinreports::BasicReport::Report::Page] page
122
+ # @return [Thinreports::BasicReport::Report::Page]
123
+ def start_new_page(options = {}, &block)
124
+ layout = internal.load_layout(options.delete(:layout))
125
+
126
+ raise Thinreports::BasicReport::Errors::NoRegisteredLayoutFound unless layout
127
+
128
+ page = internal.add_page(Report::Page.new(self, layout, options))
129
+ call_block_in(page, &block)
130
+ end
131
+
132
+ # @param [Hash] options
133
+ # @option options [Boolean] :count (true)
134
+ # @return [Thinreports::BasicReport::Report::BlankPage]
135
+ def add_blank_page(options = {})
136
+ internal.add_page(Report::BlankPage.new(options[:count]))
137
+ end
138
+ alias blank_page add_blank_page
139
+
140
+ # @param [Symbol, nil] id
141
+ # @return [Thinreports::BasicReport::Layout::Base]
142
+ def layout(id = nil)
143
+ if id
144
+ internal.layout_registry[id] ||
145
+ raise(Thinreports::BasicReport::Errors::UnknownLayoutId)
146
+ else
147
+ internal.default_layout
148
+ end
149
+ end
150
+
151
+ # @param [String] filename
152
+ # @param [Hash] security (see http://prawnpdf.org/api-docs/2.0/Prawn/Document/Security.html#encrypt_document-instance_method)
153
+ # @param [String] title Value of the title attribute of the PDF document metadata.
154
+ # if nil, the title of the default layout file is set.
155
+ # @return [String]
156
+ # @example Generate PDF data
157
+ # report.generate # => "%PDF-1.4...."
158
+ # @example Create a PDF file
159
+ # report.generate(filename: 'foo.pdf')
160
+ def generate(filename: nil, security: nil, title: nil)
161
+ Thinreports::BasicReport::Generator::PDF.new(self, security: security, title: title).generate(filename)
162
+ end
163
+
164
+ # @see Thinreports::BasicReport::Core::Shape::Manager::Target#list
165
+ def list(id = nil, &block)
166
+ start_new_page if page.nil? || page.finalized?
167
+ page.list(id, &block)
168
+ end
169
+
170
+ def_delegators :internal, :finalize, :finalized?
171
+ end
172
+ end
173
+ end
174
+ end