prawn-svg 0.34.2 → 0.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +19 -0
  3. data/.github/workflows/test.yml +14 -27
  4. data/.gitignore +0 -1
  5. data/.rubocop.yml +86 -0
  6. data/.rubocop_todo.yml +51 -0
  7. data/Gemfile +4 -3
  8. data/Gemfile.lock +81 -0
  9. data/README.md +1 -1
  10. data/Rakefile +1 -1
  11. data/lib/prawn/svg/attributes/clip_path.rb +3 -3
  12. data/lib/prawn/svg/attributes/opacity.rb +3 -3
  13. data/lib/prawn/svg/attributes/stroke.rb +9 -9
  14. data/lib/prawn/svg/attributes/transform.rb +2 -2
  15. data/lib/prawn/svg/attributes.rb +1 -1
  16. data/lib/prawn/svg/calculators/arc_to_bezier_curve.rb +17 -15
  17. data/lib/prawn/svg/calculators/aspect_ratio.rb +16 -14
  18. data/lib/prawn/svg/calculators/document_sizing.rb +9 -10
  19. data/lib/prawn/svg/calculators/pixels.rb +8 -5
  20. data/lib/prawn/svg/color.rb +209 -212
  21. data/lib/prawn/svg/css/font_family_parser.rb +2 -2
  22. data/lib/prawn/svg/css/selector_parser.rb +39 -35
  23. data/lib/prawn/svg/css/stylesheets.rb +24 -24
  24. data/lib/prawn/svg/css/values_parser.rb +68 -0
  25. data/lib/prawn/svg/document.rb +6 -5
  26. data/lib/prawn/svg/elements/base.rb +29 -34
  27. data/lib/prawn/svg/elements/circle.rb +4 -4
  28. data/lib/prawn/svg/elements/clip_path.rb +0 -1
  29. data/lib/prawn/svg/elements/depth_first_base.rb +6 -6
  30. data/lib/prawn/svg/elements/ellipse.rb +3 -4
  31. data/lib/prawn/svg/elements/gradient.rb +49 -51
  32. data/lib/prawn/svg/elements/image.rb +5 -5
  33. data/lib/prawn/svg/elements/marker.rb +5 -5
  34. data/lib/prawn/svg/elements/path.rb +46 -47
  35. data/lib/prawn/svg/elements/polygon.rb +1 -1
  36. data/lib/prawn/svg/elements/polyline.rb +2 -2
  37. data/lib/prawn/svg/elements/rect.rb +3 -3
  38. data/lib/prawn/svg/elements/text.rb +1 -1
  39. data/lib/prawn/svg/elements/text_component.rb +22 -22
  40. data/lib/prawn/svg/elements/use.rb +3 -7
  41. data/lib/prawn/svg/elements/viewport.rb +1 -3
  42. data/lib/prawn/svg/elements.rb +30 -29
  43. data/lib/prawn/svg/extension.rb +2 -1
  44. data/lib/prawn/svg/font.rb +7 -7
  45. data/lib/prawn/svg/font_registry.rb +13 -13
  46. data/lib/prawn/svg/gradients.rb +3 -2
  47. data/lib/prawn/svg/interface.rb +4 -3
  48. data/lib/prawn/svg/loaders/data.rb +2 -2
  49. data/lib/prawn/svg/loaders/file.rb +12 -14
  50. data/lib/prawn/svg/loaders/web.rb +4 -8
  51. data/lib/prawn/svg/pathable.rb +41 -37
  52. data/lib/prawn/svg/properties.rb +34 -33
  53. data/lib/prawn/svg/renderer.rb +7 -7
  54. data/lib/prawn/svg/state.rb +1 -1
  55. data/lib/prawn/svg/transform_parser.rb +5 -5
  56. data/lib/prawn/svg/ttf.rb +21 -17
  57. data/lib/prawn/svg/url_loader.rb +1 -1
  58. data/lib/prawn/svg/version.rb +1 -1
  59. data/lib/prawn-svg.rb +1 -0
  60. data/prawn-svg.gemspec +4 -6
  61. data/spec/integration_spec.rb +77 -70
  62. data/spec/prawn/svg/attributes/opacity_spec.rb +11 -15
  63. data/spec/prawn/svg/attributes/transform_spec.rb +6 -6
  64. data/spec/prawn/svg/calculators/aspect_ratio_spec.rb +50 -50
  65. data/spec/prawn/svg/calculators/document_sizing_spec.rb +35 -35
  66. data/spec/prawn/svg/calculators/pixels_spec.rb +31 -30
  67. data/spec/prawn/svg/color_spec.rb +31 -31
  68. data/spec/prawn/svg/css/font_family_parser_spec.rb +12 -12
  69. data/spec/prawn/svg/css/selector_parser_spec.rb +21 -21
  70. data/spec/prawn/svg/css/stylesheets_spec.rb +51 -45
  71. data/spec/prawn/svg/css/values_parser_spec.rb +16 -0
  72. data/spec/prawn/svg/document_spec.rb +15 -14
  73. data/spec/prawn/svg/elements/base_spec.rb +39 -34
  74. data/spec/prawn/svg/elements/gradient_spec.rb +39 -39
  75. data/spec/prawn/svg/elements/line_spec.rb +22 -22
  76. data/spec/prawn/svg/elements/marker_spec.rb +36 -40
  77. data/spec/prawn/svg/elements/path_spec.rb +134 -110
  78. data/spec/prawn/svg/elements/polygon_spec.rb +18 -18
  79. data/spec/prawn/svg/elements/polyline_spec.rb +16 -16
  80. data/spec/prawn/svg/elements/text_spec.rb +149 -127
  81. data/spec/prawn/svg/font_registry_spec.rb +34 -34
  82. data/spec/prawn/svg/font_spec.rb +4 -4
  83. data/spec/prawn/svg/interface_spec.rb +47 -39
  84. data/spec/prawn/svg/loaders/data_spec.rb +21 -21
  85. data/spec/prawn/svg/loaders/file_spec.rb +43 -40
  86. data/spec/prawn/svg/loaders/web_spec.rb +15 -15
  87. data/spec/prawn/svg/pathable_spec.rb +21 -21
  88. data/spec/prawn/svg/properties_spec.rb +51 -51
  89. data/spec/prawn/svg/transform_parser_spec.rb +12 -12
  90. data/spec/prawn/svg/ttf_spec.rb +5 -5
  91. data/spec/prawn/svg/url_loader_spec.rb +25 -23
  92. data/spec/spec_helper.rb +4 -4
  93. metadata +12 -143
@@ -10,15 +10,17 @@ module Prawn::SVG::CSS
10
10
  case token
11
11
  when Modifier
12
12
  part = token.type
13
- result.last[part] ||= part == :name ? +"" : []
13
+ result.last[part] ||= part == :name ? +'' : []
14
14
  when Identifier
15
15
  return unless part
16
+
16
17
  result.last[part] << token.name
17
18
  when Attribute
18
- return unless ["=", "*=", "~=", "^=", "|=", "$=", nil].include?(token.operator)
19
+ return unless ['=', '*=', '~=', '^=', '|=', '$=', nil].include?(token.operator)
20
+
19
21
  (result.last[:attribute] ||= []) << [token.key, token.operator, token.value]
20
22
  when Combinator
21
- result << {combinator: token.type}
23
+ result << { combinator: token.type }
22
24
  part = nil
23
25
  end
24
26
  end
@@ -26,9 +28,7 @@ module Prawn::SVG::CSS
26
28
  result
27
29
  end
28
30
 
29
- private
30
-
31
- VALID_CSS_IDENTIFIER_CHAR = /[a-zA-Z0-9_\u00a0-\uffff-]/
31
+ VALID_CSS_IDENTIFIER_CHAR = /[a-zA-Z0-9_\u00a0-\uffff-]/.freeze
32
32
  Identifier = Struct.new(:name)
33
33
  Modifier = Struct.new(:type)
34
34
  Combinator = Struct.new(:type)
@@ -50,38 +50,38 @@ module Prawn::SVG::CSS
50
50
  if VALID_CSS_IDENTIFIER_CHAR.match(char)
51
51
  result.last.key = String.new(char)
52
52
  attribute = :key
53
- elsif char != " " && char != "\t"
53
+ elsif char != ' ' && char != "\t"
54
54
  return
55
55
  end
56
56
 
57
57
  when :key
58
58
  if VALID_CSS_IDENTIFIER_CHAR.match(char)
59
59
  result.last.key << char
60
- elsif char == "]"
60
+ elsif char == ']'
61
61
  attribute = nil
62
- elsif "=*~^|$".include?(char)
62
+ elsif '=*~^|$'.include?(char)
63
63
  result.last.operator = String.new(char)
64
64
  attribute = :operator
65
- elsif char == " " || char == "\t"
65
+ elsif [' ', "\t"].include?(char)
66
66
  attribute = :pre_operator
67
67
  else
68
68
  return
69
69
  end
70
70
 
71
71
  when :pre_operator
72
- if "=*~^|$".include?(char)
72
+ if '=*~^|$'.include?(char)
73
73
  result.last.operator = String.new(char)
74
74
  attribute = :operator
75
- elsif char != " " && char != "\t"
75
+ elsif char != ' ' && char != "\t"
76
76
  return
77
77
  end
78
78
 
79
79
  when :operator
80
- if "=*~^|$".include?(char)
80
+ if '=*~^|$'.include?(char)
81
81
  result.last.operator << char
82
- elsif char == " " || char == "\t"
82
+ elsif [' ', "\t"].include?(char)
83
83
  attribute = :pre_value
84
- elsif char == '"' || char == "'"
84
+ elsif ['"', "'"].include?(char)
85
85
  result.last.value = +''
86
86
  attribute = String.new(char)
87
87
  else
@@ -90,16 +90,16 @@ module Prawn::SVG::CSS
90
90
  end
91
91
 
92
92
  when :pre_value
93
- if char == '"' || char == "'"
93
+ if ['"', "'"].include?(char)
94
94
  result.last.value = +''
95
95
  attribute = String.new(char)
96
- elsif char != " " && char != "\t"
96
+ elsif char != ' ' && char != "\t"
97
97
  result.last.value = String.new(char)
98
98
  attribute = :value
99
99
  end
100
100
 
101
101
  when :value
102
- if char == "]"
102
+ if char == ']'
103
103
  result.last.value = String.new(result.last.value.rstrip)
104
104
  attribute = nil
105
105
  else
@@ -107,7 +107,7 @@ module Prawn::SVG::CSS
107
107
  end
108
108
 
109
109
  when '"', "'"
110
- if char == "\\" && !quote
110
+ if char == '\\' && !quote
111
111
  quote = true
112
112
  elsif char == attribute && !quote
113
113
  attribute = :post_string
@@ -117,9 +117,9 @@ module Prawn::SVG::CSS
117
117
  end
118
118
 
119
119
  when :post_string
120
- if char == "]"
120
+ if char == ']'
121
121
  attribute = nil
122
- elsif char != " " && char != "\t"
122
+ elsif char != ' ' && char != "\t"
123
123
  return
124
124
  end
125
125
  end
@@ -129,37 +129,41 @@ module Prawn::SVG::CSS
129
129
  when Identifier
130
130
  result.last.name << char
131
131
  else
132
- result << Modifier.new(:name) if !result.last.is_a?(Modifier)
132
+ result << Modifier.new(:name) unless result.last.is_a?(Modifier)
133
133
  result << Identifier.new(char)
134
134
  end
135
135
  else
136
136
  case char
137
- when "."
137
+ when '.'
138
138
  result << Modifier.new(:class)
139
- when "#"
139
+ when '#'
140
140
  result << Modifier.new(:id)
141
- when ":"
141
+ when ':'
142
142
  result << Modifier.new(:pseudo_class)
143
- when " ", "\t"
143
+ when ' ', "\t"
144
144
  result << Combinator.new(:descendant) unless result.last.is_a?(Combinator)
145
- when ">"
145
+ when '>'
146
146
  result.pop if result.last == Combinator.new(:descendant)
147
147
  result << Combinator.new(:child)
148
- when "+"
148
+ when '+'
149
149
  result.pop if result.last == Combinator.new(:descendant)
150
150
  result << Combinator.new(:adjacent)
151
- when "~"
151
+ when '~'
152
152
  result.pop if result.last == Combinator.new(:descendant)
153
153
  result << Combinator.new(:siblings)
154
- when "*"
154
+ when '*'
155
155
  return unless result.empty? || result.last.is_a?(Combinator)
156
+
156
157
  result << Modifier.new(:name)
157
- result << Identifier.new("*")
158
- when "(" # e.g. :nth-child(3n+4)
159
- return unless result.last.is_a?(Identifier) && result[-2] && result[-2].is_a?(Modifier) && result[-2].type == :pseudo_class
160
- result.last.name << "("
158
+ result << Identifier.new('*')
159
+ when '(' # e.g. :nth-child(3n+4)
160
+ unless result.last.is_a?(Identifier) && result[-2] && result[-2].is_a?(Modifier) && result[-2].type == :pseudo_class
161
+ return
162
+ end
163
+
164
+ result.last.name << '('
161
165
  brackets = true
162
- when "["
166
+ when '['
163
167
  result << Attribute.new
164
168
  attribute = :pre_key
165
169
  else
@@ -39,14 +39,14 @@ module Prawn::SVG::CSS
39
39
  rule_set.each_declaration { |*data| declarations << data }
40
40
 
41
41
  rule_set.selectors.each do |selector_text|
42
- if selector = Prawn::SVG::CSS::SelectorParser.parse(selector_text)
43
- xpath = css_selector_to_xpath(selector)
44
- specificity = calculate_specificity(selector)
45
- specificity << order
46
- order += 1
42
+ next unless (selector = Prawn::SVG::CSS::SelectorParser.parse(selector_text))
47
43
 
48
- xpath_styles << [xpath, declarations, specificity]
49
- end
44
+ xpath = css_selector_to_xpath(selector)
45
+ specificity = calculate_specificity(selector)
46
+ specificity << order
47
+ order += 1
48
+
49
+ xpath_styles << [xpath, declarations, specificity]
50
50
  end
51
51
  end
52
52
 
@@ -66,7 +66,7 @@ module Prawn::SVG::CSS
66
66
  end
67
67
 
68
68
  def xpath_quote(value)
69
- %{"#{value.gsub('\\', '\\\\').gsub('"', '\\"')}"} if value
69
+ %("#{value.gsub('\\', '\\\\').gsub('"', '\\"')}") if value
70
70
  end
71
71
 
72
72
  def css_selector_to_xpath(selector)
@@ -76,33 +76,33 @@ module Prawn::SVG::CSS
76
76
 
77
77
  result = case element[:combinator]
78
78
  when :child
79
- +"/"
79
+ +'/'
80
80
  when :adjacent
81
81
  pseudo_classes << 'first-child'
82
- +"/following-sibling::"
82
+ +'/following-sibling::'
83
83
  when :siblings
84
- +"/following-sibling::"
84
+ +'/following-sibling::'
85
85
  else
86
- +"//"
86
+ +'//'
87
87
  end
88
88
 
89
89
  positions = []
90
90
  pseudo_classes.each do |pc|
91
91
  case pc
92
- when "first-child" then positions << '1'
93
- when "last-child" then positions << 'last()'
92
+ when 'first-child' then positions << '1'
93
+ when 'last-child' then positions << 'last()'
94
94
  when /^nth-child\((\d+)\)$/ then positions << $1
95
95
  end
96
96
  end
97
97
 
98
- if !positions.empty?
99
- result << "*" unless require_function_name
98
+ unless positions.empty?
99
+ result << '*' unless require_function_name
100
100
  require_function_name = true
101
101
 
102
102
  logic = if positions.length == 1
103
103
  positions.first
104
104
  else
105
- positions.map { |position| "position()=#{position}" }.join(" and ")
105
+ positions.map { |position| "position()=#{position}" }.join(' and ')
106
106
  end
107
107
 
108
108
  result << "[#{logic}]"
@@ -121,17 +121,17 @@ module Prawn::SVG::CSS
121
121
  case operator
122
122
  when nil
123
123
  result << "[@#{key}]"
124
- when "="
124
+ when '='
125
125
  result << "[@#{key}=#{xpath_quote value}]"
126
- when "^="
126
+ when '^='
127
127
  result << "[starts-with(@#{key}, #{xpath_quote value})]"
128
- when "$="
128
+ when '$='
129
129
  result << "[substring(@#{key}, string-length(@#{key}) - #{value.length - 1}) = #{xpath_quote value})]"
130
- when "*="
130
+ when '*='
131
131
  result << "[contains(@#{key}, #{xpath_quote value})]"
132
- when "~="
132
+ when '~='
133
133
  result << "[contains(concat(' ',@#{key},' '), #{xpath_quote " #{value} "})]"
134
- when "|="
134
+ when '|='
135
135
  result << "[contains(concat('-',@#{key},'-'), #{xpath_quote "-#{value}-"})]"
136
136
  end
137
137
  end
@@ -145,7 +145,7 @@ module Prawn::SVG::CSS
145
145
  [
146
146
  a + (element[:id] || []).length,
147
147
  b + (element[:class] || []).length + (element[:attribute] || []).length + (element[:pseudo_class] || []).length,
148
- c + (element[:name] && element[:name] != "*" ? 1 : 0)
148
+ c + (element[:name] && element[:name] != '*' ? 1 : 0)
149
149
  ]
150
150
  end
151
151
  end
@@ -0,0 +1,68 @@
1
+ module Prawn::SVG::CSS
2
+ class ValuesParser
3
+ class << self
4
+ def parse(values)
5
+ result = []
6
+
7
+ while values
8
+ value, remainder = parse_next(values)
9
+ break unless value
10
+
11
+ result << value
12
+ values = remainder
13
+ end
14
+
15
+ result
16
+ end
17
+
18
+ private
19
+
20
+ def parse_next(values)
21
+ values = values.strip
22
+ return if values.empty?
23
+
24
+ if (matches = values.match(/\A([a-z-]+)\(\s*(.+)/i))
25
+ parse_function_call(matches[1].downcase, matches[2])
26
+ else
27
+ values.split(/\s+/, 2)
28
+ end
29
+ end
30
+
31
+ # Note this does not support space-separated arguments.
32
+ # I don't think CSS 2 has any, but in case it does here is the place to add them.
33
+ def parse_function_call(name, rest)
34
+ arguments = []
35
+ in_quote = nil
36
+ in_escape = false
37
+ current = +''
38
+
39
+ rest.each_char.with_index do |char, index|
40
+ if in_escape
41
+ current << char
42
+ in_escape = false
43
+ elsif %w[" '].include?(char)
44
+ if in_quote == char
45
+ in_quote = nil
46
+ elsif in_quote.nil?
47
+ in_quote = char
48
+ else
49
+ current << char
50
+ end
51
+ elsif char == '\\'
52
+ in_escape = true
53
+ elsif in_quote.nil? && char == ','
54
+ arguments << current.strip
55
+ current = +''
56
+ elsif in_quote.nil? && char == ')'
57
+ arguments << current.strip
58
+ return [[name, arguments], rest[index + 1..]]
59
+ else
60
+ current << char
61
+ end
62
+ end
63
+
64
+ [rest, nil]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -2,7 +2,7 @@ class Prawn::SVG::Document
2
2
  Error = Class.new(StandardError)
3
3
  InvalidSVGData = Class.new(Error)
4
4
 
5
- DEFAULT_FALLBACK_FONT_NAME = "Times-Roman"
5
+ DEFAULT_FALLBACK_FONT_NAME = 'Times-Roman'.freeze
6
6
 
7
7
  # An +Array+ of warnings that occurred while parsing the SVG data.
8
8
  attr_reader :warnings
@@ -20,10 +20,11 @@ class Prawn::SVG::Document
20
20
  @root = REXML::Document.new(data).root
21
21
 
22
22
  if @root.nil?
23
- if data.respond_to?(:end_with?) && data.end_with?(".svg")
24
- raise InvalidSVGData, "The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg."
23
+ if data.respond_to?(:end_with?) && data.end_with?('.svg')
24
+ raise InvalidSVGData,
25
+ "The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg."
25
26
  else
26
- raise InvalidSVGData, "The data supplied is not a valid SVG document."
27
+ raise InvalidSVGData, 'The data supplied is not a valid SVG document.'
27
28
  end
28
29
  end
29
30
 
@@ -65,7 +66,7 @@ class Prawn::SVG::Document
65
66
  when nil, :rgb then :rgb
66
67
  when :cmyk then :cmyk
67
68
  else
68
- raise ArgumentError, ":color_mode must be set to :rgb (default) or :cmyk"
69
+ raise ArgumentError, ':color_mode must be set to :rgb (default) or :cmyk'
69
70
  end
70
71
  end
71
72
  end
@@ -13,9 +13,9 @@ class Prawn::SVG::Elements::Base
13
13
 
14
14
  include Prawn::SVG::TransformParser
15
15
 
16
- PAINT_TYPES = %w(fill stroke)
16
+ PAINT_TYPES = %w[fill stroke].freeze
17
17
  COMMA_WSP_REGEXP = Prawn::SVG::Elements::COMMA_WSP_REGEXP
18
- SVG_NAMESPACE = "http://www.w3.org/2000/svg"
18
+ SVG_NAMESPACE = 'http://www.w3.org/2000/svg'.freeze
19
19
 
20
20
  SkipElementQuietly = Class.new(StandardError)
21
21
  SkipElementError = Class.new(StandardError)
@@ -37,7 +37,7 @@ class Prawn::SVG::Elements::Base
37
37
  @properties = Prawn::SVG::Properties.new
38
38
 
39
39
  if source && !state.inside_use
40
- id = source.attributes["id"]
40
+ id = source.attributes['id']
41
41
  id = id.strip if id
42
42
 
43
43
  document.elements_by_id[id] = self if id && id != ''
@@ -65,19 +65,16 @@ class Prawn::SVG::Elements::Base
65
65
  end
66
66
 
67
67
  def name
68
- @name ||= source ? source.name : "???"
68
+ @name ||= source ? source.name : '???'
69
69
  end
70
70
 
71
71
  protected
72
72
 
73
- def parse
74
- end
73
+ def parse; end
75
74
 
76
- def apply
77
- end
75
+ def apply; end
78
76
 
79
- def bounding_box
80
- end
77
+ def bounding_box; end
81
78
 
82
79
  def container?
83
80
  false
@@ -128,13 +125,13 @@ class Prawn::SVG::Elements::Base
128
125
  return unless source
129
126
 
130
127
  svg_child_elements.each do |elem|
131
- if element_class = Prawn::SVG::Elements::TAG_CLASS_MAPPING[elem.name.to_sym]
132
- add_call "save"
128
+ if (element_class = Prawn::SVG::Elements::TAG_CLASS_MAPPING[elem.name.to_sym])
129
+ add_call 'save'
133
130
 
134
131
  child = element_class.new(@document, elem, @calls, state.dup)
135
132
  child.process
136
133
 
137
- add_call "restore"
134
+ add_call 'restore'
138
135
  else
139
136
  @document.warnings << "Unknown tag '#{elem.name}'; ignoring"
140
137
  end
@@ -185,9 +182,7 @@ class Prawn::SVG::Elements::Base
185
182
 
186
183
  next if [nil, 'inherit', 'none'].include?(color)
187
184
 
188
- if color == 'currentColor'
189
- color = computed_properties.color
190
- end
185
+ color = computed_properties.color if color == 'currentColor'
191
186
 
192
187
  results = Prawn::SVG::Color.parse(color, document.gradients, document.color_mode)
193
188
 
@@ -207,18 +202,12 @@ class Prawn::SVG::Elements::Base
207
202
 
208
203
  # If we were unable to find a suitable color candidate,
209
204
  # we turn off this type of paint.
210
- if success.nil?
211
- computed_properties.set(type, 'none')
212
- end
205
+ computed_properties.set(type, 'none') if success.nil?
213
206
  end
214
207
  end
215
208
 
216
- def clamp(value, min_value, max_value)
217
- [[value, min_value].max, max_value].min
218
- end
219
-
220
209
  def extract_attributes_and_properties
221
- if styles = document.element_styles[source]
210
+ if (styles = document.element_styles[source])
222
211
  # TODO : implement !important, at the moment it's just ignored
223
212
  styles.each do |name, value, _important|
224
213
  @properties.set(name, value)
@@ -238,11 +227,11 @@ class Prawn::SVG::Elements::Base
238
227
  def parse_css_declarations(declarations)
239
228
  # copied from css_parser
240
229
  declarations
241
- .gsub(/(^[\s]*)|([\s]*$)/, '')
242
- .split(/[\;$]+/m)
230
+ .gsub(/(^\s*)|(\s*$)/, '')
231
+ .split(/[;$]+/m)
243
232
  .each_with_object({}) do |decs, output|
244
- if matches = decs.match(/\s*(.[^:]*)\s*\:\s*(.[^;]*)\s*(;|\Z)/i)
245
- property, value, _ = matches.captures
233
+ if (matches = decs.match(/\s*(.[^:]*)\s*:\s*(.[^;]*)\s*(;|\Z)/i))
234
+ property, value, = matches.captures
246
235
  output[property.downcase] = value
247
236
  end
248
237
  end
@@ -251,20 +240,26 @@ class Prawn::SVG::Elements::Base
251
240
  def require_attributes(*names)
252
241
  missing_attrs = names - attributes.keys
253
242
  if missing_attrs.any?
254
- raise MissingAttributesError, "Must have attributes #{missing_attrs.join(", ")} on tag #{name}; skipping tag"
243
+ raise MissingAttributesError, "Must have attributes #{missing_attrs.join(', ')} on tag #{name}; skipping tag"
255
244
  end
256
245
  end
257
246
 
258
247
  def require_positive_value(*args)
259
- if args.any? {|arg| arg.nil? || arg <= 0}
248
+ if args.any? { |arg| arg.nil? || arg <= 0 }
260
249
  raise SkipElementError, "Invalid attributes on tag #{name}; skipping tag"
261
250
  end
262
251
  end
263
252
 
264
- def extract_element_from_url_id_reference(value, expected_type = nil)
265
- matches = value.strip.match(/\Aurl\(\s*#(\S+)\s*\)\z/i) if value
266
- element = document.elements_by_id[matches[1]] if matches
267
- element if element && (expected_type.nil? || element.name == expected_type)
253
+ def extract_element_from_url_id_reference(values, expected_type = nil)
254
+ Prawn::SVG::CSS::ValuesParser.parse(values).detect do |value|
255
+ case value
256
+ in ['url', [url]]
257
+ element = document.elements_by_id[url[1..]] if url.start_with?('#')
258
+ break element if element && (expected_type.nil? || element.name == expected_type)
259
+ else
260
+ nil
261
+ end
262
+ end
268
263
  end
269
264
 
270
265
  def href_attribute
@@ -4,8 +4,8 @@ class Prawn::SVG::Elements::Circle < Prawn::SVG::Elements::Base
4
4
  def parse
5
5
  require_attributes 'r'
6
6
 
7
- @x = x(attributes['cx'] || "0")
8
- @y = y(attributes['cy'] || "0")
7
+ @x = x(attributes['cx'] || '0')
8
+ @y = y(attributes['cy'] || '0')
9
9
  @r = pixels(attributes['r'])
10
10
 
11
11
  require_positive_value @r
@@ -13,9 +13,9 @@ class Prawn::SVG::Elements::Circle < Prawn::SVG::Elements::Base
13
13
 
14
14
  def apply
15
15
  if USE_NEW_CIRCLE_CALL
16
- add_call "circle", [@x, @y], @r
16
+ add_call 'circle', [@x, @y], @r
17
17
  else
18
- add_call "circle_at", [@x, @y], radius: @r
18
+ add_call 'circle_at', [@x, @y], radius: @r
19
19
  end
20
20
  end
21
21
 
@@ -9,4 +9,3 @@ class Prawn::SVG::Elements::ClipPath < Prawn::SVG::Elements::Base
9
9
  true
10
10
  end
11
11
  end
12
-
@@ -13,7 +13,7 @@ class Prawn::SVG::Elements::DepthFirstBase < Prawn::SVG::Elements::Base
13
13
  end
14
14
 
15
15
  def parse_and_apply
16
- raise "unsupported"
16
+ raise 'unsupported'
17
17
  end
18
18
 
19
19
  protected
@@ -36,11 +36,11 @@ class Prawn::SVG::Elements::DepthFirstBase < Prawn::SVG::Elements::Base
36
36
  return unless source
37
37
 
38
38
  svg_child_elements.each do |elem|
39
- if element_class = Prawn::SVG::Elements::TAG_CLASS_MAPPING[elem.name.to_sym]
40
- child = element_class.new(@document, elem, @calls, state.dup)
41
- child.parse_step
42
- @children << child
43
- end
39
+ next unless (element_class = Prawn::SVG::Elements::TAG_CLASS_MAPPING[elem.name.to_sym])
40
+
41
+ child = element_class.new(@document, elem, @calls, state.dup)
42
+ child.parse_step
43
+ @children << child
44
44
  end
45
45
  end
46
46
 
@@ -4,8 +4,8 @@ class Prawn::SVG::Elements::Ellipse < Prawn::SVG::Elements::Base
4
4
  def parse
5
5
  require_attributes 'rx', 'ry'
6
6
 
7
- @x = x(attributes['cx'] || "0")
8
- @y = y(attributes['cy'] || "0")
7
+ @x = x(attributes['cx'] || '0')
8
+ @y = y(attributes['cy'] || '0')
9
9
  @rx = x_pixels(attributes['rx'])
10
10
  @ry = y_pixels(attributes['ry'])
11
11
 
@@ -13,11 +13,10 @@ class Prawn::SVG::Elements::Ellipse < Prawn::SVG::Elements::Base
13
13
  end
14
14
 
15
15
  def apply
16
- add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at", [@x, @y], @rx, @ry
16
+ add_call USE_NEW_ELLIPSE_CALL ? 'ellipse' : 'ellipse_at', [@x, @y], @rx, @ry
17
17
  end
18
18
 
19
19
  def bounding_box
20
20
  [@x - @rx, @y + @ry, @x + @rx, @y - @ry]
21
21
  end
22
22
  end
23
-