diff --git a/lib/bugsnag/configuration.rb b/lib/bugsnag/configuration.rb index cb922a356..633da956b 100644 --- a/lib/bugsnag/configuration.rb +++ b/lib/bugsnag/configuration.rb @@ -5,6 +5,7 @@ require "bugsnag/middleware/callbacks" require "bugsnag/middleware/exception_meta_data" require "bugsnag/middleware/ignore_error_class" +require "bugsnag/middleware/suggestion_data" require "bugsnag/middleware/classify_error" module Bugsnag @@ -74,6 +75,7 @@ def initialize self.internal_middleware = Bugsnag::MiddlewareStack.new self.internal_middleware.use Bugsnag::Middleware::ExceptionMetaData self.internal_middleware.use Bugsnag::Middleware::IgnoreErrorClass + self.internal_middleware.use Bugsnag::Middleware::SuggestionData self.internal_middleware.use Bugsnag::Middleware::ClassifyError self.middleware = Bugsnag::MiddlewareStack.new diff --git a/lib/bugsnag/middleware/suggestion_data.rb b/lib/bugsnag/middleware/suggestion_data.rb new file mode 100644 index 000000000..696af1171 --- /dev/null +++ b/lib/bugsnag/middleware/suggestion_data.rb @@ -0,0 +1,30 @@ +module Bugsnag::Middleware + class SuggestionData + + CAPTURE_REGEX = /Did you mean\?([\s\S]+)$/ + DELIMITER = "\n" + + def initialize(bugsnag) + @bugsnag = bugsnag + end + + def call(report) + matches = [] + report.raw_exceptions.each do |exception| + match = CAPTURE_REGEX.match(exception.message) + next unless match + + suggestions = match.captures[0].split(DELIMITER) + matches.concat suggestions.map{ |suggestion| suggestion.strip } + end + + if matches.size == 1 + report.add_tab(:error, {:suggestion => matches.first}) + elsif matches.size > 1 + report.add_tab(:error, {:suggestions => matches}) + end + + @bugsnag.call(report) + end + end +end diff --git a/spec/middleware_spec.rb b/spec/middleware_spec.rb index 267669e4f..7f8d23aa7 100644 --- a/spec/middleware_spec.rb +++ b/spec/middleware_spec.rb @@ -178,6 +178,41 @@ def call(report) } end + if ruby_version_greater_equal?("2.3.0") + context "with a ruby version >= 2.3.0" do + it "attaches did you mean metadata when necessary" do + begin + "Test".starts_with? "T" + rescue Exception => e + Bugsnag.notify(e) + end + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["metaData"]["error"]).to_not be_nil + expect(event["metaData"]["error"]).to eq({"suggestion" => "start_with?"}) + } + end + end + end + + context "with a ruby version < 2.3.0" do + if !ruby_version_greater_equal?("2.3.0") + it "doesn't attach did you mean metadata" do + begin + "Test".starts_with? "T" + rescue Exception => e + Bugsnag.notify(e) + end + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["metaData"]["error"]).to be_nil + } + end + end + end + it "doesn't allow handledState properties to be changed in middleware" do HandledStateChanger = Class.new do def initialize(bugsnag) @@ -216,5 +251,4 @@ def call(report) }) } end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 549e8e605..7e91198fb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,6 +30,14 @@ def notify_test_exception(*args) Bugsnag.notify(RuntimeError.new("test message"), *args) end +def ruby_version_greater_equal?(version) + current_version = RUBY_VERSION.split "." + target_version = version.split "." + (Integer(current_version[0]) >= Integer(target_version[0])) && + (Integer(current_version[1]) >= Integer(target_version[1])) && + (Integer(current_version[2]) >= Integer(target_version[2])) +end + RSpec.configure do |config| config.order = "random"