thinreports 0.12.1 → 0.13.1

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