thinreports 0.12.1 → 0.13.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 (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 +19 -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 +173 -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,173 @@
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 [Hash] report ({}) DEPRECATED. Options for Report.
30
+ # @param [Hash] generator ({}) DEPRECATED. Options for Generator.
31
+ # @yield (see .create)
32
+ # @yieldparam (see .create)
33
+ # @return [String]
34
+ def generate(layout: nil, filename: nil, security: nil, report: {}, generator: {}, &block)
35
+ raise ArgumentError, '#generate requires a block' unless block_given?
36
+
37
+ if report.any? || generator.any?
38
+ warn '[DEPRECATION] :report and :generator argument has been deprecated. ' \
39
+ 'Use :layout and :filename, :security argument instead.'
40
+ end
41
+
42
+ layout ||= report[:layout]
43
+ filename ||= generator[:filename]
44
+ security ||= generator[:security]
45
+
46
+ report = create(layout: layout, &block)
47
+ report.generate(filename: filename, security: security)
48
+ end
49
+ end
50
+
51
+ # @return [Thinreports::BasicReport::Report::Internal]
52
+ attr_reader :internal
53
+
54
+ # @return [Integer]
55
+ attr_reader :start_page_number
56
+
57
+ # @return [Thinreports::BasicReport::Report::Page]
58
+ def_delegator :internal, :page
59
+
60
+ # @return [Integer]
61
+ def_delegator :internal, :page_count
62
+
63
+ # @return [Array<Thinreports::BasicReport::Report::Page>]
64
+ def_delegator :internal, :pages
65
+
66
+ # @return [Thinreports::BasicReport::Layout::Base]
67
+ def_delegator :internal, :default_layout
68
+
69
+ # @param [Hash] options
70
+ # @option options [String, nil] :layout (nil)
71
+ def initialize(options = {})
72
+ @internal = Report::Internal.new(self, options)
73
+ @start_page_number = 1
74
+ end
75
+
76
+ # @yield [page]
77
+ # @yieldparam [Thinreports::BasicReport::Report::Page] page
78
+ # @example
79
+ # report.on_page_create do |page|
80
+ # page.item(:header_title).value = 'Title'
81
+ # end
82
+ def on_page_create(&block)
83
+ internal.page_create_handler = block
84
+ end
85
+
86
+ # @param [Integer] page_number
87
+ def start_page_number_from(page_number)
88
+ @start_page_number = page_number
89
+ end
90
+
91
+ # @param [String] layout filename of layout file
92
+ # @param [Hash] options
93
+ # @option options [Boolean] :default (true)
94
+ # @option options [Symbol] :id (nil)
95
+ # @example
96
+ # report.use_layout '/path/to/default_layout.tlf' # Default layout
97
+ # report.use_layout '/path/to/default_layout.tlf', default: true
98
+ # report.use_layout '/path/to/other_layout', id: :other_layout
99
+ def use_layout(layout, options = {})
100
+ internal.register_layout(layout, options)
101
+ end
102
+
103
+ # @example
104
+ # page = report.start_new_page
105
+ #
106
+ # report.start_new_page do |page|
107
+ # page.item(:text).value = 'value'
108
+ # end
109
+ #
110
+ # report.use_layout 'foo.tlf', default: true
111
+ # report.use_layout 'bar.tlf', id: :bar
112
+ #
113
+ # report.start_new_page # Use 'foo.tlf'
114
+ # report.start_new_page layout: :bar # Use 'bar.tlf'
115
+ # report.start_new_page layout: 'boo.tlf' # Use 'boo.tlf'
116
+ # @param [Hash] options
117
+ # @option options [String, Symbol] :layout (nil)
118
+ # @option options [Boolean] :count (true)
119
+ # @yield [page]
120
+ # @yieldparam [Thinreports::BasicReport::Report::Page] page
121
+ # @return [Thinreports::BasicReport::Report::Page]
122
+ def start_new_page(options = {}, &block)
123
+ layout = internal.load_layout(options.delete(:layout))
124
+
125
+ raise Thinreports::BasicReport::Errors::NoRegisteredLayoutFound unless layout
126
+
127
+ page = internal.add_page(Report::Page.new(self, layout, options))
128
+ call_block_in(page, &block)
129
+ end
130
+
131
+ # @param [Hash] options
132
+ # @option options [Boolean] :count (true)
133
+ # @return [Thinreports::BasicReport::Report::BlankPage]
134
+ def add_blank_page(options = {})
135
+ internal.add_page(Report::BlankPage.new(options[:count]))
136
+ end
137
+ alias blank_page add_blank_page
138
+
139
+ # @param [Symbol, nil] id
140
+ # @return [Thinreports::BasicReport::Layout::Base]
141
+ def layout(id = nil)
142
+ if id
143
+ internal.layout_registry[id] ||
144
+ raise(Thinreports::BasicReport::Errors::UnknownLayoutId)
145
+ else
146
+ internal.default_layout
147
+ end
148
+ end
149
+
150
+ # @param [String] filename
151
+ # @param [Hash] security (see http://prawnpdf.org/api-docs/2.0/Prawn/Document/Security.html#encrypt_document-instance_method)
152
+ # @param [String] title Value of the title attribute of the PDF document metadata.
153
+ # if nil, the title of the default layout file is set.
154
+ # @return [String]
155
+ # @example Generate PDF data
156
+ # report.generate # => "%PDF-1.4...."
157
+ # @example Create a PDF file
158
+ # report.generate(filename: 'foo.pdf')
159
+ def generate(filename: nil, security: nil, title: nil)
160
+ Thinreports::BasicReport::Generator::PDF.new(self, security: security, title: title).generate(filename)
161
+ end
162
+
163
+ # @see Thinreports::BasicReport::Core::Shape::Manager::Target#list
164
+ def list(id = nil, &block)
165
+ start_new_page if page.nil? || page.finalized?
166
+ page.list(id, &block)
167
+ end
168
+
169
+ def_delegators :internal, :finalize, :finalized?
170
+ end
171
+ end
172
+ end
173
+ end