lib/roda/plugins/render_coverage.rb
# frozen-string-literal: true require 'tilt' # :nocov: raise 'Tilt version does not support coverable templates' unless Tilt::Template.method_defined?(:compiled_path=) # :nocov: # class Roda module RodaPlugins # The render_coverage plugin builds on top of the render plugin # and sets compiled_path on created templates. This allows # Ruby's coverage library before Ruby 3.2 to consider code created # by templates. You may not need this plugin on Ruby 3.2+, since # on Ruby 3.2+, coverage can consider code loaded with +eval+. # This plugin is only supported when using tilt 2.1+, since it # requires the compiled_path supported added in tilt 2.1. # # By default, the render_coverage plugin will use +coverage/views+ # as the directory containing the compiled template files. You can # change this by passing the :dir option when loading the plugin. # By default, the plugin will set the compiled_path by taking the # template file path, stripping off any of the allowed_paths used # by the render plugin, and converting slashes to dashes. You can # override the allowed_paths to strip by passing the :strip_paths # option when loading the plugin. Paths outside :strip_paths (or # the render plugin allowed_paths if :strip_paths is not set) will # not have a compiled_path set. # # Due to how Ruby's coverage library works in regards to loading # a compiled template file with identical code more than once, # it may be beneficial to run coverage testing with the # +RODA_RENDER_COMPILED_METHOD_SUPPORT+ environment variable set # to +no+ if using this plugin. module RenderCoverage def self.load_dependencies(app, opts=OPTS) app.plugin :render end # Use the :dir option to set the directory to store the compiled # template files, and the :strip_paths directory for paths to # strip. def self.configure(app, opts=OPTS) app.opts[:render_coverage_strip_paths] = opts[:strip_paths].map{|f| File.expand_path(f)} if opts.has_key?(:strip_paths) coverage_dir = app.opts[:render_coverage_dir] = opts[:dir] || app.opts[:render_coverage_dir] || 'coverage/views' Dir.mkdir(coverage_dir) unless File.directory?(coverage_dir) end module ClassMethods # Set a compiled path on the created template, if the path for # the template is in one of the allowed_views. def create_template(opts, template_opts) template = super return template if opts[:template_block] path = File.expand_path(opts[:path]) (self.opts[:render_coverage_strip_paths] || render_opts[:allowed_paths]).each do |dir| if path.start_with?(dir + '/') template.compiled_path = File.join(self.opts[:render_coverage_dir], path[dir.length+1, 10000000].gsub('/', '-')) break end end template end end module InstanceMethods private # Convert template paths to real paths to try to ensure the same template is cached. def template_path(opts) path = super if File.file?(path) File.realpath(path) else path end end end end register_plugin(:render_coverage, RenderCoverage) end end