squib 0.9.0 → 0.10.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 (230) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.gitmodules +22 -0
  4. data/.travis.yml +4 -5
  5. data/CHANGELOG.md +23 -0
  6. data/CONTRIBUTING.md +40 -0
  7. data/README.md +25 -553
  8. data/RELEASE TODO.md +2 -2
  9. data/Rakefile +6 -64
  10. data/appveyor.yml +0 -4
  11. data/benchmarks/antialias_best.rb +2 -2
  12. data/benchmarks/antialias_fast.rb +2 -2
  13. data/benchmarks/{backend-memory.rb → backend_memory.rb} +2 -2
  14. data/benchmarks/{backend-svg.rb → backend_svg.rb} +2 -2
  15. data/benchmarks/tons_of_png.rb +1 -1
  16. data/benchmarks/tons_of_svg.rb +1 -1
  17. data/benchmarks/tons_of_text.rb +1 -1
  18. data/docs/Makefile +216 -0
  19. data/docs/_static/css/squibdocs.css +18 -0
  20. data/docs/args/draw.rst +36 -0
  21. data/docs/args/expansion.rst +3 -0
  22. data/docs/args/layout.rst +6 -0
  23. data/docs/args/output_dir.rst +6 -0
  24. data/docs/args/range.rst +6 -0
  25. data/docs/args/transform.rst +51 -0
  26. data/docs/args/trim.rst +11 -0
  27. data/docs/args/wh.rst +12 -0
  28. data/docs/args/xy.rst +12 -0
  29. data/docs/arrays.rst +77 -0
  30. data/docs/backends.rst +20 -0
  31. data/docs/bleed.rst +13 -0
  32. data/docs/build_groups.rst +47 -0
  33. data/docs/colors.rst +64 -0
  34. data/docs/conf.py +287 -0
  35. data/docs/config.rst +117 -0
  36. data/docs/data.rst +22 -0
  37. data/docs/dsl/background.rst +20 -0
  38. data/docs/dsl/build.rst +32 -0
  39. data/docs/dsl/build_groups.rst +23 -0
  40. data/docs/dsl/circle.rst +27 -0
  41. data/docs/dsl/cm.rst +19 -0
  42. data/docs/dsl/csv.rst +62 -0
  43. data/docs/dsl/curve.rst +63 -0
  44. data/docs/dsl/deck.rst +45 -0
  45. data/docs/dsl/disable_build.rst +28 -0
  46. data/docs/dsl/ellipse.rst +17 -0
  47. data/docs/dsl/enable_build.rst +25 -0
  48. data/docs/dsl/grid.rst +31 -0
  49. data/docs/dsl/hand.rst +40 -0
  50. data/docs/dsl/hint.rst +15 -0
  51. data/docs/dsl/inches.rst +19 -0
  52. data/docs/dsl/index.rst +9 -0
  53. data/docs/dsl/line.rst +52 -0
  54. data/docs/dsl/png.rst +49 -0
  55. data/docs/dsl/polygon.rst +28 -0
  56. data/docs/dsl/rect.rst +18 -0
  57. data/docs/dsl/save.rst +23 -0
  58. data/docs/dsl/save_pdf.rst +48 -0
  59. data/docs/dsl/save_png.rst +46 -0
  60. data/docs/dsl/save_sheet.rst +55 -0
  61. data/docs/dsl/showcase.rst +65 -0
  62. data/docs/dsl/star.rst +35 -0
  63. data/docs/dsl/svg.rst +119 -0
  64. data/docs/dsl/text.rst +294 -0
  65. data/docs/dsl/triangle.rst +38 -0
  66. data/docs/dsl/use_layout.rst +16 -0
  67. data/docs/dsl/xlsx.rst +50 -0
  68. data/docs/guides/game_icons.rst +2 -0
  69. data/docs/guides/getting-started/index.rst +5 -0
  70. data/docs/guides/getting-started/part_0_learning_ruby.rst +145 -0
  71. data/docs/guides/getting-started/part_1_zero_to_game.rst +216 -0
  72. data/docs/guides/getting-started/part_2_iconography.rst +152 -0
  73. data/docs/guides/getting-started/part_3_workflows.rst +4 -0
  74. data/docs/guides/git.rst +13 -0
  75. data/docs/guides/hello_world.rst +6 -0
  76. data/docs/help.rst +157 -0
  77. data/docs/index.rst +35 -0
  78. data/docs/install.rst +66 -0
  79. data/docs/layouts.rst +235 -0
  80. data/docs/learning.rst +10 -0
  81. data/docs/make.bat +263 -0
  82. data/docs/parameters.rst +26 -0
  83. data/docs/server.bat +1 -0
  84. data/docs/text_feature.rst +86 -0
  85. data/docs/units.rst +6 -0
  86. data/lib/squib.rb +4 -4
  87. data/lib/squib/api/background.rb +5 -10
  88. data/lib/squib/api/data.rb +30 -54
  89. data/lib/squib/api/groups.rb +47 -0
  90. data/lib/squib/api/image.rb +8 -67
  91. data/lib/squib/api/save.rb +15 -105
  92. data/lib/squib/api/settings.rb +8 -22
  93. data/lib/squib/api/shapes.rb +15 -185
  94. data/lib/squib/api/text.rb +9 -49
  95. data/lib/squib/api/text_embed.rb +12 -12
  96. data/lib/squib/api/units.rb +3 -17
  97. data/lib/squib/args/arg_loader.rb +6 -6
  98. data/lib/squib/args/box.rb +2 -2
  99. data/lib/squib/args/card_range.rb +1 -1
  100. data/lib/squib/args/color_validator.rb +2 -2
  101. data/lib/squib/args/coords.rb +2 -2
  102. data/lib/squib/args/csv_opts.rb +25 -0
  103. data/lib/squib/args/dir_validator.rb +1 -1
  104. data/lib/squib/args/draw.rb +2 -2
  105. data/lib/squib/args/embed_adjust.rb +1 -1
  106. data/lib/squib/args/embed_key.rb +1 -1
  107. data/lib/squib/args/hand_special.rb +37 -37
  108. data/lib/squib/args/import.rb +2 -2
  109. data/lib/squib/args/input_file.rb +1 -1
  110. data/lib/squib/args/paint.rb +3 -3
  111. data/lib/squib/args/paragraph.rb +2 -2
  112. data/lib/squib/args/save_batch.rb +2 -2
  113. data/lib/squib/args/scale_box.rb +1 -1
  114. data/lib/squib/args/sheet.rb +3 -3
  115. data/lib/squib/args/showcase_special.rb +2 -2
  116. data/lib/squib/args/svg_special.rb +1 -1
  117. data/lib/squib/args/transform.rb +2 -2
  118. data/lib/squib/args/typographer.rb +5 -4
  119. data/lib/squib/args/unit_conversion.rb +4 -4
  120. data/lib/squib/card.rb +8 -8
  121. data/lib/squib/conf.rb +5 -5
  122. data/lib/squib/deck.rb +20 -18
  123. data/lib/squib/graphics/cairo_context_wrapper.rb +3 -3
  124. data/lib/squib/graphics/gradient_regex.rb +1 -1
  125. data/lib/squib/graphics/hand.rb +2 -2
  126. data/lib/squib/graphics/save_doc.rb +9 -8
  127. data/lib/squib/graphics/save_images.rb +24 -11
  128. data/lib/squib/graphics/shapes.rb +16 -17
  129. data/lib/squib/graphics/showcase.rb +9 -9
  130. data/lib/squib/graphics/text.rb +21 -21
  131. data/lib/squib/layout_parser.rb +9 -9
  132. data/lib/squib/layouts/economy.yml +85 -85
  133. data/lib/squib/layouts/fantasy.yml +101 -101
  134. data/lib/squib/layouts/hand.yml +62 -62
  135. data/lib/squib/layouts/playing-card.yml +35 -35
  136. data/lib/squib/layouts/tuck_box.yml +45 -45
  137. data/lib/squib/sample_helpers.rb +1 -1
  138. data/lib/squib/version.rb +1 -1
  139. data/samples/{backend.rb → backend/_backend.rb} +2 -2
  140. data/samples/basic.rb +3 -3
  141. data/samples/bug134.rb +14 -0
  142. data/samples/build_groups/build_groups.rb +36 -0
  143. data/samples/cairo_access.rb +12 -1
  144. data/samples/{colors.rb → colors/_colors.rb} +12 -12
  145. data/samples/{gradients.rb → colors/_gradients.rb} +1 -1
  146. data/samples/config_text_markup.rb +2 -2
  147. data/samples/custom-config.yml +5 -5
  148. data/samples/custom_config.rb +18 -18
  149. data/samples/{csv_import.rb → data/_csv.rb} +8 -1
  150. data/samples/{excel.rb → data/_excel.rb} +3 -3
  151. data/samples/embed_text.rb +21 -0
  152. data/samples/hello_world.rb +1 -1
  153. data/samples/{load_images.rb → images/_more_load_images.rb} +2 -2
  154. data/samples/layouts.rb +11 -1
  155. data/samples/layouts_builtin.rb +51 -51
  156. data/samples/offset.svg +71 -71
  157. data/samples/ranges.rb +7 -7
  158. data/samples/{hand.rb → saves/_hand.rb} +1 -2
  159. data/samples/{portrait-landscape.rb → saves/_portrait_landscape.rb} +4 -4
  160. data/samples/{saves.rb → saves/_saves.rb} +0 -0
  161. data/samples/{showcase.rb → saves/_showcase.rb} +2 -2
  162. data/samples/{draw_shapes.rb → shapes/_draw_shapes.rb} +1 -1
  163. data/samples/text/_text.rb +4 -3
  164. data/samples/text_options.rb +6 -6
  165. data/samples/unicode.rb +1 -1
  166. data/spec/api/api_data_spec.rb +59 -4
  167. data/spec/api/api_settings_spec.rb +1 -1
  168. data/spec/args/box_spec.rb +7 -7
  169. data/spec/args/draw_spec.rb +19 -19
  170. data/spec/args/embed_key_spec.rb +13 -13
  171. data/spec/args/input_file_spec.rb +2 -2
  172. data/spec/args/paint_spec.rb +5 -5
  173. data/spec/args/paragraph_spec.rb +28 -28
  174. data/spec/args/range_spec.rb +1 -1
  175. data/spec/args/save_batch_spec.rb +10 -10
  176. data/spec/args/scale_box_spec.rb +9 -9
  177. data/spec/args/sheet_spec.rb +8 -8
  178. data/spec/args/showcase_special_spec.rb +15 -15
  179. data/spec/args/transform_spec.rb +4 -4
  180. data/spec/args/typographer_spec.rb +11 -11
  181. data/spec/args/unit_conversion_spec.rb +2 -2
  182. data/spec/card_spec.rb +1 -1
  183. data/spec/commands/new_spec.rb +1 -1
  184. data/spec/data/csv/custom_opts.csv +2 -0
  185. data/spec/data/csv/newline.csv +3 -0
  186. data/spec/data/csv/qty.csv +2 -2
  187. data/spec/data/csv/qty_named.csv +2 -2
  188. data/spec/data/csv/with_spaces.csv +2 -2
  189. data/spec/data/csv/yield.csv +3 -0
  190. data/spec/data/samples/{autoscale_font.rb.txt → autoscale_font/_autoscale_font.rb.txt} +55 -18
  191. data/spec/data/samples/cairo_access.rb.txt +24 -0
  192. data/spec/data/samples/{gradients.rb.txt → colors/_gradients.rb.txt} +0 -0
  193. data/spec/data/samples/config_text_markup.rb.txt +72 -72
  194. data/spec/data/samples/custom_config.rb.txt +1 -0
  195. data/spec/data/samples/{csv_import.rb.txt → data/_csv.rb.txt} +0 -0
  196. data/spec/data/samples/{excel.rb.txt → data/_excel.rb.txt} +0 -0
  197. data/spec/data/samples/embed_text.rb.txt +79 -0
  198. data/spec/data/samples/hello_world.rb.txt +36 -36
  199. data/spec/data/samples/{load_images.rb.txt → images/_more_load_images.rb.txt} +4 -4
  200. data/spec/data/samples/{hand.rb.txt → saves/_hand.rb.txt} +0 -0
  201. data/spec/data/samples/{portrait-landscape.rb.txt → saves/_portrait_landscape.rb.txt} +11 -7
  202. data/spec/data/samples/{save_pdf.rb.txt → saves/_save_pdf.rb.txt} +0 -0
  203. data/spec/data/samples/{saves.rb.txt → saves/_saves.rb.txt} +3 -4
  204. data/spec/data/samples/{showcase.rb.txt → saves/_showcase.rb.txt} +0 -0
  205. data/spec/data/samples/{draw_shapes.rb.txt → shapes/_draw_shapes.rb.txt} +0 -0
  206. data/spec/data/samples/text_options.rb.txt +1125 -1125
  207. data/spec/graphics/cairo_context_wrapper_spec.rb +10 -10
  208. data/spec/graphics/graphics_save_doc_spec.rb +11 -5
  209. data/spec/layout_parser_spec.rb +21 -9
  210. data/spec/logger_spec.rb +2 -2
  211. data/spec/samples/run_samples_spec.rb +1 -1
  212. data/spec/samples/samples_regression_spec.rb +16 -18
  213. data/spec/samples/sanity.rb +9 -9
  214. data/spec/sanity/.gitignore +1 -0
  215. data/spec/sanity/sanity.html.erb +42 -0
  216. data/spec/sanity/sanity_test.rb +42 -0
  217. data/spec/sanity/tests.yml +12 -0
  218. data/spec/spec_helper.rb +22 -20
  219. data/squib.gemspec +3 -4
  220. metadata +143 -81
  221. data/.rspec +0 -1
  222. data/.yardopts +0 -10
  223. data/samples/autoscale_font.rb +0 -27
  224. data/samples/backend-config.yml +0 -5
  225. data/samples/color_shortcuts.rb +0 -6
  226. data/samples/explode_quantities.xlsx +0 -0
  227. data/samples/quantity_explosion.csv +0 -3
  228. data/samples/sample.csv +0 -3
  229. data/samples/sample.xlsx +0 -0
  230. data/squib.sublime-project +0 -42
@@ -32,7 +32,7 @@ describe Squib::Graphics::CairoContextWrapper do
32
32
  before(:each) do
33
33
  dbl = double(Cairo::LinearPattern)
34
34
  mtx = double(Cairo::Matrix)
35
- expect(Cairo::LinearPattern).to receive(:new).with(1,2,3,4).and_return(dbl)
35
+ expect(Cairo::LinearPattern).to receive(:new).with(1, 2, 3, 4).and_return(dbl)
36
36
  expect(dbl).to receive(:add_color_stop).with(0.0, 'blue')
37
37
  expect(dbl).to receive(:add_color_stop).with(1.0, 'red')
38
38
  expect(cairo).to receive(:matrix).and_return(mtx)
@@ -40,17 +40,17 @@ describe Squib::Graphics::CairoContextWrapper do
40
40
  expect(cairo).to receive(:set_source).with(dbl)
41
41
  end
42
42
 
43
- it('handles no decimals' ) { subject.set_source_squibcolor('(1,2) (3,4) blue@0 red@1') }
44
- it('handles decimals' ) { subject.set_source_squibcolor('(1.0,2.0) (3.0,4.0) blue@0 red@1') }
43
+ it('handles no decimals') { subject.set_source_squibcolor('(1,2) (3,4) blue@0 red@1') }
44
+ it('handles decimals') { subject.set_source_squibcolor('(1.0,2.0) (3.0,4.0) blue@0 red@1') }
45
45
  it('handles no whitespace') { subject.set_source_squibcolor('(1,2)(3,4)blue@0red@1') }
46
- it('handles whitespace' ) { subject.set_source_squibcolor(' ( 1 , 2 ) ( 3 , 4 ) blue@0 red@1 ') }
46
+ it('handles whitespace') { subject.set_source_squibcolor(' ( 1 , 2 ) ( 3 , 4 ) blue@0 red@1 ') }
47
47
  end
48
48
 
49
49
  context 'regex variations for radial gradients' do
50
50
  before(:each) do
51
51
  dbl = double(Cairo::RadialPattern)
52
52
  mtx = double(Cairo::Matrix)
53
- expect(Cairo::RadialPattern).to receive(:new).with(1,2,5,3,4,6).and_return(dbl)
53
+ expect(Cairo::RadialPattern).to receive(:new).with(1, 2, 5, 3, 4, 6).and_return(dbl)
54
54
  expect(dbl).to receive(:add_color_stop).with(0.0, 'blue')
55
55
  expect(dbl).to receive(:add_color_stop).with(1.0, 'red')
56
56
  expect(cairo).to receive(:matrix).and_return(mtx)
@@ -58,17 +58,17 @@ describe Squib::Graphics::CairoContextWrapper do
58
58
  expect(cairo).to receive(:set_source).with(dbl)
59
59
  end
60
60
 
61
- it('handles no decimals' ) { subject.set_source_squibcolor('(1,2,5) (3,4,6) blue@0 red@1') }
62
- it('handles decimals' ) { subject.set_source_squibcolor('(1.0,2.0,5.0) (3.0,4.0,6.0) blue@0 red@1') }
61
+ it('handles no decimals') { subject.set_source_squibcolor('(1,2,5) (3,4,6) blue@0 red@1') }
62
+ it('handles decimals') { subject.set_source_squibcolor('(1.0,2.0,5.0) (3.0,4.0,6.0) blue@0 red@1') }
63
63
  it('handles no whitespace') { subject.set_source_squibcolor('(1,2,5)(3,4,6)blue@0red@1') }
64
- it('handles whitespace' ) { subject.set_source_squibcolor(' ( 1 , 2 , 5 ) ( 3 , 4 , 6 ) blue@0 red@1 ') }
64
+ it('handles whitespace') { subject.set_source_squibcolor(' ( 1 , 2 , 5 ) ( 3 , 4 , 6 ) blue@0 red@1 ') }
65
65
  end
66
66
 
67
67
  context 'regex handles hash notation' do
68
68
  it 'on radial patterns' do
69
69
  dbl = double(Cairo::RadialPattern)
70
70
  mtx = double(Cairo::Matrix)
71
- expect(Cairo::RadialPattern).to receive(:new).with(1,2,5,3,4,6).and_return(dbl)
71
+ expect(Cairo::RadialPattern).to receive(:new).with(1, 2, 5, 3, 4, 6).and_return(dbl)
72
72
  expect(dbl).to receive(:add_color_stop).with(0.0, '#def')
73
73
  expect(dbl).to receive(:add_color_stop).with(1.0, '#112233')
74
74
  expect(cairo).to receive(:matrix).and_return(mtx)
@@ -80,7 +80,7 @@ describe Squib::Graphics::CairoContextWrapper do
80
80
  it 'on linear patterns' do
81
81
  dbl = double(Cairo::LinearPattern)
82
82
  mtx = double(Cairo::Matrix)
83
- expect(Cairo::LinearPattern).to receive(:new).with(1,2,3,4).and_return(dbl)
83
+ expect(Cairo::LinearPattern).to receive(:new).with(1, 2, 3, 4).and_return(dbl)
84
84
  expect(dbl).to receive(:add_color_stop).with(0.0, '#def')
85
85
  expect(dbl).to receive(:add_color_stop).with(1.0, '#112233')
86
86
  expect(cairo).to receive(:matrix).and_return(mtx)
@@ -4,7 +4,8 @@ require 'squib'
4
4
  describe Squib::Deck, '#save_pdf' do
5
5
 
6
6
  context 'typical inputs' do
7
- let(:cxt) { double(Cairo::Context) }
7
+ let(:cxt) { double(Cairo::Context) }
8
+ let(:target) { double(Cairo::PDFSurface) }
8
9
 
9
10
  def expect_card_place(x, y)
10
11
  expect(cxt).to receive(:translate).with(x, y).once
@@ -13,12 +14,12 @@ describe Squib::Deck, '#save_pdf' do
13
14
  expect(cxt).to receive(:set_source) # place the card
14
15
  .with(instance_of(Cairo::ImageSurface), 0, 0).once
15
16
  expect(cxt).to receive(:paint).once # paint placed card
16
- expect(cxt).to receive(:translate).with(-x,-y).once
17
+ expect(cxt).to receive(:translate).with(-x, -y).once
17
18
  expect(cxt).to receive(:reset_clip).once
18
19
  end
19
20
 
20
21
  before(:each) do
21
- allow(Cairo::PDFSurface).to receive(:new).and_return(nil) #don't create the file
22
+ allow(Cairo::PDFSurface).to receive(:new).and_return(nil) # don't create the file
22
23
  allow(Cairo::Context).to receive(:new).and_return(cxt)
23
24
  allow(cxt).to receive(:antialias=)
24
25
  end
@@ -27,7 +28,7 @@ describe Squib::Deck, '#save_pdf' do
27
28
  num_cards = 9
28
29
  deck = Squib::Deck.new(cards: 9, width: 825, height: 1125)
29
30
  expect(Squib.logger).to receive(:debug).at_least(:once)
30
- expect(Squib.logger).to receive(:warn).exactly(:once) #warn about making the dir
31
+ expect(Squib.logger).to receive(:warn).exactly(:once) # warn about making the dir
31
32
  expect(Dir).to receive(:mkdir) {} # don't actually make the dir
32
33
  expect(cxt).to receive(:scale).with(0.24, 0.24)
33
34
 
@@ -41,6 +42,8 @@ describe Squib::Deck, '#save_pdf' do
41
42
  expect_card_place(2343, 1131)
42
43
  expect(cxt).to receive(:show_page).once
43
44
  expect_card_place(75, 75)
45
+ expect(cxt).to receive(:target).and_return(target)
46
+ expect(target).to receive(:finish).once
44
47
 
45
48
  args = { file: 'foo.pdf', dir: '_out', margin: 75, gap: 5, trim: 37 }
46
49
  deck.save_pdf(args)
@@ -51,7 +54,7 @@ describe Squib::Deck, '#save_pdf' do
51
54
  args = { range: 2..4, file: 'foo.pdf', dir: '_out', margin: 75, gap: 5, trim: 37 }
52
55
  deck = Squib::Deck.new(cards: num_cards, width: 825, height: 1125)
53
56
  expect(Squib.logger).to receive(:debug).at_least(:once)
54
- expect(Squib.logger).to receive(:warn).exactly(:once) #warn about making the dir
57
+ expect(Squib.logger).to receive(:warn).exactly(:once) # warn about making the dir
55
58
  expect(Dir).to receive(:mkdir) {} # don't actually make the dir
56
59
  expect(cxt).to receive(:scale).with(0.24, 0.24)
57
60
 
@@ -59,6 +62,9 @@ describe Squib::Deck, '#save_pdf' do
59
62
  expect_card_place(831, 75)
60
63
  expect_card_place(1587, 75)
61
64
 
65
+ expect(cxt).to receive(:target).and_return(target)
66
+ expect(target).to receive(:finish).once
67
+
62
68
  deck.save_pdf(args)
63
69
  end
64
70
 
@@ -4,7 +4,7 @@ describe Squib::LayoutParser do
4
4
 
5
5
  it 'loads a normal layout with no extends' do
6
6
  layout = Squib::LayoutParser.load_layout(layout_file('no-extends.yml'))
7
- expect(layout).to eq({'frame' => {
7
+ expect(layout).to eq({ 'frame' => {
8
8
  'x' => 38,
9
9
  'valign' => :middle,
10
10
  'str' => 'blah',
@@ -16,7 +16,7 @@ describe Squib::LayoutParser do
16
16
 
17
17
  it 'loads with a single extends' do
18
18
  layout = Squib::LayoutParser.load_layout(layout_file('single-extends.yml'))
19
- expect(layout).to eq({'frame' => {
19
+ expect(layout).to eq({ 'frame' => {
20
20
  'x' => 38,
21
21
  'y' => 38,
22
22
  },
@@ -32,7 +32,7 @@ describe Squib::LayoutParser do
32
32
 
33
33
  it 'applies the extends regardless of order' do
34
34
  layout = Squib::LayoutParser.load_layout(layout_file('pre-extends.yml'))
35
- expect(layout).to eq({'frame' => {
35
+ expect(layout).to eq({ 'frame' => {
36
36
  'x' => 38,
37
37
  'y' => 38,
38
38
  },
@@ -48,7 +48,7 @@ describe Squib::LayoutParser do
48
48
 
49
49
  it 'applies the single-level extends multiple times' do
50
50
  layout = Squib::LayoutParser.load_layout(layout_file('single-level-multi-extends.yml'))
51
- expect(layout).to eq({'frame' => {
51
+ expect(layout).to eq({ 'frame' => {
52
52
  'x' => 38,
53
53
  'y' => 38,
54
54
  },
@@ -70,7 +70,7 @@ describe Squib::LayoutParser do
70
70
 
71
71
  it 'applies multiple extends in a single rule' do
72
72
  layout = Squib::LayoutParser.load_layout(layout_file('multi-extends-single-entry.yml'))
73
- expect(layout).to eq({'aunt' => {
73
+ expect(layout).to eq({ 'aunt' => {
74
74
  'a' => 101,
75
75
  'b' => 102,
76
76
  'c' => 103,
@@ -81,7 +81,7 @@ describe Squib::LayoutParser do
81
81
  'b' => 106,
82
82
  },
83
83
  'child' => {
84
- 'extends' => ['uncle','aunt'],
84
+ 'extends' => ['uncle', 'aunt'],
85
85
  'a' => 107, # my own
86
86
  'b' => 102, # from the younger aunt
87
87
  'c' => 103, # from aunt
@@ -94,7 +94,7 @@ describe Squib::LayoutParser do
94
94
 
95
95
  it 'applies multi-level extends' do
96
96
  layout = Squib::LayoutParser.load_layout(layout_file('multi-level-extends.yml'))
97
- expect(layout).to eq({'frame' => {
97
+ expect(layout).to eq({ 'frame' => {
98
98
  'x' => 38,
99
99
  'y' => 38,
100
100
  },
@@ -179,11 +179,23 @@ describe Squib::LayoutParser do
179
179
  .with("Processing layout: 'verbal' attempts to extend a missing 'kaisersoze'")
180
180
  layout = Squib::LayoutParser.load_layout(layout_file('extends-nonexists.yml'))
181
181
  expect(layout).to eq({
182
- 'verbal' => {
182
+ 'verbal' => {
183
183
  'font_size' => 25,
184
184
  'extends' => 'kaisersoze'
185
185
  }
186
186
  })
187
187
  end
188
188
 
189
- end
189
+ it 'loads progressively on multiple calls' do
190
+ a = layout_file('multifile-a.yml')
191
+ b = layout_file('multifile-b.yml')
192
+ layout = Squib::LayoutParser.load_layout(a)
193
+ layout = Squib::LayoutParser.load_layout(b, layout)
194
+ expect(layout).to eq({
195
+ 'title' => { 'x' => 300 },
196
+ 'subtitle' => { 'x' => 200 },
197
+ 'desc' => { 'x' => 400 }
198
+ })
199
+ end
200
+
201
+ end
data/spec/logger_spec.rb CHANGED
@@ -5,8 +5,8 @@ describe Squib.logger do
5
5
  Squib.logger = nil
6
6
  oldstdout = $stdout
7
7
  $stdout = StringIO.new
8
- Squib::logger.warn "Test warn"
8
+ Squib::logger.warn 'Test warn'
9
9
  expect($stdout.string).to match /WARN: Test warn/
10
10
  $stdout = oldstdout
11
11
  end
12
- end
12
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'squib'
3
3
  require 'pp'
4
4
 
5
- describe "Squib samples" do
5
+ describe 'Squib samples' do
6
6
 
7
7
  Dir["#{samples_dir}/**/*.rb"].each do |sample|
8
8
  it "executes #{sample} with no errors", slow: true do
@@ -2,13 +2,7 @@ require 'spec_helper'
2
2
  require 'squib'
3
3
  require 'pp'
4
4
 
5
- describe "Squib samples" do
6
-
7
- around(:each) do |example|
8
- Dir.chdir(samples_dir) do
9
- example.run
10
- end
11
- end
5
+ describe 'Squib samples' do
12
6
 
13
7
  # This test could use some explanation
14
8
  # Much of the development of Squib has been sample-driven. Every time I want
@@ -38,23 +32,24 @@ describe "Squib samples" do
38
32
  # These are samples that don't really need a regression log
39
33
  # colors.rb
40
34
  # unicode.rb
41
- %w( autoscale_font.rb
35
+ %w(
36
+ autoscale_font/_autoscale_font.rb
42
37
  basic.rb
43
38
  cairo_access.rb
44
- csv_import.rb
39
+ colors/_gradients.rb
45
40
  config_text_markup.rb
46
41
  custom_config.rb
47
- draw_shapes.rb
42
+ data/_csv.rb
43
+ data/_excel.rb
48
44
  embed_text.rb
49
- excel.rb
50
- gradients.rb
51
- hand.rb
52
45
  hello_world.rb
53
- load_images.rb
54
- portrait-landscape.rb
46
+ images/_more_load_images.rb
55
47
  ranges.rb
56
- saves.rb
57
- showcase.rb
48
+ saves/_hand.rb
49
+ saves/_portrait_landscape.rb
50
+ saves/_saves.rb
51
+ saves/_showcase.rb
52
+ shapes/_draw_shapes.rb
58
53
  text_options.rb
59
54
  tgc_proofs.rb
60
55
  units.rb
@@ -62,7 +57,10 @@ describe "Squib samples" do
62
57
  it "has not changed for #{sample}", slow: true do
63
58
  log = StringIO.new
64
59
  mock_cairo(log)
65
- load sample
60
+ full_sample_path = File.expand_path "#{samples_dir}/#{sample}"
61
+ Dir.chdir(File.dirname("#{samples_dir}/#{sample}")) do
62
+ load full_sample_path
63
+ end
66
64
  # overwrite_sample(sample, log) # Use TEMPORARILY once happy with the new sample log
67
65
  test_file_str = File.open(sample_regression_file(sample), 'r:UTF-8').read
68
66
  expect(log.string).to eq(test_file_str)
@@ -14,14 +14,14 @@ class Sanity
14
14
 
15
15
  def images
16
16
  images = []
17
- exp_pngs = Dir[@@EXPECTED_DIR + "/**/*.png"]
17
+ exp_pngs = Dir[@@EXPECTED_DIR + '/**/*.png']
18
18
  bar = ProgressBar.create(title: 'Diffing images', total: exp_pngs.size)
19
19
  exp_pngs.each do |exp_png|
20
20
  row = []
21
21
  actual_png = @@OUTPUT_DIR + File.basename(exp_png)
22
- row << "file:///" + exp_png
23
- row << "file:///" + actual_png #actual
24
- row << "file:///" + diff_image(exp_png, actual_png)
22
+ row << 'file:///' + exp_png
23
+ row << 'file:///' + actual_png # actual
24
+ row << 'file:///' + diff_image(exp_png, actual_png)
25
25
  images << row
26
26
  bar.increment
27
27
  end
@@ -30,11 +30,11 @@ class Sanity
30
30
  end
31
31
 
32
32
  def run
33
- puts "Building sanity test..."
33
+ puts 'Building sanity test...'
34
34
  sanity_template = File.read(@@SANITY_ERB)
35
35
  process_erb(sanity_template)
36
- Launchy.open("file:///" + @@SANITY_HTML)
37
- puts "Done."
36
+ Launchy.open('file:///' + @@SANITY_HTML)
37
+ puts 'Done.'
38
38
  end
39
39
 
40
40
  private
@@ -51,7 +51,7 @@ class Sanity
51
51
  end
52
52
  end
53
53
  out = Cairo::ImageSurface.new(new_data.pack('c*'), exp.format, exp.width, exp.height, exp.stride)
54
- out_file = @@DIFF_DIR + exp_file[exp_file.rindex("/")..-1]
54
+ out_file = @@DIFF_DIR + exp_file[exp_file.rindex('/')..-1]
55
55
  out.write_to_png(out_file)
56
56
  out_file
57
57
  end
@@ -67,4 +67,4 @@ class Sanity
67
67
  end
68
68
  end
69
69
 
70
- end
70
+ end
@@ -0,0 +1 @@
1
+ sanity.html
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width">
5
+ <meta charset="utf-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7
+ <title>Diff with CSS Example</title>
8
+ <style>
9
+ body{
10
+ /*background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAHElEQVQYlWO4ePFiAzGY4eLFiw0MxIBRhVRRCADsljgKUbBKPgAAAABJRU5ErkJggg==) repeat;*/
11
+ }
12
+ img{
13
+ height: 6in;
14
+ }
15
+ .diff {
16
+ width: 4in;
17
+ height: 6in;
18
+ background-repeat: none, none;
19
+ background-size: contain, contain;
20
+ background-blend-mode: difference;
21
+ display: inline-block;
22
+ }
23
+
24
+ </style>
25
+ </head>
26
+ <body>
27
+
28
+ <% images.each_with_index do |(expected, actual), i| %>
29
+
30
+ <img src="<%= expected %>"/>
31
+ <img src="<%= actual %>"/>
32
+ <style>
33
+ .mine<%= i %> {
34
+ background-image: url(<%= expected %>), url(<%= actual %>);"
35
+ }
36
+ </style>
37
+ <div class="diff mine<%= i %>"/>
38
+
39
+ <% end %>
40
+
41
+ </body>
42
+ </html>
@@ -0,0 +1,42 @@
1
+ require 'launchy'
2
+ require 'erb'
3
+ require 'yaml'
4
+
5
+ # An pixel-by-pixel comparison of sample images for visual regression testing
6
+ class SanityTest
7
+
8
+ @@ERB = "#{File.expand_path(File.dirname(__FILE__))}/sanity.html.erb"
9
+ @@HTML = "#{File.expand_path(File.dirname(__FILE__))}/sanity.html"
10
+ @@COMPARES = "#{File.expand_path(File.dirname(__FILE__))}/tests.yml"
11
+ @@SAMPLES = "file:///#{File.expand_path("samples/")}"
12
+
13
+ def images
14
+ require 'pp'
15
+ comps = YAML.load_file(@@COMPARES)
16
+ pp comps
17
+ comps.each do | test, data |
18
+ pp data
19
+ end
20
+ [
21
+ ["#{@@SAMPLES}/images/_images_00_expected.png", "#{@@SAMPLES}/images/_images_00.png"]
22
+ ]
23
+ end
24
+
25
+ def run
26
+ puts @@SAMPLES
27
+ puts 'Building sanity test...'
28
+ process_erb(File.read(@@ERB))
29
+ Launchy.open('file:///' + @@HTML)
30
+ puts 'Done.'
31
+ end
32
+
33
+ private
34
+
35
+ def process_erb(sanity_template)
36
+ renderer = ERB.new(sanity_template)
37
+ File.open(@@HTML, 'w+') do |html|
38
+ html.write(renderer.result(binding))
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,12 @@
1
+ images:
2
+ dir: images
3
+ expected: _images_00_expected.png
4
+ actual: _images_00.png
5
+ text:
6
+ dir: text
7
+ expected: _text_00_expected.png
8
+ actual: _text_00.png
9
+ autoscale_font:
10
+ dir: autoscale_font
11
+ expected: card_00_expected.png
12
+ actual: card_00.png
data/spec/spec_helper.rb CHANGED
@@ -2,10 +2,10 @@ require 'simplecov'
2
2
  require 'coveralls'
3
3
  # require 'byebug'
4
4
 
5
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
6
6
  SimpleCov::Formatter::HTMLFormatter,
7
7
  Coveralls::SimpleCov::Formatter
8
- ]
8
+ ])
9
9
  SimpleCov.start
10
10
 
11
11
  require 'squib'
@@ -14,6 +14,8 @@ RSpec.configure do |config|
14
14
  config.mock_with :rspec do |mocks|
15
15
  mocks.verify_partial_doubles = true
16
16
  end
17
+ config.tty = true
18
+ config.color = true
17
19
  end
18
20
 
19
21
  def tmp_dir
@@ -60,17 +62,17 @@ def overwrite_sample(sample_name, log)
60
62
  end
61
63
 
62
64
  def scrub_hex(str)
63
- str.gsub(/0x\w{1,8}/,'')
64
- .gsub(/ptr=\w{1,8}/,'')
65
- .gsub(/#<Pango::FontDescription:.*>/,'')
66
- .gsub(/#<Cairo::ImageSurface:.*>/,'ImageSurface')
67
- .gsub(/#<Cairo::LinearPattern:.*>/,'LinearPattern')
68
- .gsub(/#<Cairo::RadialPattern:.*>/,'RadialPattern')
69
- .gsub(/#<Cairo::Matrix:.*>/,'Matrix')
70
- .gsub(/#<RSVG::Handle.*>/,'RSVG::Handle')
71
- .gsub(/#<RSpec::Mocks::Double:.*>/,'MockDouble')
72
- .gsub(/#<Double .*>/,'MockDouble')
73
- .gsub(/RGB:\w{1,8}/,'RGB:')
65
+ str.gsub(/0x\w{1,8}/, '')
66
+ .gsub(/ptr=\w{1,8}/, '')
67
+ .gsub(/#<Pango::FontDescription:.*>/, '')
68
+ .gsub(/#<Cairo::ImageSurface:.*>/, 'ImageSurface')
69
+ .gsub(/#<Cairo::LinearPattern:.*>/, 'LinearPattern')
70
+ .gsub(/#<Cairo::RadialPattern:.*>/, 'RadialPattern')
71
+ .gsub(/#<Cairo::Matrix:.*>/, 'Matrix')
72
+ .gsub(/#<RSVG::Handle.*>/, 'RSVG::Handle')
73
+ .gsub(/#<RSpec::Mocks::Double:.*>/, 'MockDouble')
74
+ .gsub(/#<Double .*>/, 'MockDouble')
75
+ .gsub(/RGB:\w{1,8}/, 'RGB:')
74
76
  end
75
77
 
76
78
  # Build a mock cairo instance that allows basically any method
@@ -88,22 +90,22 @@ def mock_cairo(strio)
88
90
  allow(Cairo::ImageSurface).to receive(:new).and_return(surface)
89
91
  allow(surface).to receive(:width).and_return(100)
90
92
  allow(surface).to receive(:height).and_return(101)
91
- allow(surface).to receive(:ink_extents).and_return([0,0,100,100])
93
+ allow(surface).to receive(:ink_extents).and_return([0, 0, 100, 100])
92
94
  allow(Cairo::Context).to receive(:new).and_return(cxt)
93
95
  allow(cxt).to receive(:create_pango_layout).and_return(pango)
94
96
  allow(cxt).to receive(:target).and_return(surface)
95
- allow(cxt).to receive(:matrix).and_return(Cairo::Matrix.new(1,0,0,1,0,0))
97
+ allow(cxt).to receive(:matrix).and_return(Cairo::Matrix.new(1, 0, 0, 1, 0, 0))
96
98
  allow(pango).to receive(:height).and_return(25)
97
99
  allow(pango).to receive(:width).and_return(25)
98
- allow(pango).to receive(:index_to_pos).and_return(Pango::Rectangle.new(0,0,0,0))
99
- allow(pango).to receive(:extents).and_return([Pango::Rectangle.new(0,0,0,0)]*2)
100
+ allow(pango).to receive(:index_to_pos).and_return(Pango::Rectangle.new(0, 0, 0, 0))
101
+ allow(pango).to receive(:extents).and_return([Pango::Rectangle.new(0, 0, 0, 0)] * 2)
100
102
  allow(pango).to receive(:iter).and_return(iter)
101
103
  allow(pango).to receive(:alignment).and_return(Pango::Layout::Alignment::LEFT)
102
- allow(pango).to receive(:text).and_return("foo")
104
+ allow(pango).to receive(:text).and_return('foo')
103
105
  allow(pango).to receive(:context).and_return(pango_cxt)
104
106
  allow(pango_cxt).to receive(:font_options=)
105
107
  allow(iter).to receive(:next_char!).and_return(false)
106
- allow(iter).to receive(:char_extents).and_return(Pango::Rectangle.new(5,5,5,5))
108
+ allow(iter).to receive(:char_extents).and_return(Pango::Rectangle.new(5, 5, 5, 5))
107
109
  allow(iter).to receive(:index).and_return(1000)
108
110
  allow(Pango::FontDescription).to receive(:new).and_return(font)
109
111
  allow(Cairo::PDFSurface).to receive(:new).and_return(nil)
@@ -126,7 +128,7 @@ def mock_cairo(strio)
126
128
  allow(font).to receive(m) { |*args| strio << scrub_hex("pango font: #{m}(#{args})\n") }
127
129
  end
128
130
 
129
- %w(write_to_png).each do |m|
131
+ %w(write_to_png finish).each do |m|
130
132
  allow(surface).to receive(m) { |*args| strio << scrub_hex("surface: #{m}(#{args})\n") }
131
133
  end
132
134