Filter Docile's source files from backtrace (#36)

Extend any raised NoMethodError with a module to filter out Docile code
from the {#backtrace} and {#backtrace_locations} methods.

* Fixed #35
This commit is contained in:
Taichi Ishitani 2019-10-23 02:29:58 +09:00 committed by Marc Siegel
parent a55d91caba
commit def1671ce4
4 changed files with 48 additions and 1 deletions

View File

@ -2,6 +2,7 @@ require "docile/version"
require "docile/execution"
require "docile/fallback_context_proxy"
require "docile/chaining_fallback_context_proxy"
require "docile/backtrace_filter"
# Docile keeps your Ruby DSLs tame and well-behaved.
module Docile

View File

@ -0,0 +1,22 @@
module Docile
# @api private
#
# This is used to remove entries pointing to Docile's source files
# from {Exception#backtrace} and {Exception#backtrace_locations}.
#
# If {NoMethodError} is caught then the exception object will be extended
# by this module to add filter functionalities.
module BacktraceFilter
FILTER_PATTERN = /lib\/docile/
def backtrace
super.select { |trace| trace !~ FILTER_PATTERN }
end
if ::Exception.public_method_defined?(:backtrace_locations)
def backtrace_locations
super.select { |location| location.absolute_path !~ FILTER_PATTERN }
end
end
end
end

View File

@ -86,7 +86,12 @@ module Docile
if @__receiver__.respond_to?(method.to_sym)
@__receiver__.__send__(method.to_sym, *args, &block)
else
@__fallback__.__send__(method.to_sym, *args, &block)
begin
@__fallback__.__send__(method.to_sym, *args, &block)
rescue NoMethodError => e
e.extend(BacktraceFilter)
raise e
end
end
end
end

View File

@ -416,6 +416,25 @@ describe Docile do
end
end
context "when NoMethodError is raised" do
specify "#backtrace does not include path to Docile's source file" do
begin
Docile.dsl_eval(Object.new) { foo }
rescue NoMethodError => e
expect(e.backtrace).not_to include(match(/lib\/docile/))
end
end
if ::Exception.public_method_defined?(:backtrace_locations)
specify "#backtrace_locations also does not include path to Docile's source file" do
begin
Docile.dsl_eval(Object.new) { foo }
rescue NoMethodError => e
expect(e.backtrace_locations.map(&:absolute_path)).not_to include(match(/lib\/docile/))
end
end
end
end
end
describe ".dsl_eval_with_block_return" do