Skip to content

Commit

Permalink
Change asset finder configuration
Browse files Browse the repository at this point in the history
This commit changes the way the asset finder is configured. Instead of setting
the asset finder from an initializer to a specific class, the asset finder is
now detected unless configured otherwise.

This allows InlineSvg to work with Sprockets, Propshaft, or a fallback static
asset finder without any configuration.
  • Loading branch information
xymbol committed Oct 26, 2023
1 parent 6a603dc commit 3f5e7cd
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 43 deletions.
40 changes: 24 additions & 16 deletions lib/inline_svg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "inline_svg/cached_asset_file"
require "inline_svg/finds_asset_paths"
require "inline_svg/propshaft_asset_finder"
require "inline_svg/sprockets_asset_finder"
require "inline_svg/static_asset_finder"
require "inline_svg/webpack_asset_finder"
require "inline_svg/transform_pipeline"
Expand All @@ -19,7 +20,15 @@ module InlineSvg
class Configuration
class Invalid < ArgumentError; end

attr_reader :asset_file, :asset_finder, :custom_transformations, :svg_not_found_css_class
attr_reader :asset_file, :custom_transformations, :svg_not_found_css_class

# Asset finders are ordered by priority. Unless configured otherwise, the
# first asset finder that matches will be used.
ASSET_FINDERS = [
InlineSvg::SprocketsAssetFinder,
InlineSvg::PropshaftAssetFinder,
InlineSvg::StaticAssetFinder
].freeze

def initialize
@custom_transformations = {}
Expand All @@ -41,18 +50,16 @@ def asset_file=(custom_asset_file)
end
end

def asset_finder=(finder)
@asset_finder = if finder.respond_to?(:find_asset)
finder
elsif finder.class.name == "Propshaft::Assembly"
InlineSvg::PropshaftAssetFinder
else
# fallback to a naive static asset finder
# (sprokects >= 3.0 && config.assets.precompile = false
# See: https://github.com/jamesmartin/inline_svg/issues/25
InlineSvg::StaticAssetFinder
end
asset_finder
def asset_finder=(asset_finder)
if asset_finder.respond_to?(:find_asset)
@asset_finder = asset_finder
else
raise InlineSvg::Configuration::Invalid.new("asset_finder should implement the #find_asset method")
end
end

def asset_finder
@asset_finder ||= matching_asset_finder
end

def svg_not_found_css_class=(css_class)
Expand All @@ -68,9 +75,7 @@ def add_custom_transformation(options)
@custom_transformations.merge!(Hash[ *[options.fetch(:attribute, :no_attribute), options] ])
end

def raise_on_file_not_found=(value)
@raise_on_file_not_found = value
end
attr_writer :raise_on_file_not_found

def raise_on_file_not_found?
!!@raise_on_file_not_found
Expand All @@ -82,6 +87,9 @@ def incompatible_transformation?(klass)
!klass.is_a?(Class) || !klass.respond_to?(:create_with_value) || !klass.instance_methods.include?(:transform)
end

def matching_asset_finder
ASSET_FINDERS.detect(&:match?)
end
end

@configuration = InlineSvg::Configuration.new
Expand Down
13 changes: 11 additions & 2 deletions lib/inline_svg/propshaft_asset_finder.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
module InlineSvg
class PropshaftAssetFinder
def self.assets
Rails.application.assets
end

def self.find_asset(filename)
new(filename)
end

def self.match?
assets.instance_of?(Propshaft::Assembly)
rescue NameError
end

def initialize(filename)
@filename = filename
end

def pathname
asset_path = ::Rails.application.assets.load_path.find(@filename)
asset_path.path unless asset_path.nil?
asset_path = self.class.assets.load_path.find(@filename)
asset_path&.path
end
end
end
13 changes: 0 additions & 13 deletions lib/inline_svg/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,5 @@ class Railtie < ::Rails::Railtie
include InlineSvg::ActionView::Helpers
end
end

config.after_initialize do |app|
InlineSvg.configure do |config|
# Configure the asset_finder:
# Only set this when a user-configured asset finder has not been
# configured already.
if config.asset_finder.nil?
# In default Rails apps, this will be a fully operational
# Sprockets::Environment instance
config.asset_finder = app.instance_variable_get(:@assets)
end
end
end
end
end
16 changes: 16 additions & 0 deletions lib/inline_svg/sprockets_asset_finder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module InlineSvg
module SprocketsAssetFinder
def self.assets
Rails.application.assets
end

def self.find_asset(*args, **options)
assets.find_asset(*args, **options)
end

def self.match?
assets.respond_to?(:find_asset)
rescue NameError
end
end
end
4 changes: 4 additions & 0 deletions lib/inline_svg/static_asset_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def self.find_asset(filename)
new(filename)
end

def self.match?
true
end

def initialize(filename)
@filename = filename
end
Expand Down
6 changes: 3 additions & 3 deletions lib/inline_svg/webpack_asset_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def self.find_asset(filename)
def initialize(filename)
@filename = filename
manifest_lookup = Webpacker.manifest.lookup(@filename)
@asset_path = manifest_lookup.present? ? URI(manifest_lookup).path : ""
@asset_path = manifest_lookup.present? ? URI(manifest_lookup).path : ""
end

def pathname
Expand All @@ -31,7 +31,7 @@ def dev_server_asset(file_path)
file.write(asset)
file.rewind
end
rescue StandardError => e
rescue => e
Rails.logger.error "[inline_svg] Error creating tempfile for #{@filename}: #{e}"
raise
end
Expand All @@ -43,7 +43,7 @@ def fetch_from_dev_server(file_path)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

http.request(Net::HTTP::Get.new(file_path)).body
rescue StandardError => e
rescue => e
Rails.logger.error "[inline_svg] Error fetching #{@filename} from webpack-dev-server: #{e}"
raise
end
Expand Down
47 changes: 38 additions & 9 deletions spec/inline_svg_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,51 @@ def self.named(filename); end
end

context "asset finder" do
it "allows an asset finder to be assigned" do
sprockets = double('SomethingLikeSprockets', find_asset: 'some asset')
InlineSvg.configure do |config|
config.asset_finder = sprockets
context "when Sprockets is detected" do
it "uses the Sprockets asset finder" do
sprockets = double("Sprockets", find_asset: "some asset")
stub_const("Rails", double("Rails"))
allow(Rails).to receive_message_chain(:application, :assets).and_return(sprockets)

expect(InlineSvg.configuration.asset_finder).to eq InlineSvg::SprocketsAssetFinder
end
end

context "when Propshaft is detected" do
it "uses the Propshaft asset finder" do
stub_const("Propshaft::Assembly", Class.new)
stub_const("Rails", double("Rails"))
allow(Rails).to receive_message_chain(:application, :assets).and_return(Propshaft::Assembly.new)

expect(InlineSvg.configuration.asset_finder).to eq sprockets
expect(InlineSvg.configuration.asset_finder).to eq InlineSvg::PropshaftAssetFinder
end
end

context "when Sprockets and Propshaft are not detected" do
it "uses the static asset finder" do
expect(InlineSvg.configuration.asset_finder).to eq InlineSvg::StaticAssetFinder
end
end

it "falls back to StaticAssetFinder when the provided asset finder does not implement #find_asset" do
it "allows an asset finder to be assigned" do
asset_finder = double("An asset finder", find_asset: "some asset")
InlineSvg.configure do |config|
config.asset_finder = 'Not a real asset finder'
config.asset_finder = asset_finder
end

expect(InlineSvg.configuration.asset_finder).to eq InlineSvg::StaticAssetFinder
expect(InlineSvg.configuration.asset_finder).to eq asset_finder
end

it "raises an error if the asset finder does not implement the find_asset method" do
expect {
InlineSvg.configure do |config|
config.asset_finder = "Not a real asset finder"
end
}.to raise_error(InlineSvg::Configuration::Invalid, /asset_finder should implement the #find_asset method/)
end

after do
InlineSvg.reset_configuration!
end
end

Expand Down Expand Up @@ -122,7 +152,6 @@ def self.named(filename); end
end
end.to raise_error(InlineSvg::Configuration::Invalid, /#{:not_a_class} should implement the .create_with_value and #transform methods/)
end

end
end
end
11 changes: 11 additions & 0 deletions spec/sprockets_asset_finder_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require_relative "../lib/inline_svg"

describe InlineSvg::SprocketsAssetFinder do
it "returns assets from Sprockets" do
sprockets = double("Sprockets", find_asset: "some asset")
stub_const("Rails", double("Rails"))
allow(Rails).to receive_message_chain(:application, :assets).and_return(sprockets)

expect(described_class.find_asset("some-file")).to eq "some asset"
end
end

0 comments on commit 3f5e7cd

Please sign in to comment.