inline_svg 1.0.0 → 1.10.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.
Files changed (63) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/integration_test.yml +47 -0
  3. data/.github/workflows/rails_6_webpacker_integration_tests.yaml +62 -0
  4. data/.github/workflows/ruby.yml +20 -0
  5. data/.rubocop.yml +1 -0
  6. data/.rubocop_todo.yml +421 -0
  7. data/CHANGELOG.md +143 -3
  8. data/README.md +149 -30
  9. data/Rakefile +7 -0
  10. data/inline_svg.gemspec +2 -1
  11. data/lib/inline_svg/action_view/helpers.rb +68 -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/propshaft_asset_finder.rb +16 -0
  17. data/lib/inline_svg/railtie.rb +8 -3
  18. data/lib/inline_svg/static_asset_finder.rb +5 -2
  19. data/lib/inline_svg/transform_pipeline/transformations/aria_attributes.rb +16 -19
  20. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden.rb +9 -0
  21. data/lib/inline_svg/transform_pipeline/transformations/aria_hidden_attribute.rb +9 -0
  22. data/lib/inline_svg/transform_pipeline/transformations/class_attribute.rb +5 -6
  23. data/lib/inline_svg/transform_pipeline/transformations/data_attributes.rb +4 -5
  24. data/lib/inline_svg/transform_pipeline/transformations/description.rb +7 -6
  25. data/lib/inline_svg/transform_pipeline/transformations/height.rb +3 -4
  26. data/lib/inline_svg/transform_pipeline/transformations/id_attribute.rb +3 -4
  27. data/lib/inline_svg/transform_pipeline/transformations/no_comment.rb +4 -4
  28. data/lib/inline_svg/transform_pipeline/transformations/preserve_aspect_ratio.rb +3 -4
  29. data/lib/inline_svg/transform_pipeline/transformations/size.rb +4 -5
  30. data/lib/inline_svg/transform_pipeline/transformations/style_attribute.rb +11 -0
  31. data/lib/inline_svg/transform_pipeline/transformations/title.rb +7 -6
  32. data/lib/inline_svg/transform_pipeline/transformations/transformation.rb +13 -0
  33. data/lib/inline_svg/transform_pipeline/transformations/view_box.rb +9 -0
  34. data/lib/inline_svg/transform_pipeline/transformations/width.rb +3 -4
  35. data/lib/inline_svg/transform_pipeline/transformations.rb +11 -2
  36. data/lib/inline_svg/transform_pipeline.rb +1 -1
  37. data/lib/inline_svg/version.rb +1 -1
  38. data/lib/inline_svg/webpack_asset_finder.rb +60 -0
  39. data/lib/inline_svg.rb +46 -9
  40. data/spec/cached_asset_file_spec.rb +73 -0
  41. data/spec/files/static_assets/assets0/known-document-two.svg +1 -0
  42. data/spec/files/static_assets/assets0/known-document.svg +1 -0
  43. data/spec/files/static_assets/assets0/some-document.svg +1 -0
  44. data/spec/files/static_assets/assets1/known-document.svg +1 -0
  45. data/spec/files/static_assets/assets1/other-document.svg +3 -0
  46. data/spec/files/static_assets/assets1/some-file.txt +1 -0
  47. data/spec/finds_asset_paths_spec.rb +45 -0
  48. data/spec/helpers/inline_svg_spec.rb +117 -51
  49. data/spec/id_generator_spec.rb +5 -3
  50. data/spec/inline_svg_spec.rb +48 -0
  51. data/spec/propshaft_asset_finder_spec.rb +23 -0
  52. data/spec/static_asset_finder_spec.rb +25 -0
  53. data/spec/transformation_pipeline/transformations/aria_attributes_spec.rb +6 -6
  54. data/spec/transformation_pipeline/transformations/aria_hidden_attribute_spec.rb +12 -0
  55. data/spec/transformation_pipeline/transformations/height_spec.rb +9 -0
  56. data/spec/transformation_pipeline/transformations/style_attribute_spec.rb +26 -0
  57. data/spec/transformation_pipeline/transformations/title_spec.rb +9 -0
  58. data/spec/transformation_pipeline/transformations/transformation_spec.rb +39 -0
  59. data/spec/transformation_pipeline/transformations/view_box_spec.rb +13 -0
  60. data/spec/transformation_pipeline/transformations_spec.rb +7 -1
  61. data/spec/webpack_asset_finder_spec.rb +23 -0
  62. metadata +62 -10
  63. data/circle.yml +0 -3
@@ -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
@@ -0,0 +1,16 @@
1
+ module InlineSvg
2
+ class PropshaftAssetFinder
3
+ def self.find_asset(filename)
4
+ new(filename)
5
+ end
6
+
7
+ def initialize(filename)
8
+ @filename = filename
9
+ end
10
+
11
+ def pathname
12
+ asset_path = ::Rails.application.assets.load_path.find(@filename)
13
+ asset_path.path unless asset_path.nil?
14
+ end
15
+ end
16
+ end
@@ -10,9 +10,14 @@ module InlineSvg
10
10
 
11
11
  config.after_initialize do |app|
12
12
  InlineSvg.configure do |config|
13
- # In default Rails apps, this will be a fully operational
14
- # Sprockets::Environment instance
15
- config.asset_finder = app.instance_variable_get(:@assets)
13
+ # Configure the asset_finder:
14
+ # Only set this when a user-configured asset finder has not been
15
+ # configured already.
16
+ if config.asset_finder.nil?
17
+ # In default Rails apps, this will be a fully operational
18
+ # Sprockets::Environment instance
19
+ config.asset_finder = app.instance_variable_get(:@assets)
20
+ end
16
21
  end
17
22
  end
18
23
  end
@@ -1,7 +1,9 @@
1
+ require "pathname"
2
+
1
3
  # Naive fallback asset finder for when sprockets >= 3.0 &&
2
4
  # config.assets.precompile = false
3
5
  # Thanks to @ryanswood for the original code:
4
- # https://github.com/AbleHealth/inline_svg/commit/661bbb3bef7d1b4bd6ccd63f5f018305797b9509
6
+ # https://github.com/jamesmartin/inline_svg/commit/661bbb3bef7d1b4bd6ccd63f5f018305797b9509
5
7
  module InlineSvg
6
8
  class StaticAssetFinder
7
9
  def self.find_asset(filename)
@@ -14,7 +16,8 @@ module InlineSvg
14
16
 
15
17
  def pathname
16
18
  if ::Rails.application.config.assets.compile
17
- ::Rails.application.assets[@filename].pathname
19
+ asset = ::Rails.application.assets[@filename]
20
+ Pathname.new(asset.filename) if asset.present?
18
21
  else
19
22
  manifest = ::Rails.application.assets_manifest
20
23
  asset_path = manifest.assets[@filename]
@@ -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
@@ -0,0 +1,9 @@
1
+ module InlineSvg::TransformPipeline::Transformations
2
+ class ViewBox < Transformation
3
+ def transform(doc)
4
+ with_svg(doc) do |svg|
5
+ svg["viewBox"] = value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -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,13 +6,16 @@ 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
- height: { transform: Height },
12
13
  nocomment: { transform: NoComment },
13
14
  preserve_aspect_ratio: { transform: PreserveAspectRatio },
14
15
  size: { transform: Size },
15
16
  width: { transform: Width },
17
+ height: { transform: Height },
18
+ view_box: { transform: ViewBox },
16
19
  }
17
20
  end
18
21
 
@@ -38,8 +41,11 @@ module InlineSvg::TransformPipeline::Transformations
38
41
  end
39
42
 
40
43
  def self.lookup(transform_params)
44
+ return [] unless transform_params.any? || custom_transformations.any?
45
+
46
+ transform_params_with_defaults = params_with_defaults(transform_params)
41
47
  all_transformations.map { |name, definition|
42
- value = params_with_defaults(transform_params)[name]
48
+ value = transform_params_with_defaults[name]
43
49
  definition.fetch(:transform, no_transform).create_with_value(value) if value
44
50
  }.compact
45
51
  end
@@ -72,12 +78,15 @@ end
72
78
  require 'inline_svg/transform_pipeline/transformations/transformation'
73
79
  require 'inline_svg/transform_pipeline/transformations/no_comment'
74
80
  require 'inline_svg/transform_pipeline/transformations/class_attribute'
81
+ require 'inline_svg/transform_pipeline/transformations/style_attribute'
75
82
  require 'inline_svg/transform_pipeline/transformations/title'
76
83
  require 'inline_svg/transform_pipeline/transformations/description'
77
84
  require 'inline_svg/transform_pipeline/transformations/size'
78
85
  require 'inline_svg/transform_pipeline/transformations/height'
79
86
  require 'inline_svg/transform_pipeline/transformations/width'
87
+ require 'inline_svg/transform_pipeline/transformations/view_box'
80
88
  require 'inline_svg/transform_pipeline/transformations/id_attribute'
81
89
  require 'inline_svg/transform_pipeline/transformations/data_attributes'
82
90
  require 'inline_svg/transform_pipeline/transformations/preserve_aspect_ratio'
83
91
  require 'inline_svg/transform_pipeline/transformations/aria_attributes'
92
+ require "inline_svg/transform_pipeline/transformations/aria_hidden_attribute"
@@ -4,7 +4,7 @@ module InlineSvg
4
4
  document = Nokogiri::XML::Document.parse(svg_file)
5
5
  Transformations.lookup(transform_params).reduce(document) do |doc, transformer|
6
6
  transformer.transform(doc)
7
- end.to_html
7
+ end.to_html.strip
8
8
  end
9
9
  end
10
10
  end
@@ -1,3 +1,3 @@
1
1
  module InlineSvg
2
- VERSION = "1.0.0"
2
+ VERSION = "1.10.0"
3
3
  end
@@ -0,0 +1,60 @@
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
+ manifest_lookup = asset_helper.manifest.lookup(@filename)
10
+ @asset_path = manifest_lookup.present? ? URI(manifest_lookup).path : ""
11
+ end
12
+
13
+ def pathname
14
+ return if @asset_path.blank?
15
+
16
+ if asset_helper.dev_server.running?
17
+ dev_server_asset(@asset_path)
18
+ elsif asset_helper.config.public_path.present?
19
+ File.join(asset_helper.config.public_path, @asset_path)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def asset_helper
26
+ @asset_helper ||=
27
+ if defined?(::Shakapacker)
28
+ ::Shakapacker
29
+ else
30
+ ::Webpacker
31
+ end
32
+ end
33
+
34
+ def dev_server_asset(file_path)
35
+ asset = fetch_from_dev_server(file_path)
36
+
37
+ begin
38
+ Tempfile.new(file_path).tap do |file|
39
+ file.binmode
40
+ file.write(asset)
41
+ file.rewind
42
+ end
43
+ rescue StandardError => e
44
+ Rails.logger.error "[inline_svg] Error creating tempfile for #{@filename}: #{e}"
45
+ raise
46
+ end
47
+ end
48
+
49
+ def fetch_from_dev_server(file_path)
50
+ http = Net::HTTP.new(asset_helper.dev_server.host, asset_helper.dev_server.port)
51
+ http.use_ssl = asset_helper.dev_server.protocol == "https"
52
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
53
+
54
+ http.request(Net::HTTP::Get.new(file_path)).body
55
+ rescue StandardError => e
56
+ Rails.logger.error "[inline_svg] Error fetching #{@filename} from webpack-dev-server: #{e}"
57
+ raise
58
+ end
59
+ end
60
+ end
data/lib/inline_svg.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  require "inline_svg/version"
2
2
  require "inline_svg/action_view/helpers"
3
3
  require "inline_svg/asset_file"
4
+ require "inline_svg/cached_asset_file"
4
5
  require "inline_svg/finds_asset_paths"
6
+ require "inline_svg/propshaft_asset_finder"
5
7
  require "inline_svg/static_asset_finder"
8
+ require "inline_svg/webpack_asset_finder"
6
9
  require "inline_svg/transform_pipeline"
7
10
  require "inline_svg/io_resource"
8
11
 
9
12
  require "inline_svg/railtie" if defined?(Rails)
13
+ require 'active_support'
14
+ require 'active_support/core_ext/object/blank'
10
15
  require 'active_support/core_ext/string'
11
16
  require 'nokogiri'
12
17
 
@@ -14,24 +19,48 @@ module InlineSvg
14
19
  class Configuration
15
20
  class Invalid < ArgumentError; end
16
21
 
17
- attr_reader :asset_finder, :custom_transformations
22
+ attr_reader :asset_file, :asset_finder, :custom_transformations, :svg_not_found_css_class
18
23
 
19
24
  def initialize
20
25
  @custom_transformations = {}
26
+ @asset_file = InlineSvg::AssetFile
27
+ @svg_not_found_css_class = nil
28
+ @raise_on_file_not_found = false
21
29
  end
22
30
 
23
- def asset_finder=(finder)
24
- if finder.respond_to?(:find_asset)
25
- @asset_finder = finder
26
- else
27
- # fallback to a naive static asset finder (sprokects >= 3.0 &&
28
- # config.assets.precompile = false
29
- # See: https://github.com/jamesmartin/inline_svg/issues/25
30
- @asset_finder = InlineSvg::StaticAssetFinder
31
+ def asset_file=(custom_asset_file)
32
+ begin
33
+ method = custom_asset_file.method(:named)
34
+ if method.arity == 1
35
+ @asset_file = custom_asset_file
36
+ else
37
+ raise InlineSvg::Configuration::Invalid.new("asset_file should implement the #named method with arity 1")
38
+ end
39
+ rescue NameError
40
+ raise InlineSvg::Configuration::Invalid.new("asset_file should implement the #named method")
31
41
  end
42
+ end
43
+
44
+ def asset_finder=(finder)
45
+ @asset_finder = if finder.respond_to?(:find_asset)
46
+ finder
47
+ elsif finder.class.name == "Propshaft::Assembly"
48
+ InlineSvg::PropshaftAssetFinder
49
+ else
50
+ # fallback to a naive static asset finder
51
+ # (sprokects >= 3.0 && config.assets.precompile = false
52
+ # See: https://github.com/jamesmartin/inline_svg/issues/25
53
+ InlineSvg::StaticAssetFinder
54
+ end
32
55
  asset_finder
33
56
  end
34
57
 
58
+ def svg_not_found_css_class=(css_class)
59
+ if css_class.present? && css_class.is_a?(String)
60
+ @svg_not_found_css_class = css_class
61
+ end
62
+ end
63
+
35
64
  def add_custom_transformation(options)
36
65
  if incompatible_transformation?(options.fetch(:transform))
37
66
  raise InlineSvg::Configuration::Invalid.new("#{options.fetch(:transform)} should implement the .create_with_value and #transform methods")
@@ -39,6 +68,14 @@ module InlineSvg
39
68
  @custom_transformations.merge!(Hash[ *[options.fetch(:attribute, :no_attribute), options] ])
40
69
  end
41
70
 
71
+ def raise_on_file_not_found=(value)
72
+ @raise_on_file_not_found = value
73
+ end
74
+
75
+ def raise_on_file_not_found?
76
+ !!@raise_on_file_not_found
77
+ end
78
+
42
79
  private
43
80
 
44
81
  def incompatible_transformation?(klass)
@@ -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>