inline_svg 0.11.0 → 1.7.2

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.
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