inline_svg 0.11.0 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/integration_test.yml +58 -0
  3. data/.github/workflows/ruby.yml +20 -0
  4. data/.rubocop.yml +1 -0
  5. data/.rubocop_todo.yml +421 -0
  6. data/CHANGELOG.md +144 -2
  7. data/README.md +148 -34
  8. data/Rakefile +7 -0
  9. data/inline_svg.gemspec +4 -4
  10. data/lib/inline_svg.rb +41 -9
  11. data/lib/inline_svg/action_view/helpers.rb +72 -7
  12. data/lib/inline_svg/cached_asset_file.rb +71 -0
  13. data/lib/inline_svg/finds_asset_paths.rb +1 -1
  14. data/lib/inline_svg/id_generator.rb +12 -3
  15. data/lib/inline_svg/io_resource.rb +4 -3
  16. data/lib/inline_svg/railtie.rb +8 -3
  17. data/lib/inline_svg/static_asset_finder.rb +4 -2
  18. data/lib/inline_svg/transform_pipeline.rb +0 -1
  19. data/lib/inline_svg/transform_pipeline/transformations.rb +8 -1
  20. data/lib/inline_svg/transform_pipeline/transformations/aria_attributes.rb +17 -20
  21. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden.rb +9 -0
  22. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden_attribute.rb +9 -0
  23. data/lib/inline_svg/transform_pipeline/transformations/class_attribute.rb +5 -6
  24. data/lib/inline_svg/transform_pipeline/transformations/data_attributes.rb +10 -5
  25. data/lib/inline_svg/transform_pipeline/transformations/description.rb +7 -6
  26. data/lib/inline_svg/transform_pipeline/transformations/height.rb +3 -4
  27. data/lib/inline_svg/transform_pipeline/transformations/id_attribute.rb +3 -4
  28. data/lib/inline_svg/transform_pipeline/transformations/no_comment.rb +5 -2
  29. data/lib/inline_svg/transform_pipeline/transformations/preserve_aspect_ratio.rb +3 -4
  30. data/lib/inline_svg/transform_pipeline/transformations/size.rb +4 -5
  31. data/lib/inline_svg/transform_pipeline/transformations/style_attribute.rb +11 -0
  32. data/lib/inline_svg/transform_pipeline/transformations/title.rb +7 -6
  33. data/lib/inline_svg/transform_pipeline/transformations/transformation.rb +13 -0
  34. data/lib/inline_svg/transform_pipeline/transformations/width.rb +3 -4
  35. data/lib/inline_svg/version.rb +1 -1
  36. data/lib/inline_svg/webpack_asset_finder.rb +50 -0
  37. data/spec/cached_asset_file_spec.rb +73 -0
  38. data/spec/files/static_assets/assets0/known-document-two.svg +1 -0
  39. data/spec/files/static_assets/assets0/known-document.svg +1 -0
  40. data/spec/files/static_assets/assets0/some-document.svg +1 -0
  41. data/spec/files/static_assets/assets1/known-document.svg +1 -0
  42. data/spec/files/static_assets/assets1/other-document.svg +3 -0
  43. data/spec/files/static_assets/assets1/some-file.txt +1 -0
  44. data/spec/helpers/inline_svg_spec.rb +104 -21
  45. data/spec/id_generator_spec.rb +5 -3
  46. data/spec/inline_svg_spec.rb +48 -0
  47. data/spec/transformation_pipeline/transformations/aria_attributes_spec.rb +16 -16
  48. data/spec/transformation_pipeline/transformations/aria_hidden_attribute_spec.rb +12 -0
  49. data/spec/transformation_pipeline/transformations/data_attributes_spec.rb +18 -0
  50. data/spec/transformation_pipeline/transformations/height_spec.rb +9 -0
  51. data/spec/transformation_pipeline/transformations/style_attribute_spec.rb +26 -0
  52. data/spec/transformation_pipeline/transformations/title_spec.rb +9 -0
  53. data/spec/transformation_pipeline/transformations/transformation_spec.rb +39 -0
  54. data/spec/transformation_pipeline/transformations_spec.rb +5 -1
  55. metadata +49 -22
  56. data/circle.yml +0 -3
@@ -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,16 +1,21 @@
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-#{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
 
11
+ private
12
+
12
13
  def with_valid_hash_from(hash)
13
14
  Hash.try_convert(hash) || {}
14
15
  end
16
+
17
+ def dasherize(string)
18
+ string.to_s.gsub(/_/, "-")
19
+ end
15
20
  end
16
21
  end
@@ -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,8 +2,11 @@ module InlineSvg::TransformPipeline
2
2
  module Transformations
3
3
  class NoComment < Transformation
4
4
  def transform(doc)
5
- doc = Loofah::HTML::DocumentFragment.parse(doc.to_html)
6
- doc.scrub!(:strip)
5
+ with_svg(doc) do |svg|
6
+ svg.xpath("//comment()").each do |comment|
7
+ comment.remove
8
+ end
9
+ end
7
10
  end
8
11
  end
9
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
@@ -1,3 +1,3 @@
1
1
  module InlineSvg
2
- VERSION = "0.11.0"
2
+ VERSION = "1.7.2"
3
3
  end
@@ -0,0 +1,50 @@
1
+ module InlineSvg
2
+ class WebpackAssetFinder
3
+ def self.find_asset(filename)
4
+ new(filename)
5
+ end
6
+
7
+ def initialize(filename)
8
+ @filename = filename
9
+ @asset_path = Webpacker.manifest.lookup(@filename)
10
+ end
11
+
12
+ def pathname
13
+ return if @asset_path.blank?
14
+
15
+ if Webpacker.dev_server.running?
16
+ dev_server_asset(@asset_path)
17
+ elsif Webpacker.config.public_path.present?
18
+ File.join(Webpacker.config.public_path, @asset_path)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def dev_server_asset(file_path)
25
+ asset = fetch_from_dev_server(file_path)
26
+
27
+ begin
28
+ Tempfile.new(file_path).tap do |file|
29
+ file.binmode
30
+ file.write(asset)
31
+ file.rewind
32
+ end
33
+ rescue StandardError => e
34
+ Rails.logger.error "[inline_svg] Error creating tempfile for #{@filename}: #{e}"
35
+ raise
36
+ end
37
+ end
38
+
39
+ def fetch_from_dev_server(file_path)
40
+ http = Net::HTTP.new(Webpacker.dev_server.host, Webpacker.dev_server.port)
41
+ http.use_ssl = Webpacker.dev_server.https?
42
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
43
+
44
+ http.request(Net::HTTP::Get.new(file_path)).body
45
+ rescue StandardError => e
46
+ Rails.logger.error "[inline_svg] Error fetching #{@filename} from webpack-dev-server: #{e}"
47
+ raise
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require 'pathname'
3
+ require_relative '../lib/inline_svg'
4
+
5
+ describe InlineSvg::CachedAssetFile do
6
+ let(:fixture_path) { Pathname.new(File.expand_path("../files/static_assets", __FILE__)) }
7
+
8
+ it "loads assets under configured paths" do
9
+ known_document = File.read(fixture_path.join("assets0", "known-document.svg"))
10
+
11
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path.join("assets0"))
12
+
13
+ expect(asset_loader.named("known-document.svg")).to eq(known_document)
14
+ end
15
+
16
+ it "does not include assets outside of configured paths" do
17
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path.join("assets0"))
18
+
19
+ expect(fixture_path.join("assets1", "other-document.svg")).to be_file
20
+ expect do
21
+ asset_loader.named("other-document.svg")
22
+ end.to raise_error InlineSvg::AssetFile::FileNotFound
23
+ end
24
+
25
+ it "differentiates two files with the same name" do
26
+ known_document_0 = File.read(fixture_path.join("assets0", "known-document.svg"))
27
+ known_document_1 = File.read(fixture_path.join("assets1", "known-document.svg"))
28
+
29
+ expect(known_document_0).not_to eq(known_document_1)
30
+
31
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path)
32
+
33
+ expect(known_document_0).to eq(asset_loader.named("assets0/known-document.svg"))
34
+ expect(known_document_1).to eq(asset_loader.named("assets1/known-document.svg"))
35
+ end
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
+
49
+ it "filters wanted files by simple string matching" do
50
+ known_document_0 = File.read(fixture_path.join("assets0", "known-document.svg"))
51
+ known_document_1 = File.read(fixture_path.join("assets1", "known-document.svg"))
52
+
53
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path, filters: "assets1")
54
+
55
+ expect do
56
+ asset_loader.named("assets0/known-document.svg")
57
+ end.to raise_error InlineSvg::AssetFile::FileNotFound
58
+
59
+ expect(known_document_1).to eq(asset_loader.named("assets1/known-document.svg"))
60
+ end
61
+
62
+ it "filters wanted files by regex matching" do
63
+ known_document_1 = File.read(fixture_path.join("assets1", "known-document.svg"))
64
+
65
+ asset_loader = InlineSvg::CachedAssetFile.new(paths: fixture_path, filters: ["assets1", /\.svg/])
66
+
67
+ expect do
68
+ asset_loader.named("assets1/some-file.txt")
69
+ end.to raise_error InlineSvg::AssetFile::FileNotFound
70
+
71
+ expect(known_document_1).to eq(asset_loader.named("assets1/known-document.svg"))
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ <svg>other interesting content</svg>
@@ -0,0 +1 @@
1
+ <svg>interesting content</svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3.273 7.151l-2.917-2.916c-.23.665-.356 1.361-.356 2.057 0 1.608.624 3.216 1.851 4.442 1.35 1.351 3.163 1.957 4.928 1.821.933-.072 1.851.268 2.513.93l9.646 9.646c.58.579 1.338.869 2.097.869 1.636 0 2.965-1.326 2.965-2.965 0-.759-.29-1.518-.868-2.097l-9.647-9.646c-.661-.662-1.002-1.581-.93-2.514.136-1.766-.47-3.578-1.821-4.928-.372-.372-.778-.686-1.209-.945l-6.252 6.246zm18.727 13.849c0 .552-.448 1-1 1s-1-.448-1-1 .448-1 1-1 1 .447 1 1zm-12.153-13.396l-3.061 3.061-2.566-2.567 3.062-3.061 2.565 2.567zm-.933.096l-.762.761-1.705-1.705.762-.762 1.705 1.706zm-2.991-.42l-.761.762 1.706 1.705.762-.762-1.707-1.705zm2.484-6.903l-2.893 2.893-2.412-2.412c.953-.556 2.044-.858 3.165-.858.707 0 1.425.12 2.128.373l.012.004z"/></svg>
@@ -0,0 +1 @@
1
+ <svg>Another known document</svg>
@@ -0,0 +1,3 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg>Other document</svg>
@@ -0,0 +1 @@
1
+ Some file contents.
@@ -13,27 +13,86 @@ describe InlineSvg::ActionView::Helpers do
13
13
 
14
14
  let(:helper) { ( Class.new { include InlineSvg::ActionView::Helpers } ).new }
15
15
 
16
- describe "#inline_svg" do
17
-
16
+ shared_examples "inline_svg helper" do |helper_method:|
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
+
23
+ context "and configured to raise" do
24
+ it "raises an exception" do
25
+ InlineSvg.configure do |config|
26
+ config.raise_on_file_not_found = true
27
+ end
28
+
29
+ allow(InlineSvg::AssetFile).to receive(:named).
30
+ with('some-missing-file.svg').
31
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
32
+
33
+ expect {
34
+ helper.send(helper_method, 'some-missing-file.svg')
35
+ }.to raise_error(InlineSvg::AssetFile::FileNotFound)
36
+ end
37
+ end
38
+
19
39
  it "returns an empty, html safe, SVG document as a placeholder" do
20
40
  allow(InlineSvg::AssetFile).to receive(:named).
21
41
  with('some-missing-file.svg').
22
42
  and_raise(InlineSvg::AssetFile::FileNotFound.new)
23
43
 
24
- output = helper.inline_svg('some-missing-file.svg')
44
+ output = helper.send(helper_method, 'some-missing-file.svg')
25
45
  expect(output).to eq "<svg><!-- SVG file not found: 'some-missing-file.svg' --></svg>"
26
46
  expect(output).to be_html_safe
27
47
  end
28
48
 
49
+ it "escapes malicious input" do
50
+ malicious = "--></svg><script>alert(1)</script><svg>.svg"
51
+ allow(InlineSvg::AssetFile).to receive(:named).
52
+ with(malicious).
53
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
54
+
55
+ output = helper.send(helper_method, malicious)
56
+ expect(output).to eq "<svg><!-- SVG file not found: '--&gt;&lt;/svg&gt;&lt;script&gt;alert(1)&lt;/script&gt;&lt;svg&gt;.svg' --></svg>"
57
+ expect(output).to be_html_safe
58
+ end
59
+
29
60
  it "gives a helpful hint when no .svg extension is provided in the filename" do
30
61
  allow(InlineSvg::AssetFile).to receive(:named).
31
62
  with('missing-file-with-no-extension').
32
63
  and_raise(InlineSvg::AssetFile::FileNotFound.new)
33
64
 
34
- output = helper.inline_svg('missing-file-with-no-extension')
65
+ output = helper.send(helper_method, 'missing-file-with-no-extension')
35
66
  expect(output).to eq "<svg><!-- SVG file not found: 'missing-file-with-no-extension' (Try adding .svg to your filename) --></svg>"
36
67
  end
68
+
69
+ it "allows the CSS class on the empty SVG document to be changed" do
70
+ InlineSvg.configure do |config|
71
+ config.svg_not_found_css_class = 'missing-svg'
72
+ end
73
+
74
+ allow(InlineSvg::AssetFile).to receive(:named).
75
+ with('some-other-missing-file.svg').
76
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
77
+
78
+ output = helper.send(helper_method, 'some-other-missing-file.svg')
79
+ expect(output).to eq "<svg class='missing-svg'><!-- SVG file not found: 'some-other-missing-file.svg' --></svg>"
80
+ expect(output).to be_html_safe
81
+ end
82
+
83
+ context "and a fallback that does exist" do
84
+ it "displays the fallback" do
85
+ allow(InlineSvg::AssetFile).to receive(:named).
86
+ with('missing.svg').
87
+ and_raise(InlineSvg::AssetFile::FileNotFound.new)
88
+
89
+ fallback_file = <<-SVG
90
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><!-- This is a comment --></svg>
91
+ SVG
92
+ allow(InlineSvg::AssetFile).to receive(:named).with('fallback.svg').and_return(fallback_file)
93
+ expect(helper.send(helper_method, 'missing.svg', fallback: 'fallback.svg')).to eq fallback_file
94
+ end
95
+ end
37
96
  end
38
97
 
39
98
  context "when passed an existing SVG file" do
@@ -41,10 +100,10 @@ describe InlineSvg::ActionView::Helpers do
41
100
  context "and no options" do
42
101
  it "returns a html safe version of the file's contents" do
43
102
  example_file = <<-SVG
44
- <svg xmlns="http://www.w3.org/2000/svg" role="presentation" xml:lang="en"><!-- This is a comment --></svg>
103
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><!-- This is a comment --></svg>
45
104
  SVG
46
105
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(example_file)
47
- expect(helper.inline_svg('some-file')).to eq example_file
106
+ expect(helper.send(helper_method, 'some-file')).to eq example_file
48
107
  end
49
108
  end
50
109
 
@@ -57,7 +116,7 @@ SVG
57
116
  <svg xmlns="http://www.w3.org/2000/svg" role="presentation" xml:lang="en"><title>A title</title></svg>
58
117
  SVG
59
118
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
60
- expect(helper.inline_svg('some-file', title: 'A title')).to eq expected_output
119
+ expect(helper.send(helper_method, 'some-file', title: 'A title')).to eq expected_output
61
120
  end
62
121
  end
63
122
 
@@ -70,34 +129,46 @@ SVG
70
129
  <svg xmlns="http://www.w3.org/2000/svg" role="presentation" xml:lang="en"><desc>A description</desc></svg>
71
130
  SVG
72
131
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
73
- expect(helper.inline_svg('some-file', desc: 'A description')).to eq expected_output
132
+ expect(helper.send(helper_method, 'some-file', desc: 'A description')).to eq expected_output
74
133
  end
75
134
  end
76
135
 
77
136
  context "and the 'nocomment' option" do
78
137
  it "strips comments and other unknown/unsafe nodes from the output" do
79
138
  input_svg = <<-SVG
80
- <svg xmlns="http://www.w3.org/2000/svg" role="presentation" xml:lang="en"><!-- This is a comment --></svg>
139
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><!-- This is a comment --></svg>
81
140
  SVG
82
141
  expected_output = <<-SVG
83
142
  <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"></svg>
84
143
  SVG
85
144
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
86
- expect(helper.inline_svg('some-file', nocomment: true)).to eq expected_output
145
+ expect(helper.send(helper_method, 'some-file', nocomment: true)).to eq expected_output
146
+ end
147
+ end
148
+
149
+ context "and the 'aria_hidden' option" do
150
+ it "sets 'aria-hidden=true' in the output" do
151
+ input_svg = <<-SVG
152
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"></svg>
153
+ SVG
154
+ expected_output = <<-SVG
155
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en" aria-hidden="true"></svg>
156
+ SVG
157
+ allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
158
+ expect(helper.send(helper_method, 'some-file', aria_hidden: true)).to eq expected_output
87
159
  end
88
160
  end
89
161
 
90
162
  context "and all options" do
91
163
  it "applies all expected transformations to the output" do
92
164
  input_svg = <<-SVG
93
- <svg xmlns="http://www.w3.org/2000/svg" role="presentation" xml:lang="en"><!-- This is a comment --></svg>
165
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><!-- This is a comment --></svg>
94
166
  SVG
95
167
  expected_output = <<-SVG
96
- <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><title>A title</title>
97
- <desc>A description</desc></svg>
168
+ <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en"><title>A title</title><desc>A description</desc></svg>
98
169
  SVG
99
170
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
100
- expect(helper.inline_svg('some-file', title: 'A title', desc: 'A description', nocomment: true)).to eq expected_output
171
+ expect(helper.send(helper_method, 'some-file', title: 'A title', desc: 'A description', nocomment: true)).to eq expected_output
101
172
  end
102
173
  end
103
174
 
@@ -120,7 +191,7 @@ SVG
120
191
  <svg custom="some value"></svg>
121
192
  SVG
122
193
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
123
- expect(helper.inline_svg('some-file', custom: 'some value')).to eq expected_output
194
+ expect(helper.send(helper_method, 'some-file', custom: 'some value')).to eq expected_output
124
195
  end
125
196
  end
126
197
 
@@ -141,7 +212,7 @@ SVG
141
212
 
142
213
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
143
214
 
144
- expect(helper.inline_svg('some-file')).to eq "<svg custom=\"default value\"></svg>\n"
215
+ expect(helper.send(helper_method, 'some-file')).to eq "<svg custom=\"default value\"></svg>\n"
145
216
  end
146
217
  end
147
218
 
@@ -151,7 +222,7 @@ SVG
151
222
 
152
223
  allow(InlineSvg::AssetFile).to receive(:named).with('some-file').and_return(input_svg)
153
224
 
154
- expect(helper.inline_svg('some-file', custom: 'some value')).to eq "<svg custom=\"some value\"></svg>\n"
225
+ expect(helper.send(helper_method, 'some-file', custom: 'some value')).to eq "<svg custom=\"some value\"></svg>\n"
155
226
  end
156
227
  end
157
228
  end
@@ -163,13 +234,13 @@ SVG
163
234
  expect(InlineSvg::IOResource).to receive(:===).with(argument).and_return(true)
164
235
  expect(InlineSvg::IOResource).to receive(:read).with(argument)
165
236
  expect(InlineSvg::AssetFile).to_not receive(:named)
166
- helper.inline_svg(argument)
237
+ helper.send(helper_method, argument)
167
238
  end
168
239
  it 'accept filename' do
169
240
  expect(InlineSvg::IOResource).to receive(:===).with(argument).and_return(false)
170
241
  expect(InlineSvg::IOResource).to_not receive(:read)
171
242
  expect(InlineSvg::AssetFile).to receive(:named).with(argument)
172
- helper.inline_svg(argument)
243
+ helper.send(helper_method, argument)
173
244
  end
174
245
  end
175
246
  context 'when passed IO object argument' do
@@ -179,17 +250,29 @@ SVG
179
250
  it 'return valid svg' do
180
251
  expect(InlineSvg::IOResource).to receive(:===).with(io_object).and_return(true)
181
252
  expect(InlineSvg::IOResource).to receive(:read).with(io_object).and_return("<svg><!-- Test IO --></svg>")
182
- output = helper.inline_svg(io_object)
253
+ output = helper.send(helper_method, io_object)
183
254
  expect(output).to eq "<svg><!-- Test IO --></svg>\n"
184
255
  expect(output).to be_html_safe
185
256
  end
186
257
 
187
258
  it 'return valid svg for file' do
188
- output = helper.inline_svg(File.new(file_path))
259
+ output = helper.send(helper_method, File.new(file_path))
189
260
  expect(output).to eq "<svg xmlns=\"http://www.w3.org/2000/svg\" xml:lang=\"en\" role=\"presentation\"><!-- This is a test comment --></svg>\n"
190
261
  expect(output).to be_html_safe
191
262
  end
192
263
 
193
264
  end
194
265
  end
266
+
267
+ describe '#inline_svg' do
268
+ it_behaves_like "inline_svg helper", helper_method: :inline_svg
269
+ end
270
+
271
+ describe '#inline_svg_tag' do
272
+ it_behaves_like "inline_svg helper", helper_method: :inline_svg_tag
273
+ end
274
+
275
+ describe '#inline_svg_tag' do
276
+ it_behaves_like "inline_svg helper", helper_method: :inline_svg_pack_tag
277
+ end
195
278
  end