squib 0.6.0 → 0.7.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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +162 -133
  3. data/Gemfile +4 -4
  4. data/README.md +630 -550
  5. data/RELEASE TODO.md +18 -18
  6. data/Rakefile +99 -99
  7. data/lib/squib.rb +32 -32
  8. data/lib/squib/api/background.rb +20 -19
  9. data/lib/squib/api/data.rb +100 -99
  10. data/lib/squib/api/image.rb +90 -76
  11. data/lib/squib/api/save.rb +149 -103
  12. data/lib/squib/api/settings.rb +35 -37
  13. data/lib/squib/api/shapes.rb +230 -228
  14. data/lib/squib/api/text.rb +65 -66
  15. data/lib/squib/api/text_embed.rb +96 -66
  16. data/lib/squib/args/arg_loader.rb +138 -0
  17. data/lib/squib/args/box.rb +55 -0
  18. data/lib/squib/args/card_range.rb +32 -0
  19. data/lib/squib/args/color_validator.rb +12 -0
  20. data/lib/squib/args/coords.rb +33 -0
  21. data/lib/squib/args/dir_validator.rb +16 -0
  22. data/lib/squib/args/draw.rb +92 -0
  23. data/lib/squib/args/embed_adjust.rb +25 -0
  24. data/lib/squib/args/embed_key.rb +17 -0
  25. data/lib/squib/args/hand_special.rb +37 -0
  26. data/lib/squib/args/input_file.rb +37 -0
  27. data/lib/squib/args/paint.rb +44 -0
  28. data/lib/squib/args/paragraph.rb +115 -0
  29. data/lib/squib/args/save_batch.rb +60 -0
  30. data/lib/squib/args/scale_box.rb +53 -0
  31. data/lib/squib/args/sheet.rb +72 -0
  32. data/lib/squib/args/showcase_special.rb +38 -0
  33. data/lib/squib/args/svg_special.rb +37 -0
  34. data/lib/squib/args/transform.rb +25 -0
  35. data/lib/squib/args/typographer.rb +117 -117
  36. data/lib/squib/card.rb +67 -67
  37. data/lib/squib/conf.rb +117 -111
  38. data/lib/squib/constants.rb +178 -178
  39. data/lib/squib/deck.rb +113 -111
  40. data/lib/squib/graphics/cairo_context_wrapper.rb +99 -53
  41. data/lib/squib/graphics/gradient_regex.rb +46 -46
  42. data/lib/squib/graphics/hand.rb +42 -43
  43. data/lib/squib/graphics/image.rb +76 -73
  44. data/lib/squib/graphics/save_doc.rb +103 -137
  45. data/lib/squib/graphics/save_images.rb +33 -33
  46. data/lib/squib/graphics/shapes.rb +119 -152
  47. data/lib/squib/graphics/showcase.rb +85 -88
  48. data/lib/squib/graphics/text.rb +176 -216
  49. data/lib/squib/layout_parser.rb +91 -89
  50. data/lib/squib/layouts/economy.yml +85 -0
  51. data/lib/squib/layouts/fantasy.yml +101 -0
  52. data/lib/squib/layouts/hand.yml +62 -46
  53. data/lib/squib/layouts/playing-card.yml +35 -18
  54. data/lib/squib/project_template/config.yml +45 -40
  55. data/lib/squib/version.rb +10 -10
  56. data/samples/color_shortcuts.rb +6 -0
  57. data/samples/csv_import.rb +18 -18
  58. data/samples/custom-config.yml +5 -5
  59. data/samples/custom_config.rb +18 -18
  60. data/samples/draw_shapes.rb +45 -35
  61. data/samples/embed_text.rb +88 -90
  62. data/samples/hand.rb +24 -24
  63. data/samples/layouts.rb +62 -61
  64. data/samples/layouts_builtin.rb +51 -0
  65. data/samples/load_images.rb +78 -64
  66. data/samples/ranges.rb +64 -53
  67. data/samples/sample.csv +2 -2
  68. data/samples/text_options.rb +102 -94
  69. data/spec/api/api_data_spec.rb +57 -50
  70. data/spec/api/api_settings_spec.rb +37 -17
  71. data/spec/args/box_spec.rb +127 -0
  72. data/spec/args/draw_spec.rb +95 -0
  73. data/spec/args/embed_key_spec.rb +13 -0
  74. data/spec/args/input_file_spec.rb +21 -0
  75. data/spec/args/paint_spec.rb +22 -0
  76. data/spec/args/paragraph_spec.rb +153 -0
  77. data/spec/args/range_spec.rb +36 -0
  78. data/spec/args/save_batch_spec.rb +51 -0
  79. data/spec/args/scale_box_spec.rb +71 -0
  80. data/spec/args/sheet_spec.rb +58 -0
  81. data/spec/args/showcase_special_spec.rb +15 -0
  82. data/spec/data/samples/autoscale_font.rb.txt +84 -87
  83. data/spec/data/samples/basic.rb.txt +209 -203
  84. data/spec/data/samples/cairo_access.rb.txt +2 -2
  85. data/spec/data/samples/config_text_markup.rb.txt +72 -75
  86. data/spec/data/samples/csv_import.rb.txt +76 -80
  87. data/spec/data/samples/custom_config.rb.txt +48 -49
  88. data/spec/data/samples/draw_shapes.rb.txt +100 -42
  89. data/spec/data/samples/embed_text.rb.txt +283 -295
  90. data/spec/data/samples/excel.rb.txt +162 -171
  91. data/spec/data/samples/gradients.rb.txt +79 -67
  92. data/spec/data/samples/hand.rb.txt +538 -514
  93. data/spec/data/samples/hello_world.rb.txt +36 -38
  94. data/spec/data/samples/load_images.rb.txt +41 -5
  95. data/spec/data/samples/portrait-landscape.rb.txt +49 -51
  96. data/spec/data/samples/ranges.rb.txt +460 -429
  97. data/spec/data/samples/saves.rb.txt +801 -785
  98. data/spec/data/samples/showcase.rb.txt +5910 -5906
  99. data/spec/data/samples/text_options.rb.txt +1125 -981
  100. data/spec/data/samples/tgc_proofs.rb.txt +81 -79
  101. data/spec/data/samples/units.rb.txt +18 -12
  102. data/spec/data/xlsx/with_macros.xlsm +0 -0
  103. data/spec/graphics/cairo_context_wrapper_spec.rb +84 -75
  104. data/spec/graphics/graphics_images_spec.rb +94 -85
  105. data/spec/graphics/graphics_save_doc_spec.rb +67 -65
  106. data/spec/samples/expected/hand.png +0 -0
  107. data/spec/samples/expected/hand_pretty.png +0 -0
  108. data/spec/samples/expected/layout_00.png +0 -0
  109. data/spec/samples/expected/load_images_00.png +0 -0
  110. data/spec/samples/expected/ranges_00.png +0 -0
  111. data/spec/samples/expected/shape_00.png +0 -0
  112. data/spec/samples/expected/showcase.png +0 -0
  113. data/spec/samples/expected/showcase2.png +0 -0
  114. data/spec/samples/expected/showcase_individual_00.png +0 -0
  115. data/spec/samples/expected/showcase_individual_01.png +0 -0
  116. data/spec/samples/expected/showcase_individual_02.png +0 -0
  117. data/spec/samples/expected/showcase_individual_03.png +0 -0
  118. data/spec/samples/expected/text_00.png +0 -0
  119. data/spec/samples/expected/text_01.png +0 -0
  120. data/spec/samples/expected/text_02.png +0 -0
  121. data/spec/samples/samples_regression_spec.rb +82 -82
  122. data/spec/spec_helper.rb +3 -2
  123. data/squib.gemspec +48 -48
  124. data/squib.sublime-project +42 -36
  125. metadata +61 -33
  126. data/lib/squib/input_helpers.rb +0 -238
  127. data/spec/api/api_image_spec.rb +0 -38
  128. data/spec/api/api_text_spec.rb +0 -37
  129. data/spec/graphics/graphics_shapes_spec.rb +0 -85
  130. data/spec/graphics/graphics_text_spec.rb +0 -164
  131. data/spec/input_helpers_spec.rb +0 -238
  132. data/spec/samples/expected/embed_multi_00.png +0 -0
  133. data/spec/samples/expected/embed_multi_01.png +0 -0
  134. data/spec/samples/expected/embed_multi_02.png +0 -0
  135. data/spec/samples/expected/ranges_01.png +0 -0
  136. data/spec/samples/expected/ranges_02.png +0 -0
@@ -1,50 +1,57 @@
1
- require 'spec_helper'
2
-
3
- describe Squib::Deck do
4
- context '#csv' do
5
- it 'loads basic csv data' do
6
- expect(Squib.csv(file: csv_file('basic.csv'))).to eq({
7
- 'h1' => [1, 3],
8
- 'h2' => [2, 4]
9
- })
10
- end
11
-
12
- it 'collapses duplicate columns and warns' do
13
- expect(Squib.logger).to receive(:warn)
14
- .with('CSV duplicated the following column keys: h1,h1')
15
- expect(Squib.csv(file: csv_file('dup_cols.csv'))).to eq({
16
- 'h1' => [1, 3],
17
- 'h2' => [5, 7],
18
- 'H2' => [6, 8],
19
- 'h3' => [9, 10],
20
- })
21
- end
22
-
23
- it 'handles spaces properly' do
24
- expect(Squib.csv(file: csv_file('with_spaces.csv'))).to eq({
25
- 'With Spaces' => ['a b c ', 3],
26
- 'h2' => [2, 4],
27
- 'h3' => [3, nil]
28
- })
29
- end
30
- end
31
-
32
- context '#xlsx' do
33
- it 'loads basic xlsx data' do
34
- expect(Squib.xlsx(file: xlsx_file('basic.xlsx'))).to eq({
35
- 'Name' => %w(Larry Curly Mo),
36
- 'General Number' => %w(1 2 3), #general types always get loaded as strings with no conversion
37
- 'Actual Number' => [4.0, 5.0, 6.0], #numbers get auto-converted to integers
38
- })
39
- end
40
-
41
- it 'loads xlsx with formulas' do
42
- expect(Squib.xlsx(file: xlsx_file('formulas.xlsx'))).to eq({
43
- 'A' => %w(1 2),
44
- 'B' => %w(3 4),
45
- 'Sum' => %w(4 6),
46
- })
47
- end
48
-
49
- end
50
- end
1
+ require 'spec_helper'
2
+
3
+ describe Squib::Deck do
4
+ context '#csv' do
5
+ it 'loads basic csv data' do
6
+ expect(Squib.csv(file: csv_file('basic.csv'))).to eq({
7
+ 'h1' => [1, 3],
8
+ 'h2' => [2, 4]
9
+ })
10
+ end
11
+
12
+ it 'collapses duplicate columns and warns' do
13
+ expect(Squib.logger).to receive(:warn)
14
+ .with('CSV duplicated the following column keys: h1,h1')
15
+ expect(Squib.csv(file: csv_file('dup_cols.csv'))).to eq({
16
+ 'h1' => [1, 3],
17
+ 'h2' => [5, 7],
18
+ 'H2' => [6, 8],
19
+ 'h3' => [9, 10],
20
+ })
21
+ end
22
+
23
+ it 'handles spaces properly' do
24
+ expect(Squib.csv(file: csv_file('with_spaces.csv'))).to eq({
25
+ 'With Spaces' => ['a b c ', 3],
26
+ 'h2' => [2, 4],
27
+ 'h3' => [3, nil]
28
+ })
29
+ end
30
+ end
31
+
32
+ context '#xlsx' do
33
+ it 'loads basic xlsx data' do
34
+ expect(Squib.xlsx(file: xlsx_file('basic.xlsx'))).to eq({
35
+ 'Name' => %w(Larry Curly Mo),
36
+ 'General Number' => %w(1 2 3), #general types always get loaded as strings with no conversion
37
+ 'Actual Number' => [4.0, 5.0, 6.0], #numbers get auto-converted to integers
38
+ })
39
+ end
40
+
41
+ it 'loads xlsx with formulas' do
42
+ expect(Squib.xlsx(file: xlsx_file('formulas.xlsx'))).to eq({
43
+ 'A' => %w(1 2),
44
+ 'B' => %w(3 4),
45
+ 'Sum' => %w(4 6),
46
+ })
47
+ end
48
+
49
+ it 'loads xlsm files with macros' do
50
+ expect(Squib.xlsx(file: xlsx_file('with_macros.xlsm'))).to eq({
51
+ 'foo' => %w(8 10),
52
+ 'bar' => %w(9 11),
53
+ })
54
+ end
55
+
56
+ end
57
+ end
@@ -1,18 +1,38 @@
1
- require 'spec_helper'
2
-
3
- describe Squib::Deck do
4
-
5
- context '#hint' do
6
-
7
- it 'sets hinting to conf' do
8
- mock_conf = double(Squib::Conf)
9
- expect(mock_conf).to receive(:text_hint=).with(:cyan).once
10
- Squib::Deck.new do
11
- @conf = mock_conf
12
- hint text: :cyan
13
- end
14
- end
15
-
16
- end
17
-
1
+ require 'spec_helper'
2
+
3
+ describe Squib::Deck do
4
+
5
+ context '#hint' do
6
+
7
+ it 'sets hinting to conf' do
8
+ mock_conf = double(Squib::Conf)
9
+ expect(mock_conf).to receive(:text_hint=).with(:cyan).once
10
+ Squib::Deck.new do
11
+ @conf = mock_conf
12
+ hint text: :cyan
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ context '#set' do
19
+
20
+ it 'puts font in @font' do
21
+ deck = Squib::Deck.new do
22
+ set font: 'foo'
23
+ end
24
+ expect(deck.font).to eq ('foo')
25
+ end
26
+
27
+ it 'raises deprecation errors on img_dir' do
28
+ set_img_dir = Proc.new do
29
+ Squib::Deck.new do
30
+ set img_dir: 'foo'
31
+ end
32
+ end
33
+ expect { set_img_dir.call }.to raise_error('DEPRECATED: As of v0.7 img_dir is no longer supported in "set". Use config.yml instead.')
34
+ end
35
+
36
+ end
37
+
18
38
  end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+ require 'squib/args/box'
3
+
4
+ describe Squib::Args::Box do
5
+ subject(:box) { Squib::Args::Box.new }
6
+ let(:expected_defaults) { {x: [0], y: [0], width: [:deck], height: [:deck] } }
7
+
8
+ it 'intitially has no params set' do
9
+ expect(box).not_to respond_to(:x, :y, :width, :height)
10
+ end
11
+
12
+ it 'extracts the defaults from Box on an empty hash' do
13
+ box.load!({})
14
+ expect(box).to have_attributes(expected_defaults)
15
+ end
16
+
17
+ it 'extracts what is specified and fills in defaults from Box' do
18
+ box.load!(x: 4, width: 40)
19
+ expect(box).to have_attributes(x: [4], width: [40], y: [0], height: [:deck])
20
+ end
21
+
22
+ it 'extracts the defaults from Box on an empty hash' do
23
+ box.load!({foo: :bar})
24
+ expect(box).to have_attributes(expected_defaults)
25
+ expect(box).not_to respond_to(:foo)
26
+ end
27
+
28
+ context 'single expansion' do
29
+ let(:args) { {x: [1, 2], y: 3} }
30
+ before(:each) { box.load!(args, expand_by: 2) }
31
+ it 'expands box' do
32
+ expect(box).to have_attributes({
33
+ x: [1, 2],
34
+ y: [3, 3],
35
+ height: [:deck, :deck],
36
+ width: [:deck, :deck]
37
+ })
38
+ end
39
+
40
+ it 'gives access to each card too' do
41
+ expect(box[0]).to have_attributes({
42
+ x: 1,
43
+ y: 3,
44
+ height: :deck,
45
+ width: :deck
46
+ })
47
+ end
48
+ end
49
+
50
+ context 'layouts' do
51
+ let(:layout) do
52
+ { 'attack' => { 'x' => 50 },
53
+ 'defend' => { 'x' => 60 } }
54
+ end
55
+
56
+ it 'are used when not specified' do
57
+ args = { layout: ['attack', 'defend'] }
58
+ box.load!(args, expand_by: 2, layout: layout)
59
+ expect(box).to have_attributes(
60
+ x: [50, 60], # set by layout
61
+ y: [0, 0], # Box default
62
+ )
63
+ end
64
+
65
+ it 'handle single expansion' do
66
+ args = { layout: 'attack' }
67
+ box.load!(args, expand_by: 2, layout: layout)
68
+ expect(box).to have_attributes(
69
+ x: [50, 50], # set by layout
70
+ y: [0, 0], # Box default
71
+ )
72
+ end
73
+
74
+ it 'handles symbols' do
75
+ args = { layout: :attack }
76
+ box.load!(args, expand_by: 2, layout: layout)
77
+ expect(box).to have_attributes(
78
+ x: [50, 50], # set by layout
79
+ y: [0, 0], # Box default
80
+ )
81
+ end
82
+
83
+ it 'warns on non-existent layouts' do
84
+ args = { layout: :heal}
85
+ expect(Squib.logger).to receive(:warn).with('Layout "heal" does not exist in layout file - using default instead').at_least(:once)
86
+ box.load!(args, expand_by: 2, layout: layout)
87
+ expect(box).to have_attributes(
88
+ x: [0, 0], # Box default
89
+ y: [0, 0], # Box default
90
+ )
91
+ end
92
+ end
93
+
94
+ context 'unit conversion' do
95
+
96
+ it 'converts units on all args' do
97
+ args = {x: ['1in', '2in'], y: 300, width: '1in', height: '1in'}
98
+ box.load!(args, expand_by: 2)
99
+ expect(box).to have_attributes(
100
+ x: [300, 600],
101
+ y: [300, 300],
102
+ width: [300, 300],
103
+ height: [300, 300],
104
+ )
105
+ end
106
+
107
+ end
108
+
109
+ context 'validation' do
110
+ it 'replaces with deck width and height' do
111
+ args = {width: :deck, height: :deck}
112
+ deck = OpenStruct.new(width: 123, height: 456)
113
+ box = Squib::Args::Box.new(deck)
114
+ box.load!(args, expand_by: 1)
115
+ expect(box).to have_attributes(width: [123], height: [456])
116
+ end
117
+
118
+ it 'has radius override x_radius and y_radius' do
119
+ args = {x_radius: 1, y_radius: 2, radius: 3}
120
+ box.load!(args, expand_by: 2)
121
+ expect(box).to have_attributes(x_radius: [3, 3], y_radius: [3, 3])
122
+ end
123
+
124
+ end
125
+
126
+
127
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+ require 'squib/args/draw'
3
+
4
+ describe Squib::Args::Draw do
5
+ let(:custom_colors) { {'foo' => 'abc'} }
6
+ subject(:draw) {Squib::Args::Draw.new(custom_colors)}
7
+
8
+ context 'unit conversion' do
9
+
10
+ it 'converts units on stroke width' do
11
+ args = {stroke_width: '2in'}
12
+ draw.load!(args, expand_by: 2)
13
+ expect(draw).to have_attributes(stroke_width: [600, 600])
14
+ end
15
+
16
+ end
17
+
18
+ context 'dsl overrides' do
19
+ subject(:draw) {Squib::Args::Draw.new(custom_colors, {stroke_width: 0.0})}
20
+
21
+ it 'works when specified' do
22
+ draw.load!({}) # go right to defaults
23
+ expect(draw.stroke_width).to eq( [0.0] ) #ordinarily a non-zero according
24
+ end
25
+
26
+ end
27
+
28
+ context 'validation' do
29
+
30
+ it 'converts to Cairo options' do
31
+ args = {join: 'bevel', cap: 'round'}
32
+ draw.load!(args)
33
+ expect(draw).to have_attributes(
34
+ join: [Cairo::LINE_JOIN_BEVEL],
35
+ cap: [Cairo::LINE_JOIN_ROUND]
36
+ )
37
+ end
38
+
39
+ it 'parses dash options' do
40
+ args = {dash: '3 4 5'}
41
+ draw.load!(args)
42
+ expect(draw).to have_attributes(dash: [[3, 4, 5]])
43
+ end
44
+
45
+ it 'parses more complex dash options' do
46
+ args = {dash: '30.5, 90, 5'}
47
+ draw.load!(args)
48
+ expect(draw).to have_attributes(dash: [[30.5, 90, 5]])
49
+ end
50
+
51
+ it 'does unit conversion on dash options' do
52
+ args = {dash: '3in 4in 5in'}
53
+ draw.load!(args)
54
+ expect(draw).to have_attributes(dash: [[900, 1200, 1500]])
55
+ end
56
+
57
+ it 'converts line caps to Cairo constants' do
58
+ args = {cap: :SQUARE}
59
+ draw.load! args
60
+ expect(draw).to have_attributes( cap: [Cairo::LINE_CAP_SQUARE] )
61
+ end
62
+
63
+ it 'allows fill_first stroke_strategy' do
64
+ args = {stroke_strategy: :FILL_first}
65
+ draw.load! args
66
+ expect(draw).to have_attributes( stroke_strategy: [:fill_first] )
67
+ end
68
+
69
+ it 'allows stroke_first stroke_strategy' do
70
+ args = {stroke_strategy: ' stroke_FIRST '}
71
+ draw.load! args
72
+ expect(draw).to have_attributes( stroke_strategy: [:stroke_first] )
73
+ end
74
+
75
+ it 'disallows anything not stroke_first and fill_first' do
76
+ args = {stroke_strategy: 'foo'}
77
+ expect { draw.load! args }.to raise_error("Only 'stroke_first' or 'fill_first' allowed")
78
+ end
79
+
80
+ context 'custom colors' do
81
+
82
+ it 'looks up custom colors in the config' do
83
+ draw.load!({color: 'foo'})
84
+ expect(draw.color).to eq ['abc']
85
+ end
86
+
87
+ it 'passes on through for non-custom color' do
88
+ draw = Squib::Args::Draw.new(custom_colors)
89
+ draw.load!({color: 'bar'})
90
+ expect(draw.color).to eq ['bar']
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'squib/args/embed_key'
3
+
4
+ describe Squib::Args::EmbedKey do
5
+
6
+ context '#validate_key' do
7
+
8
+ it 'converts to string' do
9
+ expect(subject.validate_key(2.5)).to eq ('2.5')
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'squib/args/input_file'
3
+
4
+ describe Squib::Args::InputFile do
5
+ subject(:ifile) {Squib::Args::InputFile.new}
6
+
7
+ context 'validate_file' do
8
+
9
+ it 'allows a file if it exists' do
10
+ args = {file: __FILE__} # I code therefore I am.
11
+ ifile.load!(args, expand_by: 1)
12
+ expect(ifile).to have_attributes(file: [File.expand_path(__FILE__)])
13
+ end
14
+
15
+ it 'raises on non-existent file' do
16
+ args = {file: 'foo.rb'}
17
+ expect { ifile.load!(args, expand_by: 1) }.to raise_error("File #{File.expand_path('foo.rb')} does not exist!")
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'squib/args/paint'
3
+
4
+ describe Squib::Args::Draw do
5
+ let(:custom_colors) { {'foo' => 'abc'} }
6
+ subject(:paint) {Squib::Args::Paint.new(custom_colors)}
7
+
8
+ context 'alpha' do
9
+
10
+ it 'can be a float' do
11
+ args = {alpha: 0.6}
12
+ paint.load!(args)
13
+ expect(paint.alpha).to eq [0.6]
14
+ end
15
+
16
+ it 'raises exception when not a float' do
17
+ args = {alpha: /6/}
18
+ expect { paint.load!(args) }.to raise_error('alpha must respond to to_f')
19
+ end
20
+
21
+ end
22
+ end