prawn-svg 0.28.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +18 -0
  3. data/LICENSE +1 -1
  4. data/README.md +14 -9
  5. data/lib/prawn-svg.rb +4 -0
  6. data/lib/prawn/svg/attributes/opacity.rb +4 -4
  7. data/lib/prawn/svg/attributes/transform.rb +2 -44
  8. data/lib/prawn/svg/calculators/document_sizing.rb +2 -2
  9. data/lib/prawn/svg/css/stylesheets.rb +40 -19
  10. data/lib/prawn/svg/elements.rb +2 -0
  11. data/lib/prawn/svg/elements/base.rb +11 -5
  12. data/lib/prawn/svg/elements/call_duplicator.rb +1 -1
  13. data/lib/prawn/svg/elements/gradient.rb +83 -25
  14. data/lib/prawn/svg/elements/image.rb +2 -2
  15. data/lib/prawn/svg/elements/path.rb +42 -29
  16. data/lib/prawn/svg/elements/root.rb +4 -1
  17. data/lib/prawn/svg/elements/text_component.rb +21 -5
  18. data/lib/prawn/svg/elements/use.rb +23 -7
  19. data/lib/prawn/svg/extensions/additional_gradient_transforms.rb +23 -0
  20. data/lib/prawn/svg/interface.rb +38 -8
  21. data/lib/prawn/svg/loaders/data.rb +1 -1
  22. data/lib/prawn/svg/loaders/file.rb +4 -2
  23. data/lib/prawn/svg/properties.rb +1 -0
  24. data/lib/prawn/svg/transform_parser.rb +72 -0
  25. data/lib/prawn/svg/version.rb +1 -1
  26. data/prawn-svg.gemspec +3 -3
  27. data/spec/integration_spec.rb +24 -24
  28. data/spec/prawn/svg/attributes/opacity_spec.rb +85 -0
  29. data/spec/prawn/svg/attributes/transform_spec.rb +30 -35
  30. data/spec/prawn/svg/calculators/document_sizing_spec.rb +4 -4
  31. data/spec/prawn/svg/css/stylesheets_spec.rb +17 -6
  32. data/spec/prawn/svg/elements/base_spec.rb +16 -16
  33. data/spec/prawn/svg/elements/gradient_spec.rb +79 -4
  34. data/spec/prawn/svg/elements/line_spec.rb +12 -12
  35. data/spec/prawn/svg/elements/marker_spec.rb +27 -27
  36. data/spec/prawn/svg/elements/path_spec.rb +29 -17
  37. data/spec/prawn/svg/elements/polygon_spec.rb +9 -9
  38. data/spec/prawn/svg/elements/polyline_spec.rb +7 -7
  39. data/spec/prawn/svg/elements/text_spec.rb +65 -50
  40. data/spec/prawn/svg/loaders/data_spec.rb +8 -0
  41. data/spec/prawn/svg/pathable_spec.rb +4 -4
  42. data/spec/prawn/svg/transform_parser_spec.rb +94 -0
  43. data/spec/sample_svg/double_opacity.svg +6 -0
  44. data/spec/sample_svg/gradient_transform.svg +19 -0
  45. data/spec/sample_svg/links.svg +18 -0
  46. data/spec/sample_svg/radgrad01-bounding.svg +26 -0
  47. data/spec/sample_svg/radgrad01.svg +26 -0
  48. data/spec/sample_svg/svg_fill.svg +5 -0
  49. data/spec/sample_svg/text-decoration.svg +4 -0
  50. data/spec/sample_svg/transform.svg +20 -0
  51. data/spec/sample_svg/use_disordered.svg +17 -0
  52. data/spec/spec_helper.rb +2 -2
  53. metadata +48 -11
  54. data/.travis.yml +0 -6
@@ -37,6 +37,7 @@ class Prawn::SVG::Properties
37
37
  "stroke-opacity" => Config.new("1", true),
38
38
  "stroke-width" => Config.new("1", true),
39
39
  "text-anchor" => Config.new("start", true, %w(inherit start middle end), true),
40
+ 'text-decoration' => Config.new('none', true, %w(inherit none underline), true),
40
41
  }.freeze
41
42
 
42
43
  PROPERTIES.each do |name, value|
@@ -0,0 +1,72 @@
1
+ module Prawn::SVG::TransformParser
2
+ def parse_transform_attribute(transform)
3
+ matrix = Matrix.identity(3)
4
+
5
+ parse_css_method_calls(transform).each do |name, arguments|
6
+ case name
7
+ when 'translate'
8
+ x, y = arguments
9
+ matrix *= Matrix[[1, 0, x_pixels(x.to_f)], [0, 1, -y_pixels(y.to_f)], [0, 0, 1]]
10
+
11
+ when 'translateX'
12
+ x = arguments.first
13
+ matrix *= Matrix[[1, 0, x_pixels(x.to_f)], [0, 1, 0], [0, 0, 1]]
14
+
15
+ when 'translateY'
16
+ y = arguments.first
17
+ matrix *= Matrix[[1, 0, 0], [0, 1, -y_pixels(y.to_f)], [0, 0, 1]]
18
+
19
+ when 'rotate'
20
+ angle, x, y = arguments.collect { |a| a.to_f }
21
+ angle = angle * Math::PI / 180.0
22
+
23
+ case arguments.length
24
+ when 1
25
+ matrix *= Matrix[[Math.cos(angle), Math.sin(angle), 0], [-Math.sin(angle), Math.cos(angle), 0], [0, 0, 1]]
26
+ when 3
27
+ matrix *= Matrix[[1, 0, x_pixels(x.to_f)], [0, 1, -y_pixels(y.to_f)], [0, 0, 1]]
28
+ matrix *= Matrix[[Math.cos(angle), Math.sin(angle), 0], [-Math.sin(angle), Math.cos(angle), 0], [0, 0, 1]]
29
+ matrix *= Matrix[[1, 0, -x_pixels(x.to_f)], [0, 1, y_pixels(y.to_f)], [0, 0, 1]]
30
+ else
31
+ warnings << "transform 'rotate' must have either one or three arguments"
32
+ end
33
+
34
+ when 'scale'
35
+ x_scale = arguments[0].to_f
36
+ y_scale = (arguments[1] || x_scale).to_f
37
+ matrix *= Matrix[[x_scale, 0, 0], [0, y_scale, 0], [0, 0, 1]]
38
+
39
+ when 'skewX'
40
+ angle = arguments[0].to_f * Math::PI / 180.0
41
+ matrix *= Matrix[[1, -Math.tan(angle), 0], [0, 1, 0], [0, 0, 1]]
42
+
43
+ when 'skewY'
44
+ angle = arguments[0].to_f * Math::PI / 180.0
45
+ matrix *= Matrix[[1, 0, 0], [-Math.tan(angle), 1, 0], [0, 0, 1]]
46
+
47
+ when 'matrix'
48
+ if arguments.length != 6
49
+ warnings << "transform 'matrix' must have six arguments"
50
+ else
51
+ a, b, c, d, e, f = arguments.collect { |argument| argument.to_f }
52
+ matrix *= Matrix[[a, -c, e], [-b, d, -f], [0, 0, 1]]
53
+ end
54
+
55
+ else
56
+ warnings << "Unknown/unsupported transformation '#{name}'; ignoring"
57
+ end
58
+ end
59
+
60
+ matrix.to_a[0..1].transpose.flatten
61
+ end
62
+
63
+ private
64
+
65
+ def parse_css_method_calls(string)
66
+ string.scan(/\s*(\w+)\(([^)]+)\)\s*/).collect do |call|
67
+ name, argument_string = call
68
+ arguments = argument_string.strip.split(/\s*[,\s]\s*/)
69
+ [name, arguments]
70
+ end
71
+ end
72
+ end
@@ -1,5 +1,5 @@
1
1
  module Prawn
2
2
  module SVG
3
- VERSION = '0.28.0'
3
+ VERSION = '0.32.0'
4
4
  end
5
5
  end
data/prawn-svg.gemspec CHANGED
@@ -6,7 +6,6 @@ Gem::Specification.new do |gem|
6
6
  gem.version = Prawn::SVG::VERSION
7
7
  gem.summary = "SVG renderer for Prawn PDF library"
8
8
  gem.description = "This gem allows you to render SVG directly into a PDF using the 'prawn' gem. Since PDF is vector-based, you'll get nice scaled graphics if you use SVG instead of an image."
9
- gem.has_rdoc = false
10
9
  gem.author = "Roger Nesbitt"
11
10
  gem.email = "roger@seriousorange.com"
12
11
  gem.homepage = "http://github.com/mogest/prawn-svg"
@@ -18,10 +17,11 @@ Gem::Specification.new do |gem|
18
17
  gem.name = "prawn-svg"
19
18
  gem.require_paths = ["lib"]
20
19
 
21
- gem.required_ruby_version = '>= 2.1.0'
20
+ gem.required_ruby_version = '>= 2.3.0'
22
21
 
23
22
  gem.add_runtime_dependency "prawn", ">= 0.11.1", "< 3"
24
23
  gem.add_runtime_dependency "css_parser", "~> 1.6"
24
+ gem.add_runtime_dependency "rexml", "~> 3.2"
25
25
  gem.add_development_dependency "rspec", "~> 3.0"
26
- gem.add_development_dependency "rake", "~> 10.1"
26
+ gem.add_development_dependency "rake", "~> 13.0"
27
27
  end
@@ -28,34 +28,34 @@ describe "Integration test" do
28
28
  element.process
29
29
 
30
30
  expect(element.calls).to eq [
31
- ["fill_color", ["000000"], []],
32
- ["transformation_matrix", [1, 0, 0, 1, 0, 0], []],
33
- ["transformation_matrix", [1, 0, 0, 1, 0, 0], []],
34
- ["save", [], []], ["restore", [], []],
35
- ["save", [], []],
36
- ["fill_color", ["0000ff"], []],
37
- ["fill", [], [
38
- ["rectangle", [[0.0, 200.0], 10.0, 10.0], []]
31
+ ["fill_color", ["000000"], {}, []],
32
+ ["transformation_matrix", [1, 0, 0, 1, 0, 0], {}, []],
33
+ ["transformation_matrix", [1, 0, 0, 1, 0, 0], {}, []],
34
+ ["save", [], {}, []], ["restore", [], {}, []],
35
+ ["save", [], {}, []],
36
+ ["fill_color", ["0000ff"], {}, []],
37
+ ["fill", [], {}, [
38
+ ["rectangle", [[0.0, 200.0], 10.0, 10.0], {}, []]
39
39
  ]],
40
- ["restore", [], []],
41
- ["save", [], []],
42
- ["fill_color", ["008000"], []],
43
- ["fill", [], [
44
- ["rectangle", [[10.0, 200.0], 10.0, 10.0], []]
40
+ ["restore", [], {}, []],
41
+ ["save", [], {}, []],
42
+ ["fill_color", ["008000"], {}, []],
43
+ ["fill", [], {}, [
44
+ ["rectangle", [[10.0, 200.0], 10.0, 10.0], {}, []]
45
45
  ]],
46
- ["restore", [], []],
47
- ["save", [], []],
48
- ["fill_color", ["ff0000"], []],
49
- ["fill", [], [
50
- ["rectangle", [[20.0, 200.0], 10.0, 10.0], []]
46
+ ["restore", [], {}, []],
47
+ ["save", [], {}, []],
48
+ ["fill_color", ["ff0000"], {}, []],
49
+ ["fill", [], {}, [
50
+ ["rectangle", [[20.0, 200.0], 10.0, 10.0], {}, []]
51
51
  ]],
52
- ["restore", [], []],
53
- ["save", [], []],
54
- ["fill_color", ["ffff00"], []],
55
- ["fill", [], [
56
- ["rectangle", [[30.0, 200.0], 10.0, 10.0], []]
52
+ ["restore", [], {}, []],
53
+ ["save", [], {}, []],
54
+ ["fill_color", ["ffff00"], {}, []],
55
+ ["fill", [], {}, [
56
+ ["rectangle", [[30.0, 200.0], 10.0, 10.0], {}, []]
57
57
  ]],
58
- ["restore", [], []]
58
+ ["restore", [], {}, []]
59
59
  ]
60
60
  end
61
61
  end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Prawn::SVG::Attributes::Opacity do
4
+ class OpacityTestElement
5
+ include Prawn::SVG::Attributes::Opacity
6
+
7
+ attr_accessor :properties, :state
8
+
9
+ def initialize
10
+ @properties = ::Prawn::SVG::Properties.new
11
+ @state = ::Prawn::SVG::State.new
12
+ end
13
+
14
+ def clamp(value, min_value, max_value)
15
+ [[value, min_value].max, max_value].min
16
+ end
17
+ end
18
+
19
+ let(:element) { OpacityTestElement.new }
20
+
21
+ describe "#parse_opacity_attributes_and_call" do
22
+ subject { element.parse_opacity_attributes_and_call }
23
+
24
+ context "with no opacity specified" do
25
+ it "does nothing" do
26
+ expect(element).not_to receive(:add_call_and_enter)
27
+ subject
28
+ end
29
+ end
30
+
31
+ context "with opacity" do
32
+ it "sets fill and stroke opacity" do
33
+ element.properties.opacity = '0.4'
34
+
35
+ expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.4)
36
+ subject
37
+
38
+ expect(element.state.fill_opacity).to eq 0.4
39
+ expect(element.state.stroke_opacity).to eq 0.4
40
+ end
41
+ end
42
+
43
+ context "with just fill opacity" do
44
+ it "sets fill opacity and sets stroke opacity to 1" do
45
+ element.properties.fill_opacity = '0.4'
46
+
47
+ expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 1)
48
+ subject
49
+
50
+ expect(element.state.fill_opacity).to eq 0.4
51
+ expect(element.state.stroke_opacity).to eq 1
52
+ end
53
+ end
54
+
55
+ context "with an existing fill/stroke opacity" do
56
+ it "multiplies the new opacity by the old" do
57
+ element.state.fill_opacity = 0.5
58
+ element.state.stroke_opacity = 0.8
59
+
60
+ element.properties.fill_opacity = '0.4'
61
+ element.properties.stroke_opacity = '0.5'
62
+
63
+ expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.4)
64
+ subject
65
+
66
+ expect(element.state.fill_opacity).to eq 0.2
67
+ expect(element.state.stroke_opacity).to eq 0.4
68
+ end
69
+ end
70
+
71
+ context "with stroke, fill, and opacity all specified" do
72
+ it "choses the lower of them" do
73
+ element.properties.fill_opacity = '0.4'
74
+ element.properties.stroke_opacity = '0.6'
75
+ element.properties.opacity = '0.5'
76
+
77
+ expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.5)
78
+ subject
79
+
80
+ expect(element.state.fill_opacity).to eq 0.4
81
+ expect(element.state.stroke_opacity).to eq 0.5
82
+ end
83
+ end
84
+ end
85
+ end
@@ -14,43 +14,38 @@ describe Prawn::SVG::Attributes::Transform do
14
14
 
15
15
  let(:element) { TransformTestElement.new }
16
16
 
17
- describe "#parse_transform_attribute_and_call" do
18
- subject { element.send :parse_transform_attribute_and_call }
19
-
20
- describe "translate" do
21
- it "handles a missing y argument" do
22
- expect(element).to receive(:add_call_and_enter).with('translate', -5.5, 0)
23
- expect(element).to receive(:x_pixels).with(-5.5).and_return(-5.5)
24
- expect(element).to receive(:y_pixels).with(0.0).and_return(0.0)
25
-
26
- element.attributes['transform'] = 'translate(-5.5)'
27
- subject
28
- end
17
+ subject { element.send :parse_transform_attribute_and_call }
18
+
19
+ context "when a non-identity matrix is requested" do
20
+ let(:transform) { 'translate(-5.5)' }
21
+
22
+ it "passes the transform and executes the returned matrix" do
23
+ expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 2, 3, 4, 5, 6])
24
+ expect(element).to receive(:add_call_and_enter).with('transformation_matrix', 1, 2, 3, 4, 5, 6)
25
+
26
+ element.attributes['transform'] = transform
27
+ subject
28
+ end
29
+ end
30
+
31
+ context "when an identity matrix is requested" do
32
+ let(:transform) { 'translate(0)' }
33
+
34
+ it "does not execute any commands" do
35
+ expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 0, 0, 1, 0, 0])
36
+ expect(element).not_to receive(:add_call_and_enter)
37
+
38
+ element.attributes['transform'] = transform
39
+ subject
29
40
  end
41
+ end
42
+
43
+ context "when transform is blank" do
44
+ it "does nothing" do
45
+ expect(element).not_to receive(:parse_transform_attribute)
46
+ expect(element).not_to receive(:add_call_and_enter)
30
47
 
31
- describe "rotate" do
32
- it "handles a single angle argument" do
33
- expect(element).to receive(:add_call_and_enter).with('rotate', -5.5, :origin => [0, 0])
34
- expect(element).to receive(:y).with('0').and_return(0)
35
-
36
- element.attributes['transform'] = 'rotate(5.5)'
37
- subject
38
- end
39
-
40
- it "handles three arguments" do
41
- expect(element).to receive(:add_call_and_enter).with('rotate', -5.5, :origin => [1.0, 2.0])
42
- expect(element).to receive(:x).with(1.0).and_return(1.0)
43
- expect(element).to receive(:y).with(2.0).and_return(2.0)
44
-
45
- element.attributes['transform'] = 'rotate(5.5 1 2)'
46
- subject
47
- end
48
-
49
- it "does nothing and warns if two arguments" do
50
- expect(element).to receive(:warnings).and_return([])
51
- element.attributes['transform'] = 'rotate(5.5 1)'
52
- subject
53
- end
48
+ subject
54
49
  end
55
50
  end
56
51
  end
@@ -31,8 +31,8 @@ describe Prawn::SVG::Calculators::DocumentSizing do
31
31
  describe "#calculate" do
32
32
  it "calculates the document sizing measurements for a given set of inputs" do
33
33
  sizing.calculate
34
- expect(sizing.x_offset).to eq -75 / 0.25
35
- expect(sizing.y_offset).to eq -30
34
+ expect(sizing.x_offset).to eq(-75 / 0.25)
35
+ expect(sizing.y_offset).to eq(-30)
36
36
  expect(sizing.x_scale).to eq 0.25
37
37
  expect(sizing.y_scale).to eq 0.25
38
38
  expect(sizing.viewport_width).to eq 300
@@ -74,12 +74,12 @@ describe Prawn::SVG::Calculators::DocumentSizing do
74
74
  context "when a viewBox is specified" do
75
75
  let(:attributes) { {"viewBox" => "0 0 100 200"} }
76
76
 
77
- it "defaults to 100% width and height" do
77
+ it "defaults to 100% width and uses the viewbox ratio for height" do
78
78
  sizing.calculate
79
79
  expect(sizing.viewport_width).to eq 100
80
80
  expect(sizing.viewport_height).to eq 200
81
81
  expect(sizing.output_width).to eq 1200
82
- expect(sizing.output_height).to eq 800
82
+ expect(sizing.output_height).to eq 2400
83
83
  end
84
84
  end
85
85
 
@@ -11,6 +11,7 @@ RSpec.describe Prawn::SVG::CSS::Stylesheets do
11
11
  rect { fill: #ff0000; }
12
12
  rect ~ rect { fill: #330000; }
13
13
  rect + rect { fill: #440000; }
14
+ rect:first-child:last-child { fill: #441234; }
14
15
 
15
16
  circle:first-child { fill: #550000; }
16
17
  circle:nth-child(2) { fill: #660000; }
@@ -37,9 +38,13 @@ RSpec.describe Prawn::SVG::CSS::Stylesheets do
37
38
  <rect width="6" height="6" />
38
39
  </g>
39
40
 
40
- <circle width="7" />
41
- <circle width="8" />
42
- <circle width="9" />
41
+ <circle width="100" />
42
+
43
+ <g id="circles">
44
+ <circle width="7" />
45
+ <circle width="8" />
46
+ <circle width="9" />
47
+ </g>
43
48
  </g>
44
49
 
45
50
  <square width="10" chocolate="hi there" />
@@ -56,13 +61,17 @@ RSpec.describe Prawn::SVG::CSS::Stylesheets do
56
61
  result = Prawn::SVG::CSS::Stylesheets.new(CssParser::Parser.new, REXML::Document.new(svg)).load
57
62
  width_and_styles = result.map { |k, v| [k.attributes["width"].to_i, v] }.sort_by(&:first)
58
63
 
59
- expect(width_and_styles).to eq [
64
+ expected = [
60
65
  [1, [["fill", "#ff0000", false]]],
61
66
  [2, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#220000", false]]],
62
67
  [3, [["fill", "#ff0000", false], ["fill", "#00ff00", false]]],
63
68
  [4, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]],
64
- [5, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#330000", false], ["fill", "#00ff00", false]]],
65
- [6, [["fill", "#ff0000", false], ["fill", "#0000ff", false]]],
69
+ ]
70
+
71
+ expected << [5, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]]
72
+
73
+ expected.concat [
74
+ [6, [["fill", "#ff0000", false], ["fill", "#441234", false], ["fill", "#0000ff", false]]],
66
75
  [7, [["fill", "#550000", false]]],
67
76
  [8, [["fill", "#660000", false]]],
68
77
  [9, [["fill", "#770000", false]]],
@@ -74,6 +83,8 @@ RSpec.describe Prawn::SVG::CSS::Stylesheets do
74
83
  [15, [["fill", "#dd0000", false]]],
75
84
  [16, [["fill", "#ee0000", false]]],
76
85
  ]
86
+
87
+ expect(width_and_styles).to eq(expected)
77
88
  end
78
89
  end
79
90
 
@@ -25,19 +25,19 @@ describe Prawn::SVG::Elements::Base do
25
25
  describe "applying calls from the standard attributes" do
26
26
  let(:svg) do
27
27
  <<-SVG
28
- <something transform="rotate(90)" fill-opacity="0.5" fill="red" stroke="blue" stroke-width="5"/>
28
+ <something transform="scale(2)" fill-opacity="0.5" fill="red" stroke="blue" stroke-width="5"/>
29
29
  SVG
30
30
  end
31
31
 
32
32
  it "appends the relevant calls" do
33
33
  element.process
34
34
  expect(element.base_calls).to eq [
35
- ["rotate", [-90.0, {origin: [0, 600.0]}], [
36
- ["transparent", [0.5, 1], [
37
- ["fill_color", ["ff0000"], []],
38
- ["stroke_color", ["0000ff"], []],
39
- ["line_width", [5.0], []],
40
- ["fill_and_stroke", [], []]
35
+ ["transformation_matrix", [2, 0, 0, 2, 0, 0], {}, [
36
+ ["transparent", [0.5, 1], {}, [
37
+ ["fill_color", ["ff0000"], {}, []],
38
+ ["stroke_color", ["0000ff"], {}, []],
39
+ ["line_width", [5.0], {}, []],
40
+ ["fill_and_stroke", [], {}, []]
41
41
  ]]
42
42
  ]]
43
43
  ]
@@ -50,37 +50,37 @@ describe Prawn::SVG::Elements::Base do
50
50
 
51
51
  context "with neither fill nor stroke" do
52
52
  let(:svg) { '<rect style="fill: none;"></rect>' }
53
- it { is_expected.to eq ['end_path', [], []] }
53
+ it { is_expected.to eq ['end_path', [], {}, []] }
54
54
  end
55
55
 
56
56
  context "with a fill only" do
57
57
  let(:svg) { '<rect style="fill: black;"></rect>' }
58
- it { is_expected.to eq ['fill', [], []] }
58
+ it { is_expected.to eq ['fill', [], {}, []] }
59
59
  end
60
60
 
61
61
  context "with a stroke only" do
62
62
  let(:svg) { '<rect style="fill: none; stroke: black;"></rect>' }
63
- it { is_expected.to eq ['stroke', [], []] }
63
+ it { is_expected.to eq ['stroke', [], {}, []] }
64
64
  end
65
65
 
66
66
  context "with fill and stroke" do
67
67
  let(:svg) { '<rect style="fill: black; stroke: black;"></rect>' }
68
- it { is_expected.to eq ['fill_and_stroke', [], []] }
68
+ it { is_expected.to eq ['fill_and_stroke', [], {}, []] }
69
69
  end
70
70
 
71
71
  context "with fill with evenodd fill rule" do
72
72
  let(:svg) { '<rect style="fill: black; fill-rule: evenodd;"></rect>' }
73
- it { is_expected.to eq ['fill', [{fill_rule: :even_odd}], []] }
73
+ it { is_expected.to eq ['fill', [], {fill_rule: :even_odd}, []] }
74
74
  end
75
75
  end
76
76
 
77
77
  it "appends calls to the parent element" do
78
78
  expect(element).to receive(:apply) do
79
- element.send :add_call, "test", "argument"
79
+ element.send :add_call, "test", "argument", kw: 'argument'
80
80
  end
81
81
 
82
82
  element.process
83
- expect(element.parent_calls).to eq [["fill", [], [["test", ["argument"], []]]]]
83
+ expect(element.parent_calls).to eq [["fill", [], {}, [["test", ["argument"], {kw: 'argument'}, []]]]]
84
84
  end
85
85
 
86
86
  it "quietly absorbs a SkipElementQuietly exception" do
@@ -149,8 +149,8 @@ describe Prawn::SVG::Elements::Base do
149
149
  it "uses the parent's color element if 'currentColor' fill attribute provided" do
150
150
  element.process
151
151
 
152
- expect(flattened_calls).to include ['fill_color', ['ff0000']]
153
- expect(flattened_calls).not_to include ['fill_color', ['00ff00']]
152
+ expect(flattened_calls).to include ['fill_color', ['ff0000'], {}]
153
+ expect(flattened_calls).not_to include ['fill_color', ['00ff00'], {}]
154
154
  end
155
155
  end
156
156