squib 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +38 -33
  5. data/Rakefile +1 -1
  6. data/bin/squib +6 -6
  7. data/lib/squib.rb +8 -8
  8. data/lib/squib/api/background.rb +3 -3
  9. data/lib/squib/api/data.rb +5 -6
  10. data/lib/squib/api/image.rb +13 -10
  11. data/lib/squib/api/save.rb +4 -5
  12. data/lib/squib/api/settings.rb +4 -4
  13. data/lib/squib/api/shapes.rb +20 -20
  14. data/lib/squib/api/text.rb +11 -11
  15. data/lib/squib/api/units.rb +4 -4
  16. data/lib/squib/card.rb +5 -5
  17. data/lib/squib/commands/new.rb +5 -5
  18. data/lib/squib/constants.rb +10 -10
  19. data/lib/squib/deck.rb +24 -22
  20. data/lib/squib/graphics/background.rb +3 -3
  21. data/lib/squib/graphics/image.rb +13 -6
  22. data/lib/squib/graphics/save_doc.rb +13 -11
  23. data/lib/squib/graphics/save_images.rb +3 -3
  24. data/lib/squib/graphics/shapes.rb +9 -8
  25. data/lib/squib/graphics/text.rb +61 -59
  26. data/lib/squib/input_helpers.rb +13 -13
  27. data/lib/squib/progress.rb +4 -4
  28. data/lib/squib/project_template/Gemfile +1 -1
  29. data/lib/squib/project_template/deck.rb +3 -3
  30. data/lib/squib/version.rb +6 -2
  31. data/samples/autoscale_font.rb +4 -4
  32. data/samples/basic.rb +6 -7
  33. data/samples/cairo_access.rb +27 -0
  34. data/samples/colors.rb +2 -2
  35. data/samples/custom-layout.yml +5 -5
  36. data/samples/custom_config.rb +4 -4
  37. data/samples/draw_shapes.rb +8 -8
  38. data/samples/hello_world.rb +2 -3
  39. data/samples/load_images.rb +6 -1
  40. data/samples/portrait-landscape.rb +7 -7
  41. data/samples/ranges.rb +13 -14
  42. data/samples/save_pdf.rb +2 -2
  43. data/samples/text_options.rb +17 -17
  44. data/samples/tgc_proofs.rb +3 -3
  45. data/samples/use_layout.rb +3 -3
  46. data/spec/api/api_text_spec.rb +11 -17
  47. data/spec/commands/new_spec.rb +10 -10
  48. data/spec/data/easy-circular-extends.yml +1 -1
  49. data/spec/data/hard-circular-extends.yml +2 -2
  50. data/spec/data/multi-extends-single-entry.yml +3 -3
  51. data/spec/data/multi-level-extends.yml +1 -1
  52. data/spec/data/no-extends.yml +2 -2
  53. data/spec/data/pre-extends.yml +1 -1
  54. data/spec/data/self-circular-extends.yml +1 -1
  55. data/spec/data/single-extends.yml +1 -1
  56. data/spec/data/single-level-multi-extends.yml +1 -1
  57. data/spec/deck_spec.rb +62 -62
  58. data/spec/graphics/graphics_images_spec.rb +79 -0
  59. data/spec/graphics/graphics_save_doc_spec.rb +66 -0
  60. data/spec/graphics/graphics_shapes_spec.rb +74 -0
  61. data/spec/graphics/graphics_text_spec.rb +135 -0
  62. data/spec/input_helpers_spec.rb +61 -40
  63. data/spec/samples_run_spec.rb +6 -6
  64. data/spec/spec_helper.rb +32 -1
  65. data/squib.gemspec +21 -21
  66. metadata +22 -14
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'squib'
3
+
4
+ describe Squib::Deck, '#save_pdf' do
5
+
6
+ def expect_card_place(x, y)
7
+ expect(@context).to receive(:set_source)
8
+ .with(instance_of(Cairo::ImageSurface), -37, -37)
9
+ .once # trim the card
10
+ expect(@context).to receive(:paint).once # paint trimmed card
11
+ expect(@context).to receive(:set_source) # place the card
12
+ .with(instance_of(Cairo::ImageSurface), x, y).once
13
+ expect(@context).to receive(:paint).once # paint placed card
14
+ end
15
+
16
+ context 'typical inputs' do
17
+
18
+ before(:each) do
19
+ @context = double(Cairo::Context)
20
+ allow(Cairo::PDFSurface).to receive(:new).and_return(nil) #don't create the file
21
+ end
22
+
23
+ it 'make all the expected calls on a smoke test' do
24
+ num_cards = 9
25
+ args = { file: 'foo.pdf', dir: '_out', margin: 75, gap: 5, trim: 37 }
26
+ deck = Squib::Deck.new(cards: num_cards, width: 825, height: 1125)
27
+ mock_squib_logger(@old_logger) do
28
+ expect(Squib.logger).to receive(:debug).thrice
29
+ expect(Cairo::Context).to receive(:new).and_return(@context).exactly(num_cards + 1).times
30
+ expect(deck).to receive(:dirify) { |arg| arg } #don't create the dir
31
+
32
+ expect_card_place(75, 75)
33
+ expect_card_place(831, 75)
34
+ expect_card_place(1587, 75)
35
+ expect_card_place(2343, 75)
36
+ expect_card_place(75, 1131)
37
+ expect_card_place(831, 1131)
38
+ expect_card_place(1587, 1131)
39
+ expect_card_place(2343, 1131)
40
+ expect(@context).to receive(:show_page).once
41
+ expect_card_place(75, 75)
42
+
43
+ deck.save_pdf(args)
44
+ end
45
+ end
46
+
47
+ it 'only does the three cards on a limited range' do
48
+ num_cards = 9
49
+ args = { range: 2..4, file: 'foo.pdf', dir: '_out', margin: 75, gap: 5, trim: 37 }
50
+ deck = Squib::Deck.new(cards: num_cards, width: 825, height: 1125)
51
+ mock_squib_logger(@old_logger) do
52
+ expect(Squib.logger).to receive(:debug).thrice
53
+ expect(Cairo::Context).to receive(:new).and_return(@context).exactly(4).times
54
+ expect(deck).to receive(:dirify) { |arg| arg } #don't create the dir
55
+
56
+ expect_card_place(75, 75)
57
+ expect_card_place(831, 75)
58
+ expect_card_place(1587, 75)
59
+
60
+ deck.save_pdf(args)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'squib'
3
+
4
+ describe Squib::Card do
5
+
6
+ def expect_stroke(fill_color, stroke_color, stroke_width)
7
+ expect(@context).to receive(:set_source_color).with(stroke_color).once
8
+ expect(@context).to receive(:set_line_width).with(stroke_width).once
9
+ expect(@context).to receive(:stroke).once
10
+ expect(@context).to receive(:set_source_color).with(fill_color).once
11
+ expect(@context).to receive(:fill).once
12
+ end
13
+
14
+ before(:each) do
15
+ @deck = double(Squib::Deck)
16
+ @context = double(Cairo::Context)
17
+ allow(Cairo::Context).to receive(:new).and_return(@context)
18
+ end
19
+
20
+ context 'rect' do
21
+ it 'make all the expected calls on a smoke test' do
22
+ expect(@context).to receive(:save).once
23
+ expect(@context).to receive(:rounded_rectangle).with(37, 38, 50, 100, 10, 15).twice
24
+ expect_stroke('#fff', '#f00', 2.0)
25
+ expect(@context).to receive(:restore).once
26
+
27
+ card = Squib::Card.new(@deck, 100, 150)
28
+ # rect(x, y, width, height, x_radius, y_radius,
29
+ # fill_color, stroke_color, stroke_width)
30
+ card.rect(37, 38, 50, 100, 10, 15, '#fff', '#f00', 2.0)
31
+ end
32
+ end
33
+
34
+ context 'circle' do
35
+ it 'make all the expected calls on a smoke test' do
36
+ expect(@context).to receive(:save).once
37
+ expect(@context).to receive(:circle).with(37, 38, 100).twice
38
+ expect_stroke('#fff', '#f00', 2.0)
39
+ expect(@context).to receive(:restore).once
40
+
41
+ card = Squib::Card.new(@deck, 100, 150)
42
+ # circle(x, y, radius,
43
+ # fill_color, stroke_color, stroke_width)
44
+ card.circle(37, 38, 100, '#fff', '#f00', 2.0)
45
+ end
46
+ end
47
+
48
+ context 'triangle' do
49
+ it 'make all the expected calls on a smoke test' do
50
+ expect(@context).to receive(:save).once
51
+ expect(@context).to receive(:triangle).with(1, 2, 3, 4, 5, 6).twice
52
+ expect_stroke('#fff', '#f00', 2.0)
53
+ expect(@context).to receive(:restore).once
54
+
55
+ card = Squib::Card.new(@deck, 100, 150)
56
+ card.triangle(1, 2, 3, 4, 5, 6, '#fff', '#f00', 2.0)
57
+ end
58
+ end
59
+
60
+ context 'line' do
61
+ it 'make all the expected calls on a smoke test' do
62
+ expect(@context).to receive(:save).once
63
+ expect(@context).to receive(:move_to).with(1, 2).once
64
+ expect(@context).to receive(:line_to).with(3, 4).once
65
+ expect(@context).to receive(:set_source_color).with('#fff').once
66
+ expect(@context).to receive(:set_line_width).with(2.0).once
67
+ expect(@context).to receive(:stroke).once
68
+ expect(@context).to receive(:restore).once
69
+
70
+ card = Squib::Card.new(@deck, 100, 150)
71
+ card.line(1, 2, 3, 4, '#fff', 2.0)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+ require 'squib'
3
+
4
+ describe Squib::Card, '#text' do
5
+
6
+ context 'typical inputs' do
7
+ before(:each) do
8
+ @deck = double(Squib::Deck)
9
+ @context = double(Cairo::Context)
10
+ @layout = double(Pango::Layout)
11
+ allow(Cairo::Context).to receive(:new).and_return(@context)
12
+ end
13
+
14
+ it 'make all the expected calls on a smoke test' do
15
+ mock_squib_logger(@old_logger) do
16
+ expect(Squib.logger).to receive(:debug).once
17
+ expect(@context).to receive(:save).once
18
+ expect(@context).to receive(:set_source_color).once
19
+ expect(@context).to receive(:move_to).with(10, 15).once
20
+ expect(@context).to receive(:translate).with(-10, -15).once
21
+ expect(@context).to receive(:rotate).with(0.0).once
22
+ expect(@context).to receive(:translate).with(10, 15).once
23
+ expect(@context).to receive(:create_pango_layout).once.and_return(@layout)
24
+ expect(@layout).to receive(:font_description=).with(Pango::FontDescription.new('Sans 12')).once
25
+ expect(@layout).to receive(:text=).with('foo').once
26
+ expect(@layout).to receive(:width=).with(20 * Pango::SCALE).once
27
+ expect(@layout).to receive(:height=).with(25 * Pango::SCALE).once
28
+ expect(@layout).to receive(:ellipsize=).with(Pango::Layout::ELLIPSIZE_NONE).once
29
+ expect(@layout).to receive(:alignment=).with(Pango::Layout::ALIGN_LEFT).once
30
+ expect(@layout).to receive(:justify=).with(false).once
31
+ expect(@layout).to receive(:spacing=).with(1.0 * Pango::SCALE).once
32
+ expect(@context).to receive(:update_pango_layout).once
33
+ expect(@layout).to receive(:height).once.and_return(25)
34
+ expect(@layout).to receive(:extents).once.and_return([0,0])
35
+ expect(@context).to receive(:update_pango_layout).once
36
+ expect(@context).to receive(:show_pango_layout).once
37
+ expect(@context).to receive(:restore).once
38
+
39
+ card = Squib::Card.new(@deck, 100, 150)
40
+ # text(str, font, font_size, color,
41
+ # x, y, width, height,
42
+ # markup, justify, wrap, ellipsize,
43
+ # spacing, align, valign, hint, angle)
44
+ card.text('foo', 'Sans 12', nil, '#abc',
45
+ 10, 15, 20, 25,
46
+ nil, false, false, false,
47
+ 1.0, :left, :top, nil, 0.0)
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'convenience lookups' do
53
+ before(:each) do
54
+ @deck = double(Squib::Deck)
55
+ @context = double(Cairo::Context).as_null_object
56
+ @layout = double(Pango::Layout).as_null_object
57
+ @extents = double("extents")
58
+ allow(Cairo::Context).to receive(:new).and_return(@context)
59
+ expect(@context).to receive(:create_pango_layout).once.and_return(@layout)
60
+ end
61
+
62
+ it 'aligns right with strings' do
63
+ card = Squib::Card.new(@deck, 100, 150)
64
+ expect(@layout).to receive(:alignment=).with(Pango::Layout::ALIGN_RIGHT).once
65
+ card.text('foo', 'Sans 12', nil, '#abc',
66
+ 10, 15, 20, 50,
67
+ nil, false, false, false,
68
+ 1.0, 'right', :top, nil, 0.0)
69
+ end
70
+
71
+ it 'aligns center with strings' do
72
+ card = Squib::Card.new(@deck, 100, 150)
73
+ expect(@layout).to receive(:alignment=).with(Pango::Layout::ALIGN_CENTER).once
74
+ card.text('foo', 'Sans 12', nil, '#abc',
75
+ 10, 15, 20, 50,
76
+ nil, false, false, false,
77
+ 1.0, 'center', :top, nil, 0.0)
78
+ end
79
+
80
+ it 'sets wrap to char with string char' do
81
+ card = Squib::Card.new(@deck, 100, 150)
82
+ expect(@layout).to receive(:wrap=).with(Pango::Layout::WRAP_CHAR).once
83
+ card.text('foo', 'Sans 12', nil, '#abc',
84
+ 10, 15, 20, 50,
85
+ nil, false, 'char', false,
86
+ 1.0, :left, :top, nil, 0.0)
87
+ end
88
+
89
+ it 'sets wrap to word with word string' do
90
+ card = Squib::Card.new(@deck, 100, 150)
91
+ expect(@layout).to receive(:wrap=).with(Pango::Layout::WRAP_WORD).once
92
+ card.text('foo', 'Sans 12', nil, '#abc',
93
+ 10, 15, 20, 50,
94
+ nil, false, 'word', false,
95
+ 1.0, :left, :top, nil, 0.0)
96
+ end
97
+
98
+ it 'sets wrap to word_char with symbol word_char' do
99
+ card = Squib::Card.new(@deck, 100, 150)
100
+ expect(@layout).to receive(:wrap=).with(Pango::Layout::WRAP_WORD_CHAR).once
101
+ card.text('foo', 'Sans 12', nil, '#abc',
102
+ 10, 15, 20, 50,
103
+ nil, false, :word_char, false,
104
+ 1.0, :left, :top, nil, 0.0)
105
+ end
106
+
107
+ it 'sets wrap to word_char with true' do
108
+ card = Squib::Card.new(@deck, 100, 150)
109
+ expect(@layout).to receive(:wrap=).with(Pango::Layout::WRAP_WORD_CHAR).once
110
+ card.text('foo', 'Sans 12', nil, '#abc',
111
+ 10, 15, 20, 50,
112
+ nil, false, true, false,
113
+ 1.0, :left, :top, nil, 0.0)
114
+ end
115
+
116
+ it 'sets ellipsize to start properly' do
117
+ card = Squib::Card.new(@deck, 100, 150)
118
+ expect(@layout).to receive(:ellipsize=).with(Pango::Layout::ELLIPSIZE_START).once
119
+ card.text('foo', 'Sans 12', nil, '#abc',
120
+ 10, 15, 20, 50,
121
+ nil, false, true, :start,
122
+ 1.0, :left, :top, nil, 0.0)
123
+ end
124
+
125
+ it 'sets ellipsize to middle properly' do
126
+ card = Squib::Card.new(@deck, 100, 150)
127
+ expect(@layout).to receive(:ellipsize=).with(Pango::Layout::ELLIPSIZE_MIDDLE).once
128
+ card.text('foo', 'Sans 12', nil, '#abc',
129
+ 10, 15, 20, 50,
130
+ nil, false, true, 'middle',
131
+ 1.0, :left, :top, nil, 0.0)
132
+ end
133
+
134
+ end
135
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'squib'
2
3
  require 'squib/input_helpers'
3
4
 
4
5
  class DummyDeck
@@ -6,20 +7,12 @@ class DummyDeck
6
7
  attr_accessor :layout, :cards, :custom_colors
7
8
  end
8
9
 
9
- module Squib
10
- def logger=(l)
11
- @logger = l
12
- end
13
- module_function 'logger='
14
- end
15
-
16
10
  describe Squib::InputHelpers do
17
11
 
18
-
19
12
  before(:each) do
20
13
  @deck = DummyDeck.new
21
14
  @deck.layout = {
22
- 'blah' => {x: 25},
15
+ 'blah' => {x: 25},
23
16
  'apples' => {x: 35},
24
17
  'oranges' => {y: 45},
25
18
  }
@@ -28,90 +21,118 @@ describe Squib::InputHelpers do
28
21
  end
29
22
 
30
23
  context '#layoutify' do
31
- it "warns on the logger when the layout doesn't exist" do
32
- @old_logger = Squib.logger
33
- Squib.logger = instance_double(Logger)
34
- expect(Squib.logger).to receive(:warn).with("Layout entry 'foo' does not exist.").twice
35
- expect(Squib.logger).to receive(:debug)
36
- expect(@deck.send(:layoutify, {layout: :foo})).to eq({layout: [:foo,:foo]})
37
- Squib.logger = @old_logger
24
+ it 'warns on the logger when the layout does not exist' do
25
+ mock_squib_logger(@old_logger) do
26
+ expect(Squib.logger).to receive(:warn).with("Layout entry 'foo' does not exist.").twice
27
+ expect(Squib.logger).to receive(:debug)
28
+ expect(@deck.send(:layoutify, {layout: :foo})).to eq({layout: [:foo,:foo]})
29
+ end
38
30
  end
39
31
 
40
- it "applies the layout in a normal situation" do
32
+ it 'applies the layout in a normal situation' do
41
33
  expect(@deck.send(:layoutify, {layout: :blah})).to \
42
- eq({layout: [:blah, :blah], x: [25, 25]})
34
+ eq({layout: [:blah, :blah], x: [25, 25]})
43
35
  end
44
36
 
45
- it "applies two different layouts for two different situations" do
37
+ it 'applies two different layouts for two different situations' do
46
38
  expect(@deck.send(:layoutify, {layout: ['blah', 'apples']})).to \
47
- eq({layout: ['blah','apples'], x: [25, 35]})
39
+ eq({layout: ['blah','apples'], x: [25, 35]})
48
40
  end
49
41
 
50
- it "still has nils when not applied two different layouts differ in structure" do
42
+ it 'still has nils when not applied two different layouts differ in structure' do
51
43
  expect(@deck.send(:layoutify, {layout: ['apples', 'oranges']})).to \
52
- eq({layout: ['apples','oranges'], x: [35], y: [nil, 45]})
44
+ eq({layout: ['apples','oranges'], x: [35], y: [nil, 45]})
53
45
  #...this might behavior that is hard to debug for users. Trying to come up with a warning or something...
54
46
  end
55
47
 
56
- it "also looks up based on strings" do
48
+ it 'also looks up based on strings' do
57
49
  expect(@deck.send(:layoutify, {layout: 'blah'})).to \
58
- eq({layout: ['blah','blah'], x: [25, 25]})
50
+ eq({layout: ['blah','blah'], x: [25, 25]})
59
51
  end
60
52
 
61
53
  end
62
54
 
63
55
  context '#rangeify' do
64
- it "must be within the card size range" do
56
+ it 'must be within the card size range' do
65
57
  expect{@deck.send(:rangeify, {range: 2..3})}.to \
66
58
  raise_error(ArgumentError, '2..3 is outside of deck range of 0..1')
67
59
  end
68
60
 
69
- it "cannot be nil" do
61
+ it 'cannot be nil' do
70
62
  expect{@deck.send(:rangeify, {range: nil})}.to \
71
63
  raise_error(RuntimeError, 'Range cannot be nil')
72
64
  end
73
65
 
74
- it "defaults to a range of all cards if :all" do
66
+ it 'defaults to a range of all cards if :all' do
75
67
  expect(@deck.send(:rangeify, {range: :all})).to eq({range: 0..1})
76
68
  end
77
69
  end
78
70
 
79
- context "#fileify" do
80
- it "should throw an error if the file doesn't exist" do
71
+ context '#fileify' do
72
+ it 'should throw an error if the file does not exist' do
81
73
  expect{@deck.send(:fileify, {file: 'nonexist.txt'}, true)}.to \
82
74
  raise_error(RuntimeError,"File #{File.expand_path('nonexist.txt')} does not exist!")
83
75
  end
84
76
  end
85
77
 
86
- context "#dir" do
87
- it "should raise an error if the directory does not exist" do
78
+ context '#dirify' do
79
+ it 'should raise an error if the directory does not exist' do
88
80
  expect{@deck.send(:dirify, {dir: 'nonexist'}, :dir, false)}.to \
89
81
  raise_error(RuntimeError,"'nonexist' does not exist!")
90
82
  end
83
+
84
+ it 'should warn and make a directory creation is allowed' do
85
+ opts = {dir: 'tocreate'}
86
+ Dir.chdir(output_dir) do
87
+ FileUtils.rm_rf('tocreate', secure: true)
88
+ mock_squib_logger(@old_logger) do
89
+ expect(Squib.logger).to receive(:warn).with("Dir 'tocreate' does not exist, creating it.").once
90
+ expect(@deck.send(:dirify, opts, :dir, true)).to eq(opts)
91
+ expect(Dir.exists? 'tocreate').to be true
92
+ end
93
+ end
94
+ end
95
+
91
96
  end
92
97
 
93
- context "#colorify" do
94
- it "should parse if nillable" do
98
+ context '#colorify' do
99
+ it 'should parse if nillable' do
95
100
  color = @deck.send(:colorify, {color: ['#fff']}, true)[:color]
96
101
  expect(color.to_a[0].to_a).to eq([1.0, 1.0, 1.0, 1.0])
97
102
  end
98
103
 
99
- it "raises and error if the color doesn't exist" do
104
+ it 'raises and error if the color does not exist' do
100
105
  expect{ @deck.send(:colorify, {color: [:nonexist]}, false) }.to \
101
- raise_error(ArgumentError, "unknown color name: nonexist")
106
+ raise_error(ArgumentError, 'unknown color name: nonexist')
102
107
  end
103
108
 
104
- it "pulls from config's custom colors" do
105
- @deck.custom_colors['foo'] = "#abc"
109
+ it 'pulls from custom colors in the config' do
110
+ @deck.custom_colors['foo'] = '#abc'
106
111
  expect(@deck.send(:colorify, {color: [:foo]}, false)[:color][0].to_s).to \
107
112
  eq('#AABBCCFF')
108
113
  end
109
114
 
110
- it "pulls from config's custom colors even when a string" do
111
- @deck.custom_colors['foo'] = "#abc"
115
+ it 'pulls custom colors even when a string' do
116
+ @deck.custom_colors['foo'] = '#abc'
112
117
  expect(@deck.send(:colorify, {color: ['foo']}, false)[:color][0].to_s).to \
113
118
  eq('#AABBCCFF')
114
119
  end
115
120
  end
116
121
 
117
- end
122
+ context '#rotateify' do
123
+ it 'computes a clockwise rotate properly' do
124
+ opts = @deck.send(:rotateify, {rotate: :clockwise})
125
+ expect(opts).to eq({ :angle => 0.5 * Math::PI,
126
+ :rotate => :clockwise
127
+ })
128
+ end
129
+
130
+ it 'computes a counter-clockwise rotate properly' do
131
+ opts = @deck.send(:rotateify, {rotate: :counterclockwise})
132
+ expect(opts).to eq({ :angle => 1.5 * Math::PI,
133
+ :rotate => :counterclockwise
134
+ })
135
+ end
136
+ end
137
+
138
+ end