inline_svg 1.2.0 → 1.3.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.

Potentially problematic release.


This version of inline_svg might be problematic. Click here for more details.

Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +421 -0
  4. data/CHANGELOG.md +35 -1
  5. data/README.md +46 -9
  6. data/Rakefile +7 -0
  7. data/inline_svg.gemspec +1 -0
  8. data/lib/inline_svg/action_view/helpers.rb +29 -6
  9. data/lib/inline_svg/cached_asset_file.rb +17 -3
  10. data/lib/inline_svg/id_generator.rb +9 -2
  11. data/lib/inline_svg/io_resource.rb +4 -3
  12. data/lib/inline_svg/transform_pipeline/transformations/aria_attributes.rb +16 -19
  13. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden.rb +9 -0
  14. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden_attribute.rb +9 -0
  15. data/lib/inline_svg/transform_pipeline/transformations/class_attribute.rb +5 -6
  16. data/lib/inline_svg/transform_pipeline/transformations/data_attributes.rb +4 -5
  17. data/lib/inline_svg/transform_pipeline/transformations/description.rb +7 -6
  18. data/lib/inline_svg/transform_pipeline/transformations/height.rb +3 -4
  19. data/lib/inline_svg/transform_pipeline/transformations/id_attribute.rb +3 -4
  20. data/lib/inline_svg/transform_pipeline/transformations/no_comment.rb +4 -4
  21. data/lib/inline_svg/transform_pipeline/transformations/preserve_aspect_ratio.rb +3 -4
  22. data/lib/inline_svg/transform_pipeline/transformations/size.rb +4 -5
  23. data/lib/inline_svg/transform_pipeline/transformations/style_attribute.rb +11 -0
  24. data/lib/inline_svg/transform_pipeline/transformations/title.rb +7 -6
  25. data/lib/inline_svg/transform_pipeline/transformations/transformation.rb +13 -0
  26. data/lib/inline_svg/transform_pipeline/transformations/width.rb +3 -4
  27. data/lib/inline_svg/transform_pipeline/transformations.rb +4 -0
  28. data/lib/inline_svg/version.rb +1 -1
  29. data/lib/inline_svg.rb +16 -9
  30. data/spec/cached_asset_file_spec.rb +12 -0
  31. data/spec/files/static_assets/assets0/known-document-two.svg +1 -0
  32. data/spec/helpers/inline_svg_spec.rb +46 -1
  33. data/spec/id_generator_spec.rb +5 -3
  34. data/spec/inline_svg_spec.rb +10 -0
  35. data/spec/transformation_pipeline/transformations/aria_attributes_spec.rb +6 -6
  36. data/spec/transformation_pipeline/transformations/aria_hidden_attribute_spec.rb +12 -0
  37. data/spec/transformation_pipeline/transformations/height_spec.rb +9 -0
  38. data/spec/transformation_pipeline/transformations/style_attribute_spec.rb +26 -0
  39. data/spec/transformation_pipeline/transformations/title_spec.rb +9 -0
  40. data/spec/transformation_pipeline/transformations/transformation_spec.rb +39 -0
  41. data/spec/transformation_pipeline/transformations_spec.rb +5 -1
  42. metadata +30 -3
@@ -1,7 +1,14 @@
1
1
  module InlineSvg
2
2
  class IdGenerator
3
- def self.generate(base, salt)
4
- bytes = Digest::SHA1.digest("#{base}-#{salt}")
3
+ class Randomness
4
+ require "securerandom"
5
+ def self.call
6
+ SecureRandom.hex(10)
7
+ end
8
+ end
9
+
10
+ def self.generate(base, salt, randomness: Randomness)
11
+ bytes = Digest::SHA1.digest("#{base}-#{salt}-#{randomness.call}")
5
12
  Digest.hexencode(bytes).to_i(16).to_s(36)
6
13
  end
7
14
  end
@@ -1,16 +1,17 @@
1
1
  module InlineSvg
2
2
  module IOResource
3
- def self.=== object
3
+ def self.===(object)
4
4
  object.is_a?(IO) || object.is_a?(StringIO)
5
5
  end
6
6
 
7
- def self.default_for object
7
+ def self.default_for(object)
8
8
  case object
9
9
  when StringIO then ''
10
10
  when IO then 1
11
11
  end
12
12
  end
13
- def self.read object
13
+
14
+ def self.read(object)
14
15
  start = object.pos
15
16
  str = object.read
16
17
  object.seek start
@@ -1,34 +1,31 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class AriaAttributes < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css("svg")
4
+ with_svg(doc) do |svg|
5
+ # Add role
6
+ svg["role"] = "img"
6
7
 
7
- # Add role
8
- svg["role"] = "img"
8
+ # Build aria-labelledby string
9
+ aria_elements = []
10
+ svg.search("title").each do |element|
11
+ aria_elements << element["id"] = element_id_for("title", element)
12
+ end
9
13
 
10
- # Build aria-labelledby string
11
- aria_elements = []
12
- doc.search("svg title").each do |element|
13
- aria_elements << element['id'] = element_id_for("title", element)
14
- end
15
-
16
- doc.search("svg desc").each do |element|
17
- aria_elements << element['id'] = element_id_for("desc", element)
18
- end
14
+ svg.search("desc").each do |element|
15
+ aria_elements << element["id"] = element_id_for("desc", element)
16
+ end
19
17
 
20
- if aria_elements.any?
21
- svg["aria-labelledby"] = aria_elements.join(" ")
18
+ if aria_elements.any?
19
+ svg["aria-labelledby"] = aria_elements.join(" ")
20
+ end
22
21
  end
23
-
24
- doc
25
22
  end
26
23
 
27
24
  def element_id_for(base, element)
28
- if element['id'].nil?
25
+ if element["id"].nil?
29
26
  InlineSvg::IdGenerator.generate(base, element.text)
30
27
  else
31
- InlineSvg::IdGenerator.generate(element['id'], element.text)
28
+ InlineSvg::IdGenerator.generate(element["id"], element.text)
32
29
  end
33
30
  end
34
31
  end
@@ -0,0 +1,9 @@
1
+ module InlineSvg::TransformPipeline::Transformations
2
+ class AriaHidden < Transformation
3
+ def transform(doc)
4
+ with_svg(doc) do |svg|
5
+ svg["aria-hidden"] = self.value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module InlineSvg::TransformPipeline::Transformations
2
+ class AriaHiddenAttribute < Transformation
3
+ def transform(doc)
4
+ with_svg(doc) do |svg|
5
+ svg["aria-hidden"] = self.value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,12 +1,11 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class ClassAttribute < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css "svg"
6
- classes = (svg["class"] || "").split(" ")
7
- classes << value
8
- svg["class"] = classes.join(" ")
9
- doc
4
+ with_svg(doc) do |svg|
5
+ classes = (svg["class"] || "").split(" ")
6
+ classes << value
7
+ svg["class"] = classes.join(" ")
8
+ end
10
9
  end
11
10
  end
12
11
  end
@@ -1,12 +1,11 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class DataAttributes < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- with_valid_hash_from(self.value).each_pair do |name, data|
7
- svg["data-#{dasherize(name)}"] = data
4
+ with_svg(doc) do |svg|
5
+ with_valid_hash_from(self.value).each_pair do |name, data|
6
+ svg["data-#{dasherize(name)}"] = data
7
+ end
8
8
  end
9
- doc
10
9
  end
11
10
 
12
11
  private
@@ -1,12 +1,13 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class Description < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- node = Nokogiri::XML::Node.new('desc', doc)
6
- node.content = value
7
- doc.search('svg desc').each { |node| node.remove }
8
- doc.at_css('svg').prepend_child(node)
9
- doc
4
+ with_svg(doc) do |svg|
5
+ node = Nokogiri::XML::Node.new("desc", doc)
6
+ node.content = value
7
+
8
+ svg.search("desc").each { |node| node.remove }
9
+ svg.prepend_child(node)
10
+ end
10
11
  end
11
12
  end
12
13
  end
@@ -1,10 +1,9 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class Height < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- svg['height'] = self.value
7
- doc
4
+ with_svg(doc) do |svg|
5
+ svg["height"] = self.value
6
+ end
8
7
  end
9
8
  end
10
9
  end
@@ -1,10 +1,9 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class IdAttribute < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- svg['id'] = self.value
7
- doc
4
+ with_svg(doc) do |svg|
5
+ svg["id"] = self.value
6
+ end
8
7
  end
9
8
  end
10
9
  end
@@ -2,11 +2,11 @@ module InlineSvg::TransformPipeline
2
2
  module Transformations
3
3
  class NoComment < Transformation
4
4
  def transform(doc)
5
- doc = Nokogiri::XML::Document.parse(doc.to_html)
6
- doc.xpath("//comment()").each do |comment|
7
- comment.remove
5
+ with_svg(doc) do |svg|
6
+ svg.xpath("//comment()").each do |comment|
7
+ comment.remove
8
+ end
8
9
  end
9
- doc
10
10
  end
11
11
  end
12
12
  end
@@ -1,10 +1,9 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class PreserveAspectRatio < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- svg['preserveAspectRatio'] = self.value
7
- doc
4
+ with_svg(doc) do |svg|
5
+ svg["preserveAspectRatio"] = self.value
6
+ end
8
7
  end
9
8
  end
10
9
  end
@@ -1,11 +1,10 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class Size < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- svg['width'] = width_of(self.value)
7
- svg['height'] = height_of(self.value)
8
- doc
4
+ with_svg(doc) do |svg|
5
+ svg["width"] = width_of(self.value)
6
+ svg["height"] = height_of(self.value)
7
+ end
9
8
  end
10
9
 
11
10
  def width_of(value)
@@ -0,0 +1,11 @@
1
+ module InlineSvg::TransformPipeline::Transformations
2
+ class StyleAttribute < Transformation
3
+ def transform(doc)
4
+ with_svg(doc) do |svg|
5
+ styles = svg["style"].to_s.split(";")
6
+ styles << value
7
+ svg["style"] = styles.join(";")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,12 +1,13 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class Title < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- node = Nokogiri::XML::Node.new('title', doc)
6
- node.content = value
7
- doc.search('svg title').each { |node| node.remove }
8
- doc.at_css('svg').prepend_child(node)
9
- doc
4
+ with_svg(doc) do |svg|
5
+ node = Nokogiri::XML::Node.new("title", doc)
6
+ node.content = value
7
+
8
+ svg.search("title").each { |node| node.remove }
9
+ svg.prepend_child(node)
10
+ end
10
11
  end
11
12
  end
12
13
  end
@@ -13,6 +13,19 @@ module InlineSvg::TransformPipeline::Transformations
13
13
  def transform(*)
14
14
  raise "#transform should be implemented by subclasses of Transformation"
15
15
  end
16
+
17
+ # Parses a document and yields the contained SVG nodeset to the given block
18
+ # if it exists.
19
+ #
20
+ # Returns a Nokogiri::XML::Document.
21
+ def with_svg(doc)
22
+ doc = Nokogiri::XML::Document.parse(
23
+ doc.to_html(encoding: "UTF-8"), nil, "UTF-8"
24
+ )
25
+ svg = doc.at_css "svg"
26
+ yield svg if svg && block_given?
27
+ doc
28
+ end
16
29
  end
17
30
 
18
31
  class NullTransformation < Transformation
@@ -1,10 +1,9 @@
1
1
  module InlineSvg::TransformPipeline::Transformations
2
2
  class Width < Transformation
3
3
  def transform(doc)
4
- doc = Nokogiri::XML::Document.parse(doc.to_html)
5
- svg = doc.at_css 'svg'
6
- svg['width'] = self.value
7
- doc
4
+ with_svg(doc) do |svg|
5
+ svg["width"] = self.value
6
+ end
8
7
  end
9
8
  end
10
9
  end
@@ -6,7 +6,9 @@ module InlineSvg::TransformPipeline::Transformations
6
6
  desc: { transform: Description, priority: 2 },
7
7
  title: { transform: Title, priority: 3 },
8
8
  aria: { transform: AriaAttributes },
9
+ aria_hidden: { transform: AriaHiddenAttribute },
9
10
  class: { transform: ClassAttribute },
11
+ style: { transform: StyleAttribute },
10
12
  data: { transform: DataAttributes },
11
13
  height: { transform: Height },
12
14
  nocomment: { transform: NoComment },
@@ -72,6 +74,7 @@ end
72
74
  require 'inline_svg/transform_pipeline/transformations/transformation'
73
75
  require 'inline_svg/transform_pipeline/transformations/no_comment'
74
76
  require 'inline_svg/transform_pipeline/transformations/class_attribute'
77
+ require 'inline_svg/transform_pipeline/transformations/style_attribute'
75
78
  require 'inline_svg/transform_pipeline/transformations/title'
76
79
  require 'inline_svg/transform_pipeline/transformations/description'
77
80
  require 'inline_svg/transform_pipeline/transformations/size'
@@ -81,3 +84,4 @@ require 'inline_svg/transform_pipeline/transformations/id_attribute'
81
84
  require 'inline_svg/transform_pipeline/transformations/data_attributes'
82
85
  require 'inline_svg/transform_pipeline/transformations/preserve_aspect_ratio'
83
86
  require 'inline_svg/transform_pipeline/transformations/aria_attributes'
87
+ require "inline_svg/transform_pipeline/transformations/aria_hidden_attribute"
@@ -1,3 +1,3 @@
1
1
  module InlineSvg
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
data/lib/inline_svg.rb CHANGED
@@ -15,11 +15,12 @@ module InlineSvg
15
15
  class Configuration
16
16
  class Invalid < ArgumentError; end
17
17
 
18
- attr_reader :asset_file, :asset_finder, :custom_transformations
18
+ attr_reader :asset_file, :asset_finder, :custom_transformations, :svg_not_found_css_class
19
19
 
20
20
  def initialize
21
21
  @custom_transformations = {}
22
22
  @asset_file = InlineSvg::AssetFile
23
+ @svg_not_found_css_class = nil
23
24
  end
24
25
 
25
26
  def asset_file=(custom_asset_file)
@@ -36,17 +37,23 @@ module InlineSvg
36
37
  end
37
38
 
38
39
  def asset_finder=(finder)
39
- if finder.respond_to?(:find_asset)
40
- @asset_finder = finder
41
- else
42
- # fallback to a naive static asset finder (sprokects >= 3.0 &&
43
- # config.assets.precompile = false
44
- # See: https://github.com/jamesmartin/inline_svg/issues/25
45
- @asset_finder = InlineSvg::StaticAssetFinder
46
- end
40
+ @asset_finder = if finder.respond_to?(:find_asset)
41
+ finder
42
+ else
43
+ # fallback to a naive static asset finder
44
+ # (sprokects >= 3.0 && config.assets.precompile = false
45
+ # See: https://github.com/jamesmartin/inline_svg/issues/25
46
+ InlineSvg::StaticAssetFinder
47
+ end
47
48
  asset_finder
48
49
  end
49
50
 
51
+ def svg_not_found_css_class=(css_class)
52
+ if css_class.present? && css_class.is_a?(String)
53
+ @svg_not_found_css_class = css_class
54
+ end
55
+ end
56
+
50
57
  def add_custom_transformation(options)
51
58
  if incompatible_transformation?(options.fetch(:transform))
52
59
  raise InlineSvg::Configuration::Invalid.new("#{options.fetch(:transform)} should implement the .create_with_value and #transform methods")
@@ -34,6 +34,18 @@ describe InlineSvg::CachedAssetFile do
34
34
  expect(known_document_1).to eq(asset_loader.named("assets1/known-document.svg"))
35
35
  end
36
36
 
37
+ it "chooses the closest exact matching file when similar files exist in the same path" do
38
+ known_document = File.read(fixture_path.join("assets0", "known-document.svg"))
39
+ known_document_2 = File.read(fixture_path.join("assets0", "known-document-two.svg"))
40
+
41
+ expect(known_document).not_to eq(known_document_2)
42
+
43
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path.join("assets0"), filters: /\.svg/)
44
+
45
+ expect(asset_loader.named("known-document")).to eq(known_document)
46
+ expect(asset_loader.named("known-document-two")).to eq(known_document_2)
47
+ end
48
+
37
49
  it "filters wanted files by simple string matching" do
38
50
  known_document_0 = File.read(fixture_path.join("assets0", "known-document.svg"))
39
51
  known_document_1 = File.read(fixture_path.join("assets1", "known-document.svg"))
@@ -0,0 +1 @@
1
+ <svg>other interesting content</svg>
@@ -14,8 +14,12 @@ describe InlineSvg::ActionView::Helpers do
14
14
  let(:helper) { ( Class.new { include InlineSvg::ActionView::Helpers } ).new }
15
15
 
16
16
  describe "#inline_svg" do
17
-
17
+
18
18
  context "when passed the name of an SVG that does not exist" do
19
+ after(:each) do
20
+ InlineSvg.reset_configuration!
21
+ end
22
+
19
23
  it "returns an empty, html safe, SVG document as a placeholder" do
20
24
  allow(InlineSvg::AssetFile).to receive(:named).
21
25
  with('some-missing-file.svg').
@@ -34,6 +38,34 @@ describe InlineSvg::ActionView::Helpers do
34
38
  output = helper.inline_svg('missing-file-with-no-extension')
35
39
  expect(output).to eq "<svg><!-- SVG file not found: 'missing-file-with-no-extension' (Try adding .svg to your filename) --></svg>"
36
40
  end
41
+
42
+ it "allows the CSS class on the empty SVG document to be changed" do
43
+ InlineSvg.configure do |config|
44
+ config.svg_not_found_css_class = 'missing-svg'
45
+ end
46
+
47
+ allow(InlineSvg::AssetFile).to receive(:named).
48
+ with('some-other-missing-file.svg').
49
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
50
+
51
+ output = helper.inline_svg('some-other-missing-file.svg')
52
+ expect(output).to eq "<svg class='missing-svg'><!-- SVG file not found: 'some-other-missing-file.svg' --></svg>"
53
+ expect(output).to be_html_safe
54
+ end
55
+
56
+ context "and a fallback that does exist" do
57
+ it "displays the fallback" do
58
+ allow(InlineSvg::AssetFile).to receive(:named).
59
+ with('missing.svg').
60
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
61
+
62
+ fallback_file = <<-SVG
63
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><!-- This is a comment --></svg>
64
+ SVG
65
+ allow(InlineSvg::AssetFile).to receive(:named).with('fallback.svg').and_return(fallback_file)
66
+ expect(helper.inline_svg('missing.svg', fallback: 'fallback.svg')).to eq fallback_file
67
+ end
68
+ end
37
69
  end
38
70
 
39
71
  context "when passed an existing SVG file" do
@@ -87,6 +119,19 @@ SVG
87
119
  end
88
120
  end
89
121
 
122
+ context "and the 'aria_hidden' option" do
123
+ it "sets 'aria-hidden=true' in the output" do
124
+ input_svg = <<-SVG
125
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"></svg>
126
+ SVG
127
+ expected_output = <<-SVG
128
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en" aria-hidden="true"></svg>
129
+ SVG
130
+ allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
131
+ expect(helper.inline_svg('some-file', aria_hidden: true)).to eq expected_output
132
+ end
133
+ end
134
+
90
135
  context "and all options" do
91
136
  it "applies all expected transformations to the output" do
92
137
  input_svg = <<-SVG
@@ -1,8 +1,10 @@
1
1
  require_relative '../lib/inline_svg/id_generator'
2
2
 
3
3
  describe InlineSvg::IdGenerator do
4
- it "generates a hexencoded ID based on a salt" do
5
- expect(InlineSvg::IdGenerator.generate("some-base", "some-salt")).
6
- to eq("ksiuuy1jduycacqpoj5smn2kyt9iv02")
4
+ it "generates a hexencoded ID based on a salt and a random value" do
5
+ randomizer = -> { "some-random-value" }
6
+
7
+ expect(InlineSvg::IdGenerator.generate("some-base", "some-salt", randomness: randomizer)).
8
+ to eq("t2c17mkqnvopy36iccxspura7wnreqf")
7
9
  end
8
10
  end
@@ -80,6 +80,16 @@ describe InlineSvg do
80
80
  end
81
81
  end
82
82
 
83
+ context "configuring the default svg-not-found class" do
84
+ it "sets the class name" do
85
+ InlineSvg.configure do |config|
86
+ config.svg_not_found_css_class = 'missing-svg'
87
+ end
88
+
89
+ expect(InlineSvg.configuration.svg_not_found_css_class).to eq 'missing-svg'
90
+ end
91
+ end
92
+
83
93
  context "configuring custom transformation" do
84
94
  it "allows a custom transformation to be added" do
85
95
  InlineSvg.configure do |config|
@@ -1,8 +1,8 @@
1
- require 'inline_svg/transform_pipeline'
1
+ require "inline_svg/transform_pipeline"
2
2
 
3
3
  describe InlineSvg::TransformPipeline::Transformations::AriaAttributes do
4
4
  it "adds a role attribute to the SVG document" do
5
- document = Nokogiri::XML::Document.parse('<svg>Some document</svg>')
5
+ document = Nokogiri::XML::Document.parse("<svg>Some document</svg>")
6
6
  transformation = InlineSvg::TransformPipeline::Transformations::AriaAttributes.create_with_value({})
7
7
 
8
8
  expect(transformation.transform(document).to_html).to eq(
@@ -12,7 +12,7 @@ describe InlineSvg::TransformPipeline::Transformations::AriaAttributes do
12
12
 
13
13
  context "aria-labelledby attribute" do
14
14
  it "adds 'title' when a title element is present" do
15
- document = Nokogiri::XML::Document.parse('<svg><title>Some title</title>Some document</svg>')
15
+ document = Nokogiri::XML::Document.parse("<svg><title>Some title</title>Some document</svg>")
16
16
  transformation = InlineSvg::TransformPipeline::Transformations::AriaAttributes.create_with_value(true)
17
17
 
18
18
  expect(InlineSvg::IdGenerator).to receive(:generate).with("title", "Some title").
@@ -24,7 +24,7 @@ describe InlineSvg::TransformPipeline::Transformations::AriaAttributes do
24
24
  end
25
25
 
26
26
  it "adds 'desc' when a description element is present" do
27
- document = Nokogiri::XML::Document.parse('<svg><desc>Some description</desc>Some document</svg>')
27
+ document = Nokogiri::XML::Document.parse("<svg><desc>Some description</desc>Some document</svg>")
28
28
  transformation = InlineSvg::TransformPipeline::Transformations::AriaAttributes.create_with_value(true)
29
29
 
30
30
  expect(InlineSvg::IdGenerator).to receive(:generate).with("desc", "Some description").
@@ -36,7 +36,7 @@ describe InlineSvg::TransformPipeline::Transformations::AriaAttributes do
36
36
  end
37
37
 
38
38
  it "adds both 'desc' and 'title' when title and description elements are present" do
39
- document = Nokogiri::XML::Document.parse('<svg><title>Some title</title><desc>Some description</desc>Some document</svg>')
39
+ document = Nokogiri::XML::Document.parse("<svg><title>Some title</title><desc>Some description</desc>Some document</svg>")
40
40
  transformation = InlineSvg::TransformPipeline::Transformations::AriaAttributes.create_with_value(true)
41
41
 
42
42
  expect(InlineSvg::IdGenerator).to receive(:generate).with("title", "Some title").
@@ -50,7 +50,7 @@ describe InlineSvg::TransformPipeline::Transformations::AriaAttributes do
50
50
  end
51
51
 
52
52
  it "uses existing IDs when they exist" do
53
- document = Nokogiri::XML::Document.parse('<svg><title id="my-title">Some title</title><desc id="my-desc">Some description</desc>Some document</svg>')
53
+ document = Nokogiri::XML::Document.parse("<svg><title id='my-title'>Some title</title><desc id='my-desc'>Some description</desc>Some document</svg>")
54
54
  transformation = InlineSvg::TransformPipeline::Transformations::AriaAttributes.create_with_value(true)
55
55
 
56
56
  expect(InlineSvg::IdGenerator).to receive(:generate).with("my-title", "Some title").
@@ -0,0 +1,12 @@
1
+ require 'inline_svg/transform_pipeline'
2
+
3
+ describe InlineSvg::TransformPipeline::Transformations::AriaHiddenAttribute do
4
+ it "adds an aria-hidden='true' attribute to a SVG document" do
5
+ document = Nokogiri::XML::Document.parse('<svg>Some document</svg>')
6
+ transformation = InlineSvg::TransformPipeline::Transformations::AriaHiddenAttribute.create_with_value(true)
7
+
8
+ expect(transformation.transform(document).to_html).to eq(
9
+ "<svg aria-hidden=\"true\">Some document</svg>\n"
10
+ )
11
+ end
12
+ end
@@ -9,4 +9,13 @@ describe InlineSvg::TransformPipeline::Transformations::Height do
9
9
  "<svg height=\"5%\">Some document</svg>\n"
10
10
  )
11
11
  end
12
+
13
+ it "handles documents without SVG root elements" do
14
+ document = Nokogiri::XML::Document.parse("<foo>bar</foo><svg>Some document</svg>")
15
+ transformation = InlineSvg::TransformPipeline::Transformations::Height.create_with_value("5%")
16
+
17
+ expect(transformation.transform(document).to_html).to eq(
18
+ "<foo>bar</foo>\n"
19
+ )
20
+ end
12
21
  end
@@ -0,0 +1,26 @@
1
+ require "inline_svg/transform_pipeline"
2
+
3
+ describe InlineSvg::TransformPipeline::Transformations::ClassAttribute do
4
+ it "adds a style attribute to a SVG document" do
5
+ document = Nokogiri::XML::Document.parse('<svg>Some document</svg>')
6
+ transformation =
7
+ InlineSvg::TransformPipeline::Transformations::StyleAttribute
8
+ .create_with_value("padding: 10px")
9
+
10
+ expect(transformation.transform(document).to_html).to eq(
11
+ "<svg style=\"padding: 10px\">Some document</svg>\n"
12
+ )
13
+ end
14
+
15
+ it "preserves existing style attributes on a SVG document" do
16
+ xml = '<svg style="fill: red">Some document</svg>'
17
+ document = Nokogiri::XML::Document.parse(xml)
18
+ transformation =
19
+ InlineSvg::TransformPipeline::Transformations::StyleAttribute
20
+ .create_with_value("padding: 10px")
21
+
22
+ expect(transformation.transform(document).to_html).to eq(
23
+ "<svg style=\"fill: red;padding: 10px\">Some document</svg>\n"
24
+ )
25
+ end
26
+ end
@@ -27,4 +27,13 @@ describe InlineSvg::TransformPipeline::Transformations::Title do
27
27
  "<svg><title>Some Title</title></svg>\n"
28
28
  )
29
29
  end
30
+
31
+ it "handles non-ASCII characters" do
32
+ document = Nokogiri::XML::Document.parse('<svg>Some document</svg>')
33
+ transformation = InlineSvg::TransformPipeline::Transformations::Title.create_with_value("åäö")
34
+
35
+ expect(transformation.transform(document).to_html).to eq(
36
+ "<svg><title>åäö</title>Some document</svg>\n"
37
+ )
38
+ end
30
39
  end