squib 0.14.2 → 0.14.3.pre1

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 (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +41 -41
  3. data/.travis.yml +19 -19
  4. data/CHANGELOG.md +366 -357
  5. data/CONTRIBUTING.md +40 -40
  6. data/Gemfile +2 -2
  7. data/LICENSE.txt +22 -22
  8. data/README.md +121 -121
  9. data/RELEASE TODO.md +21 -21
  10. data/Rakefile +48 -48
  11. data/appveyor.yml +24 -24
  12. data/bin/squib +4 -4
  13. data/lib/squib.rb +32 -32
  14. data/lib/squib/api/background.rb +15 -15
  15. data/lib/squib/api/data.rb +137 -137
  16. data/lib/squib/api/groups.rb +54 -54
  17. data/lib/squib/api/image.rb +49 -49
  18. data/lib/squib/api/save.rb +83 -83
  19. data/lib/squib/api/settings.rb +21 -21
  20. data/lib/squib/api/shapes.rb +124 -124
  21. data/lib/squib/api/text.rb +25 -25
  22. data/lib/squib/api/text_embed.rb +71 -71
  23. data/lib/squib/api/units.rb +27 -27
  24. data/lib/squib/args/arg_loader.rb +126 -126
  25. data/lib/squib/args/box.rb +55 -55
  26. data/lib/squib/args/card_range.rb +32 -32
  27. data/lib/squib/args/color_validator.rb +12 -12
  28. data/lib/squib/args/coords.rb +35 -35
  29. data/lib/squib/args/csv_opts.rb +25 -25
  30. data/lib/squib/args/dir_validator.rb +16 -16
  31. data/lib/squib/args/draw.rb +92 -92
  32. data/lib/squib/args/embed_adjust.rb +25 -25
  33. data/lib/squib/args/embed_key.rb +17 -17
  34. data/lib/squib/args/hand_special.rb +37 -37
  35. data/lib/squib/args/import.rb +40 -40
  36. data/lib/squib/args/input_file.rb +37 -37
  37. data/lib/squib/args/paint.rb +44 -44
  38. data/lib/squib/args/paragraph.rb +116 -116
  39. data/lib/squib/args/save_batch.rb +63 -63
  40. data/lib/squib/args/scale_box.rb +53 -53
  41. data/lib/squib/args/sheet.rb +172 -172
  42. data/lib/squib/args/showcase_special.rb +38 -38
  43. data/lib/squib/args/sprue_file.rb +44 -44
  44. data/lib/squib/args/svg_special.rb +37 -37
  45. data/lib/squib/args/transform.rb +61 -61
  46. data/lib/squib/args/typographer.rb +119 -119
  47. data/lib/squib/args/unit_conversion.rb +29 -29
  48. data/lib/squib/builtin/layouts/economy.yml +85 -85
  49. data/lib/squib/builtin/layouts/fantasy.yml +101 -101
  50. data/lib/squib/builtin/layouts/hand.yml +62 -62
  51. data/lib/squib/builtin/layouts/party.yml +94 -94
  52. data/lib/squib/builtin/layouts/playing-card.yml +35 -35
  53. data/lib/squib/builtin/layouts/tuck_box.yml +46 -46
  54. data/lib/squib/builtin/projects/advanced/.gitignore +4 -4
  55. data/lib/squib/builtin/projects/advanced/ABOUT.md +19 -19
  56. data/lib/squib/builtin/projects/advanced/Gemfile +11 -11
  57. data/lib/squib/builtin/projects/advanced/Guardfile +21 -21
  58. data/lib/squib/builtin/projects/advanced/IDEAS.md +22 -22
  59. data/lib/squib/builtin/projects/advanced/PLAYTESTING.md +26 -26
  60. data/lib/squib/builtin/projects/advanced/Rakefile +27 -27
  61. data/lib/squib/builtin/projects/advanced/config.yml +53 -49
  62. data/lib/squib/builtin/projects/advanced/docs/PNP NOTES.md +3 -3
  63. data/lib/squib/builtin/projects/advanced/docs/RULES.md +21 -21
  64. data/lib/squib/builtin/projects/advanced/img/example.svg +60 -60
  65. data/lib/squib/builtin/projects/advanced/layouts/deck.yml +27 -27
  66. data/lib/squib/builtin/projects/advanced/src/deck.rb +34 -34
  67. data/lib/squib/builtin/projects/advanced/src/version.rb +3 -3
  68. data/lib/squib/builtin/projects/basic/.gitignore +4 -4
  69. data/lib/squib/builtin/projects/basic/ABOUT.md +19 -19
  70. data/lib/squib/builtin/projects/basic/Gemfile +3 -3
  71. data/lib/squib/builtin/projects/basic/IDEAS.md +22 -22
  72. data/lib/squib/builtin/projects/basic/PLAYTESTING.md +26 -26
  73. data/lib/squib/builtin/projects/basic/PNP NOTES.md +3 -3
  74. data/lib/squib/builtin/projects/basic/RULES.md +21 -21
  75. data/lib/squib/builtin/projects/basic/Rakefile +7 -7
  76. data/lib/squib/builtin/projects/basic/config.yml +53 -49
  77. data/lib/squib/builtin/projects/basic/deck.rb +6 -6
  78. data/lib/squib/builtin/sprues/a4_euro_card.yml +42 -42
  79. data/lib/squib/builtin/sprues/a4_poker_card_8up.yml +40 -40
  80. data/lib/squib/builtin/sprues/a4_poker_card_9up.yml +42 -42
  81. data/lib/squib/builtin/sprues/a4_usa_card.yml +42 -42
  82. data/lib/squib/builtin/sprues/drivethrucards_1up.yml +10 -10
  83. data/lib/squib/builtin/sprues/letter_poker_card_9up.yml +25 -25
  84. data/lib/squib/builtin/sprues/letter_poker_foldable_8up.yml +52 -52
  85. data/lib/squib/builtin/sprues/printplaygames_18up.yml +68 -68
  86. data/lib/squib/card.rb +75 -75
  87. data/lib/squib/commands/cli.rb +39 -39
  88. data/lib/squib/commands/data/template_option.rb +109 -109
  89. data/lib/squib/commands/make_sprue.rb +275 -275
  90. data/lib/squib/commands/new.rb +77 -77
  91. data/lib/squib/conf.rb +144 -139
  92. data/lib/squib/constants.rb +17 -17
  93. data/lib/squib/deck.rb +116 -116
  94. data/lib/squib/graphics/background.rb +14 -14
  95. data/lib/squib/graphics/cairo_context_wrapper.rb +113 -113
  96. data/lib/squib/graphics/embedding_utils.rb +28 -28
  97. data/lib/squib/graphics/gradient_regex.rb +47 -47
  98. data/lib/squib/graphics/hand.rb +42 -42
  99. data/lib/squib/graphics/image.rb +129 -108
  100. data/lib/squib/graphics/save_doc.rb +61 -61
  101. data/lib/squib/graphics/save_images.rb +52 -52
  102. data/lib/squib/graphics/save_pdf.rb +90 -90
  103. data/lib/squib/graphics/save_sprue.rb +204 -204
  104. data/lib/squib/graphics/shapes.rb +143 -143
  105. data/lib/squib/graphics/showcase.rb +85 -85
  106. data/lib/squib/graphics/text.rb +174 -174
  107. data/lib/squib/import/data_frame.rb +108 -108
  108. data/lib/squib/layout_parser.rb +138 -138
  109. data/lib/squib/progress.rb +38 -38
  110. data/lib/squib/sample_helpers.rb +34 -34
  111. data/lib/squib/sprues/crop_line.rb +28 -28
  112. data/lib/squib/sprues/crop_line_dash.rb +35 -35
  113. data/lib/squib/sprues/invalid_sprue_definition.rb +9 -9
  114. data/lib/squib/sprues/sprue.rb +203 -203
  115. data/lib/squib/sprues/sprue_schema.rb +48 -48
  116. data/lib/squib/version.rb +10 -10
  117. data/samples/autoscale_font/_autoscale_font.rb +29 -29
  118. data/samples/backend/_backend.rb +26 -26
  119. data/samples/basic.rb +19 -19
  120. data/samples/bug256/_bug256.rb +13 -0
  121. data/samples/build_groups/build_groups.rb +36 -36
  122. data/samples/colors/_colors.rb +38 -38
  123. data/samples/colors/_gradients.rb +34 -34
  124. data/samples/config/config_text_markup.rb +20 -20
  125. data/samples/config/custom_config.rb +18 -18
  126. data/samples/data/_csv.rb +33 -33
  127. data/samples/data/_excel.rb +55 -55
  128. data/samples/data/_yaml.rb +12 -12
  129. data/samples/hello_world.rb +6 -6
  130. data/samples/images/_cairo_access.rb +39 -39
  131. data/samples/images/_images.rb +104 -104
  132. data/samples/images/_more_load_images.rb +102 -102
  133. data/samples/intro/01_hello.rb +8 -8
  134. data/samples/intro/02_options.rb +14 -14
  135. data/samples/intro/03_layout.rb +11 -11
  136. data/samples/intro/04_arrays.rb +15 -15
  137. data/samples/intro/05_excel.rb +14 -14
  138. data/samples/layouts/builtin_layouts.rb +97 -97
  139. data/samples/layouts/layouts.rb +71 -71
  140. data/samples/project/src/characters.rb +8 -8
  141. data/samples/project/src/skills.rb +7 -7
  142. data/samples/proofs/_tgc_proofs.rb +16 -16
  143. data/samples/ranges/_ranges.rb +64 -64
  144. data/samples/saves/_hand.rb +23 -23
  145. data/samples/saves/_portrait_landscape.rb +23 -23
  146. data/samples/saves/_save_pdf.rb +29 -29
  147. data/samples/saves/_saves.rb +51 -51
  148. data/samples/saves/_showcase.rb +25 -25
  149. data/samples/shapes/_draw_shapes.rb +60 -60
  150. data/samples/shapes/_proofs.rb +22 -22
  151. data/samples/sprues/_advanced_sprues.rb +24 -24
  152. data/samples/sprues/_builtin_sprues.rb +21 -21
  153. data/samples/sprues/_fold_sheet.rb +27 -27
  154. data/samples/sprues/_hex_tiles.rb +15 -15
  155. data/samples/sprues/_mints.rb +11 -11
  156. data/samples/sprues/_sprue_example.rb +11 -11
  157. data/samples/text/_embed_text.rb +128 -128
  158. data/samples/text/_text.rb +47 -47
  159. data/samples/text/_text_options.rb +102 -102
  160. data/samples/text/bug134.rb +14 -14
  161. data/samples/units/_units.rb +32 -32
  162. data/squib.gemspec +52 -52
  163. metadata +51 -48
@@ -1,174 +1,174 @@
1
- require 'pango'
2
- require_relative '../args/typographer'
3
- require_relative 'embedding_utils'
4
-
5
- module Squib
6
- class Card
7
-
8
- # :nodoc:
9
- # @api private
10
- def draw_text_hint(cc, x, y, layout, color)
11
- color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
12
- return if color.to_s.eql? 'off' or color.nil?
13
- # when w,h < 0, it was never set. extents[1] are ink extents
14
- w = layout.width / Pango::SCALE
15
- w = layout.extents[1].width / Pango::SCALE if w < 0
16
- h = layout.height / Pango::SCALE
17
- h = layout.extents[1].height / Pango::SCALE if h < 0
18
- cc.rounded_rectangle(0, 0, w, h, 0, 0)
19
- cc.set_source_color(color)
20
- cc.set_line_width(2.0)
21
- cc.stroke
22
- end
23
-
24
- # :nodoc:
25
- # @api private
26
- def compute_valign(layout, valign, embed_h)
27
- return 0 unless layout.height > 0
28
- ink_extents = layout.extents[1]
29
- ink_extents.height = embed_h * Pango::SCALE if ink_extents.height == 0 # JUST embed, bug #134
30
- case valign.to_s.downcase
31
- when 'middle'
32
- Pango.pixels((layout.height - ink_extents.height) / 2)
33
- when 'bottom'
34
- Pango.pixels(layout.height - ink_extents.height)
35
- else
36
- 0
37
- end
38
- end
39
-
40
- def set_font_rendering_opts!(layout)
41
- font_options = Cairo::FontOptions.new
42
- font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
43
- font_options.hint_metrics = 'on' # TODO make this configurable
44
- font_options.hint_style = 'full' # TODO make this configurable
45
- layout.context.font_options = font_options
46
- end
47
-
48
- # :nodoc:
49
- # @api private
50
- def set_wh!(layout, width, height)
51
- layout.width = width * Pango::SCALE unless width.nil? || width == :auto
52
- layout.height = height * Pango::SCALE unless height.nil? || height == :auto
53
- end
54
-
55
- # Compute the width of the carve that we need
56
- def compute_carve(rule, range)
57
- w = rule[:box].width[@index]
58
- if w == :native
59
- file = rule[:file][@index].file
60
- case rule[:type]
61
- when :png
62
- Squib.cache_load_image(file).width.to_f / (range.size - 1)
63
- when :svg
64
- svg_data = rule[:svg_args].data[@index]
65
- unless file.to_s.empty? || svg_data.to_s.empty?
66
- Squib.logger.warn 'Both an SVG file and SVG data were specified'
67
- end
68
- return 0 if (file.nil? or file.eql? '') and svg_data.nil?
69
- svg_data = File.read(file) if svg_data.to_s.empty?
70
- RSVG::Handle.new_from_data(svg_data).width
71
- end
72
- else
73
- rule[:box].width[@index] * Pango::SCALE / (range.size - 1)
74
- end
75
- end
76
-
77
- # # :nodoc:
78
- # # @api private
79
- def embed_images!(embed, str, layout, valign)
80
- return [] unless embed.rules.any?
81
- layout.markup = str
82
- clean_str = layout.text
83
- attrs = layout.attributes || Pango::AttrList.new
84
- EmbeddingUtils.indices(clean_str, embed.rules.keys).each do |key, ranges|
85
- rule = embed.rules[key]
86
- ranges.each do |range|
87
- carve = Pango::Rectangle.new(0, 0, compute_carve(rule, range), 0)
88
- att = Pango::AttrShape.new(carve, carve, rule)
89
- att.start_index = range.first
90
- att.end_index = range.last
91
- attrs.insert(att)
92
- end
93
- end
94
- layout.attributes = attrs
95
- layout.context.set_shape_renderer do |cxt, att, do_path|
96
- unless do_path # when stroking the text
97
- rule = att.data
98
- x = Pango.pixels(layout.index_to_pos(att.start_index).x) +
99
- rule[:adjust].dx[@index]
100
- y = Pango.pixels(layout.index_to_pos(att.start_index).y) +
101
- rule[:adjust].dy[@index] +
102
- compute_valign(layout, valign, rule[:box].height[@index])
103
- rule[:draw].call(self, x, y)
104
- cxt.reset_clip
105
- [cxt, att, do_path]
106
- end
107
- end
108
- end
109
-
110
- def stroke_outline!(cc, layout, draw)
111
- if draw.stroke_width > 0
112
- cc.pango_layout_path(layout)
113
- cc.fancy_stroke draw
114
- cc.set_source_squibcolor(draw.color)
115
- end
116
- end
117
-
118
- def warn_if_ellipsized(layout)
119
- if @deck.conf.warn_ellipsize? && layout.ellipsized?
120
- Squib.logger.warn { "Ellipsized (too much text). Card \##{@index}. Text: \"#{layout.text}\". \n (To disable this warning, set warn_ellipsize: false in config.yml)" }
121
- end
122
- end
123
-
124
- # :nodoc:
125
- # @api private
126
- def text(embed, para, box, trans, draw, dpi)
127
- Squib.logger.debug {"Rendering text with: \n#{para} \nat:\n #{box} \ndraw:\n #{draw} \ntransform: #{trans}"}
128
- extents = nil
129
- use_cairo do |cc|
130
- cc.set_source_squibcolor(draw.color)
131
- cc.translate(box.x, box.y)
132
- cc.rotate(trans.angle)
133
- cc.move_to(0, 0)
134
-
135
- font_desc = Pango::FontDescription.new(para.font)
136
- font_desc.size = para.font_size * Pango::SCALE unless para.font_size.nil?
137
- layout = cc.create_pango_layout
138
- layout.font_description = font_desc
139
- layout.text = para.str.to_s
140
- layout.context.resolution = dpi
141
- if para.markup
142
- para.str = @deck.typographer.process(layout.text)
143
- layout.markup = para.str.to_s
144
- end
145
-
146
- set_font_rendering_opts!(layout)
147
- set_wh!(layout, box.width, box.height)
148
- layout.wrap = para.wrap
149
- layout.ellipsize = para.ellipsize
150
- layout.alignment = para.align
151
-
152
- layout.justify = para.justify unless para.justify.nil?
153
- layout.spacing = para.spacing unless para.spacing.nil?
154
-
155
- embed_images!(embed, para.str, layout, para.valign)
156
-
157
- vertical_start = compute_valign(layout, para.valign, 0)
158
- cc.move_to(0, vertical_start)
159
-
160
- stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :stroke_first
161
- cc.move_to(0, vertical_start)
162
-
163
- cc.show_pango_layout(layout)
164
- stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :fill_first
165
- draw_text_hint(cc, box.x, box.y, layout, para.hint)
166
- extents = { width: layout.extents[1].width / Pango::SCALE,
167
- height: layout.extents[1].height / Pango::SCALE }
168
- warn_if_ellipsized layout
169
- end
170
- return extents
171
- end
172
-
173
- end
174
- end
1
+ require 'pango'
2
+ require_relative '../args/typographer'
3
+ require_relative 'embedding_utils'
4
+
5
+ module Squib
6
+ class Card
7
+
8
+ # :nodoc:
9
+ # @api private
10
+ def draw_text_hint(cc, x, y, layout, color)
11
+ color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
12
+ return if color.to_s.eql? 'off' or color.nil?
13
+ # when w,h < 0, it was never set. extents[1] are ink extents
14
+ w = layout.width / Pango::SCALE
15
+ w = layout.extents[1].width / Pango::SCALE if w < 0
16
+ h = layout.height / Pango::SCALE
17
+ h = layout.extents[1].height / Pango::SCALE if h < 0
18
+ cc.rounded_rectangle(0, 0, w, h, 0, 0)
19
+ cc.set_source_color(color)
20
+ cc.set_line_width(2.0)
21
+ cc.stroke
22
+ end
23
+
24
+ # :nodoc:
25
+ # @api private
26
+ def compute_valign(layout, valign, embed_h)
27
+ return 0 unless layout.height > 0
28
+ ink_extents = layout.extents[1]
29
+ ink_extents.height = embed_h * Pango::SCALE if ink_extents.height == 0 # JUST embed, bug #134
30
+ case valign.to_s.downcase
31
+ when 'middle'
32
+ Pango.pixels((layout.height - ink_extents.height) / 2)
33
+ when 'bottom'
34
+ Pango.pixels(layout.height - ink_extents.height)
35
+ else
36
+ 0
37
+ end
38
+ end
39
+
40
+ def set_font_rendering_opts!(layout)
41
+ font_options = Cairo::FontOptions.new
42
+ font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
43
+ font_options.hint_metrics = 'on' # TODO make this configurable
44
+ font_options.hint_style = 'full' # TODO make this configurable
45
+ layout.context.font_options = font_options
46
+ end
47
+
48
+ # :nodoc:
49
+ # @api private
50
+ def set_wh!(layout, width, height)
51
+ layout.width = width * Pango::SCALE unless width.nil? || width == :auto
52
+ layout.height = height * Pango::SCALE unless height.nil? || height == :auto
53
+ end
54
+
55
+ # Compute the width of the carve that we need
56
+ def compute_carve(rule, range)
57
+ w = rule[:box].width[@index]
58
+ if w == :native
59
+ file = rule[:file][@index].file
60
+ case rule[:type]
61
+ when :png
62
+ Squib.cache_load_image(file).width.to_f / (range.size - 1)
63
+ when :svg
64
+ svg_data = rule[:svg_args].data[@index]
65
+ unless file.to_s.empty? || svg_data.to_s.empty?
66
+ Squib.logger.warn 'Both an SVG file and SVG data were specified'
67
+ end
68
+ return 0 if (file.nil? or file.eql? '') and svg_data.nil?
69
+ svg_data = File.read(file) if svg_data.to_s.empty?
70
+ RSVG::Handle.new_from_data(svg_data).width
71
+ end
72
+ else
73
+ rule[:box].width[@index] * Pango::SCALE / (range.size - 1)
74
+ end
75
+ end
76
+
77
+ # # :nodoc:
78
+ # # @api private
79
+ def embed_images!(embed, str, layout, valign)
80
+ return [] unless embed.rules.any?
81
+ layout.markup = str
82
+ clean_str = layout.text
83
+ attrs = layout.attributes || Pango::AttrList.new
84
+ EmbeddingUtils.indices(clean_str, embed.rules.keys).each do |key, ranges|
85
+ rule = embed.rules[key]
86
+ ranges.each do |range|
87
+ carve = Pango::Rectangle.new(0, 0, compute_carve(rule, range), 0)
88
+ att = Pango::AttrShape.new(carve, carve, rule)
89
+ att.start_index = range.first
90
+ att.end_index = range.last
91
+ attrs.insert(att)
92
+ end
93
+ end
94
+ layout.attributes = attrs
95
+ layout.context.set_shape_renderer do |cxt, att, do_path|
96
+ unless do_path # when stroking the text
97
+ rule = att.data
98
+ x = Pango.pixels(layout.index_to_pos(att.start_index).x) +
99
+ rule[:adjust].dx[@index]
100
+ y = Pango.pixels(layout.index_to_pos(att.start_index).y) +
101
+ rule[:adjust].dy[@index] +
102
+ compute_valign(layout, valign, rule[:box].height[@index])
103
+ rule[:draw].call(self, x, y)
104
+ cxt.reset_clip
105
+ [cxt, att, do_path]
106
+ end
107
+ end
108
+ end
109
+
110
+ def stroke_outline!(cc, layout, draw)
111
+ if draw.stroke_width > 0
112
+ cc.pango_layout_path(layout)
113
+ cc.fancy_stroke draw
114
+ cc.set_source_squibcolor(draw.color)
115
+ end
116
+ end
117
+
118
+ def warn_if_ellipsized(layout)
119
+ if @deck.conf.warn_ellipsize? && layout.ellipsized?
120
+ Squib.logger.warn { "Ellipsized (too much text). Card \##{@index}. Text: \"#{layout.text}\". \n (To disable this warning, set warn_ellipsize: false in config.yml)" }
121
+ end
122
+ end
123
+
124
+ # :nodoc:
125
+ # @api private
126
+ def text(embed, para, box, trans, draw, dpi)
127
+ Squib.logger.debug {"Rendering text with: \n#{para} \nat:\n #{box} \ndraw:\n #{draw} \ntransform: #{trans}"}
128
+ extents = nil
129
+ use_cairo do |cc|
130
+ cc.set_source_squibcolor(draw.color)
131
+ cc.translate(box.x, box.y)
132
+ cc.rotate(trans.angle)
133
+ cc.move_to(0, 0)
134
+
135
+ font_desc = Pango::FontDescription.new(para.font)
136
+ font_desc.size = para.font_size * Pango::SCALE unless para.font_size.nil?
137
+ layout = cc.create_pango_layout
138
+ layout.font_description = font_desc
139
+ layout.text = para.str.to_s
140
+ layout.context.resolution = dpi
141
+ if para.markup
142
+ para.str = @deck.typographer.process(layout.text)
143
+ layout.markup = para.str.to_s
144
+ end
145
+
146
+ set_font_rendering_opts!(layout)
147
+ set_wh!(layout, box.width, box.height)
148
+ layout.wrap = para.wrap
149
+ layout.ellipsize = para.ellipsize
150
+ layout.alignment = para.align
151
+
152
+ layout.justify = para.justify unless para.justify.nil?
153
+ layout.spacing = para.spacing unless para.spacing.nil?
154
+
155
+ embed_images!(embed, para.str, layout, para.valign)
156
+
157
+ vertical_start = compute_valign(layout, para.valign, 0)
158
+ cc.move_to(0, vertical_start)
159
+
160
+ stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :stroke_first
161
+ cc.move_to(0, vertical_start)
162
+
163
+ cc.show_pango_layout(layout)
164
+ stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :fill_first
165
+ draw_text_hint(cc, box.x, box.y, layout, para.hint)
166
+ extents = { width: layout.extents[1].width / Pango::SCALE,
167
+ height: layout.extents[1].height / Pango::SCALE }
168
+ warn_if_ellipsized layout
169
+ end
170
+ return extents
171
+ end
172
+
173
+ end
174
+ end
@@ -1,108 +1,108 @@
1
- # encoding: UTF-8
2
-
3
- require 'json'
4
- require 'forwardable'
5
-
6
- module Squib
7
- class DataFrame
8
- include Enumerable
9
-
10
- def initialize(hash = {}, def_columns = true)
11
- @hash = hash
12
- columns.each { |col| def_column(col) } if def_columns
13
- end
14
-
15
- def each(&block)
16
- @hash.each(&block)
17
- end
18
-
19
- def [](i)
20
- @hash[i]
21
- end
22
-
23
- def []=(col, v)
24
- @hash[col] = v
25
- def_column(col)
26
- return v
27
- end
28
-
29
- def columns
30
- @hash.keys
31
- end
32
-
33
- def ncolumns
34
- @hash.keys.size
35
- end
36
-
37
- def col?(col)
38
- @hash.key? col
39
- end
40
-
41
- def row(i)
42
- @hash.inject(Hash.new) { |ret, (name, arr)| ret[name] = arr[i]; ret }
43
- end
44
-
45
- def nrows
46
- @hash.inject(0) { |max, (_n, col)| col.size > max ? col.size : max }
47
- end
48
-
49
- def to_json
50
- @hash.to_json
51
- end
52
-
53
- def to_pretty_json
54
- JSON.pretty_generate(@hash)
55
- end
56
-
57
- def to_h
58
- @hash
59
- end
60
-
61
- def to_pretty_text
62
- max_col = columns.inject(0) { |max, c | c.length > max ? c.length : max }
63
- top = " ╭#{'-' * 36}╮\n"
64
- bottom = " ╰#{'-' * 36}╯\n"
65
- str = ''
66
- 0.upto(nrows - 1) do | i |
67
- str += (' ' * max_col) + top
68
- row(i).each do |col, data|
69
- str += "#{col.rjust(max_col)} #{wrap_n_pad(data, max_col)}"
70
- end
71
- str += (' ' * max_col) + bottom
72
- end
73
- return str
74
- end
75
-
76
- private
77
-
78
- def snake_case(str)
79
- str.to_s.
80
- strip.
81
- gsub(/\s+/,'_').
82
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
83
- gsub(/([a-z]+)([A-Z])/,'\1_\2').
84
- downcase.
85
- to_sym
86
- end
87
-
88
- def wrap_n_pad(str, max_col)
89
- new_str = str.to_s + ' ' # handle nil & empty strings
90
- new_str = new_str.
91
- scan(/.{1,34}/). # break down
92
- map { |s| (' ' * max_col) + " | " + s.ljust(34) }.
93
- join(" |\n").
94
- lstrip # initially no whitespace next to key
95
- return new_str + " |\n"
96
- end
97
-
98
- def def_column(col)
99
- raise "Column #{col} - does not exist" unless @hash.key? col
100
- method_name = snake_case(col)
101
- return if self.class.method_defined?(method_name) #warn people? or skip?
102
- define_singleton_method method_name do
103
- @hash[col]
104
- end
105
- end
106
-
107
- end
108
- end
1
+ # encoding: UTF-8
2
+
3
+ require 'json'
4
+ require 'forwardable'
5
+
6
+ module Squib
7
+ class DataFrame
8
+ include Enumerable
9
+
10
+ def initialize(hash = {}, def_columns = true)
11
+ @hash = hash
12
+ columns.each { |col| def_column(col) } if def_columns
13
+ end
14
+
15
+ def each(&block)
16
+ @hash.each(&block)
17
+ end
18
+
19
+ def [](i)
20
+ @hash[i]
21
+ end
22
+
23
+ def []=(col, v)
24
+ @hash[col] = v
25
+ def_column(col)
26
+ return v
27
+ end
28
+
29
+ def columns
30
+ @hash.keys
31
+ end
32
+
33
+ def ncolumns
34
+ @hash.keys.size
35
+ end
36
+
37
+ def col?(col)
38
+ @hash.key? col
39
+ end
40
+
41
+ def row(i)
42
+ @hash.inject(Hash.new) { |ret, (name, arr)| ret[name] = arr[i]; ret }
43
+ end
44
+
45
+ def nrows
46
+ @hash.inject(0) { |max, (_n, col)| col.size > max ? col.size : max }
47
+ end
48
+
49
+ def to_json
50
+ @hash.to_json
51
+ end
52
+
53
+ def to_pretty_json
54
+ JSON.pretty_generate(@hash)
55
+ end
56
+
57
+ def to_h
58
+ @hash
59
+ end
60
+
61
+ def to_pretty_text
62
+ max_col = columns.inject(0) { |max, c | c.length > max ? c.length : max }
63
+ top = " ╭#{'-' * 36}╮\n"
64
+ bottom = " ╰#{'-' * 36}╯\n"
65
+ str = ''
66
+ 0.upto(nrows - 1) do | i |
67
+ str += (' ' * max_col) + top
68
+ row(i).each do |col, data|
69
+ str += "#{col.rjust(max_col)} #{wrap_n_pad(data, max_col)}"
70
+ end
71
+ str += (' ' * max_col) + bottom
72
+ end
73
+ return str
74
+ end
75
+
76
+ private
77
+
78
+ def snake_case(str)
79
+ str.to_s.
80
+ strip.
81
+ gsub(/\s+/,'_').
82
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
83
+ gsub(/([a-z]+)([A-Z])/,'\1_\2').
84
+ downcase.
85
+ to_sym
86
+ end
87
+
88
+ def wrap_n_pad(str, max_col)
89
+ new_str = str.to_s + ' ' # handle nil & empty strings
90
+ new_str = new_str.
91
+ scan(/.{1,34}/). # break down
92
+ map { |s| (' ' * max_col) + " | " + s.ljust(34) }.
93
+ join(" |\n").
94
+ lstrip # initially no whitespace next to key
95
+ return new_str + " |\n"
96
+ end
97
+
98
+ def def_column(col)
99
+ raise "Column #{col} - does not exist" unless @hash.key? col
100
+ method_name = snake_case(col)
101
+ return if self.class.method_defined?(method_name) #warn people? or skip?
102
+ define_singleton_method method_name do
103
+ @hash[col]
104
+ end
105
+ end
106
+
107
+ end
108
+ end