chatterbox 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.markdown CHANGED
@@ -1,5 +1,8 @@
1
1
  HEAD
2
2
 
3
+ 0.6.0
4
+ - Extract exception handling to Chatterbox::ExceptionNotification, and have RailsCatcher use that
5
+ - clean up and standardize names of things
3
6
  0.5.4
4
7
  - Remove very dangerous delegation from RailsCatcher, as these delegates can override common
5
8
  ActionController::Base methods when the catcher is included. Wishing Ruby had real namespaces
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 5
4
- :patch: 4
3
+ :minor: 6
5
4
  :build:
5
+ :patch: 0
data/chatterbox.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{chatterbox}
8
- s.version = "0.5.4"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rob Sanheim"]
12
- s.date = %q{2009-11-13}
12
+ s.date = %q{2009-11-15}
13
13
  s.description = %q{Send notifications and messages. However you want.}
14
14
  s.email = %q{rsanheim@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "examples/lib/chatterbox/exception_notification/extracter_example.rb",
30
30
  "examples/lib/chatterbox/exception_notification/presenter_example.rb",
31
31
  "examples/lib/chatterbox/exception_notification/rails_extracter_example.rb",
32
+ "examples/lib/chatterbox/exception_notification_example.rb",
32
33
  "examples/lib/chatterbox/rails_catcher_controller_example.rb",
33
34
  "examples/lib/chatterbox/rails_catcher_example.rb",
34
35
  "examples/lib/chatterbox/services/email/mailer_example.rb",
@@ -60,6 +61,7 @@ Gem::Specification.new do |s|
60
61
  "examples/lib/chatterbox/exception_notification/extracter_example.rb",
61
62
  "examples/lib/chatterbox/exception_notification/presenter_example.rb",
62
63
  "examples/lib/chatterbox/exception_notification/rails_extracter_example.rb",
64
+ "examples/lib/chatterbox/exception_notification_example.rb",
63
65
  "examples/lib/chatterbox/rails_catcher_controller_example.rb",
64
66
  "examples/lib/chatterbox/rails_catcher_example.rb",
65
67
  "examples/lib/chatterbox/services/email/mailer_example.rb",
@@ -3,24 +3,22 @@ require 'chatterbox/exception_notification'
3
3
 
4
4
  describe Chatterbox::ExceptionNotification::Extracter do
5
5
 
6
- def raised_exception
7
- raise RuntimeError, "Your zing bats got mixed up with the snosh frazzles."
8
- rescue => e
9
- e
10
- end
11
-
12
6
  describe "notice" do
13
- it "should extract exception info" do
14
- exception = raised_exception
15
- data = Chatterbox::ExceptionNotification::Extracter.new(exception).notice
16
- data[:summary].should == "RuntimeError: Your zing bats got mixed up with the snosh frazzles."
17
- data[:error_class].should == "RuntimeError"
18
- data[:error_message].should == "Your zing bats got mixed up with the snosh frazzles."
19
- data[:backtrace].should == exception.backtrace
7
+ it "merges ruby info" do
8
+ hsh = {}
9
+ data = Chatterbox::ExceptionNotification::Extracter.new(hsh).notice
10
+ data[:ruby_info][:ruby_version].should == RUBY_VERSION
11
+ data[:ruby_info][:ruby_platform].should == RUBY_PLATFORM
12
+ end
13
+
14
+ it "merges environment hash" do
15
+ hsh = {}
16
+ data = Chatterbox::ExceptionNotification::Extracter.new(hsh).notice
17
+ data[:environment].should == ENV.to_hash
20
18
  end
21
19
 
22
20
  it "should extract exception info from an exception in a hash" do
23
- exception = raised_exception
21
+ exception = RuntimeError.new("Your zing bats got mixed up with the snosh frazzles.")
24
22
  data = Chatterbox::ExceptionNotification::Extracter.new(:exception => exception, :other_info => "yo dawg").notice
25
23
  data[:summary].should == "RuntimeError: Your zing bats got mixed up with the snosh frazzles."
26
24
  data[:error_class].should == "RuntimeError"
@@ -30,8 +28,7 @@ describe Chatterbox::ExceptionNotification::Extracter do
30
28
  end
31
29
 
32
30
  it "should let extra data win over auto extracted exception data" do
33
- exception = raised_exception
34
- data = Chatterbox::ExceptionNotification::Extracter.new(:exception => exception, :summary => "I know what I'm doing, and we got an error").notice
31
+ data = Chatterbox::ExceptionNotification::Extracter.new(:exception => Exception.new, :summary => "I know what I'm doing, and we got an error").notice
35
32
  data[:summary].should == "I know what I'm doing, and we got an error"
36
33
  end
37
34
  end
@@ -76,7 +76,7 @@ describe Chatterbox::ExceptionNotification::RailsExtracter do
76
76
  it "returns top level Rails config if defined" do
77
77
  Object.expects(:const_defined?).with("Rails").returns(true)
78
78
  Object.expects(:const_get).with("Rails").returns("fake rails const")
79
- extracter = Chatterbox::ExceptionNotification::RailsExtracter.new
79
+ extracter = Chatterbox::ExceptionNotification::RailsExtracter.new({})
80
80
  extracter.rails_configuration.should == "fake rails const"
81
81
  end
82
82
  end
@@ -0,0 +1,66 @@
1
+ require 'example_helper'
2
+ require 'chatterbox/exception_notification'
3
+
4
+ describe Chatterbox::ExceptionNotification do
5
+
6
+ describe "handling" do
7
+ it "accepts exceptions" do
8
+ Chatterbox::ExceptionNotification.handle(Exception.new)
9
+ end
10
+
11
+ it "accepts hashes" do
12
+ Chatterbox::ExceptionNotification.handle(:exception => Exception.new)
13
+ end
14
+
15
+ describe "when on ignore list" do
16
+ after do
17
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore = Chatterbox::ExceptionNotification.default_ignored_exceptions }
18
+ end
19
+
20
+ it "returns nil for explicit exception" do
21
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore << RuntimeError }
22
+ Chatterbox::ExceptionNotification.handle(RuntimeError.new).should be_nil
23
+ end
24
+
25
+ it "returns nil for :exception => exception" do
26
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore << RuntimeError }
27
+ Chatterbox::ExceptionNotification.handle(:exception => RuntimeError.new).should be_nil
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ describe "normalize_to_hash" do
34
+ it "returns :exception => for exception" do
35
+ exception = RuntimeError.new
36
+ Chatterbox::ExceptionNotification.normalize_to_hash(exception).should == { :exception => exception }
37
+ end
38
+
39
+ it "returns hashes as is" do
40
+ Chatterbox::ExceptionNotification.normalize_to_hash({}).should == {}
41
+ end
42
+
43
+ it "returns string like objects as :summary => obj.to_s" do
44
+ Chatterbox::ExceptionNotification.normalize_to_hash("failure").should == { :summary => "failure" }
45
+ end
46
+ end
47
+
48
+ describe "configuration" do
49
+ after do
50
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore = Chatterbox::ExceptionNotification.default_ignored_exceptions }
51
+ end
52
+
53
+ it "ignores common Rails exceptions by default" do
54
+ Chatterbox::ExceptionNotification.configuration.ignore.should == Chatterbox::ExceptionNotification.default_ignored_exceptions
55
+ end
56
+
57
+ it "allows adding exceptions to the ignore list" do
58
+ Chatterbox::ExceptionNotification.configure do |config|
59
+ config.ignore << "SomeOtherException"
60
+ end
61
+ Chatterbox::ExceptionNotification.configuration.ignore.should include("SomeOtherException")
62
+ end
63
+ end
64
+
65
+
66
+ end
@@ -54,7 +54,7 @@ describe WidgetsController do
54
54
  end
55
55
 
56
56
  it "should send exception notice as hash" do
57
- Chatterbox.expects(:handle_notice).with(instance_of(Hash))
57
+ Chatterbox::ExceptionNotification.expects(:handle).with(instance_of(Hash))
58
58
  get :index rescue nil
59
59
  end
60
60
  end
@@ -62,11 +62,11 @@ describe WidgetsController do
62
62
  describe "ignoring exceptions" do
63
63
  describe "when configured to ignore RuntimeError (as class)" do
64
64
  before do
65
- Chatterbox::RailsCatcher.configure { |c| c.ignore << RuntimeError }
65
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore << RuntimeError }
66
66
  end
67
67
 
68
68
  after do
69
- Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
69
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore = Chatterbox::ExceptionNotification.default_ignored_exceptions }
70
70
  end
71
71
 
72
72
  it "handles exceptions normally" do
@@ -85,11 +85,11 @@ describe WidgetsController do
85
85
 
86
86
  describe "when configured to ignore RuntimeError (as String)" do
87
87
  before do
88
- Chatterbox::RailsCatcher.configure { |c| c.ignore << "RuntimeError" }
88
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore << "RuntimeError" }
89
89
  end
90
90
 
91
91
  after do
92
- Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
92
+ Chatterbox::ExceptionNotification.configure { |c| c.ignore = Chatterbox::ExceptionNotification.default_ignored_exceptions }
93
93
  end
94
94
 
95
95
  it "handles exceptions normally" do
@@ -5,25 +5,29 @@ require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. rails in
5
5
  describe Chatterbox::RailsCatcher do
6
6
 
7
7
  def helper
8
- @helper ||= Class.new {
8
+ @helper ||= Class.new do
9
+ def rescue_action_in_public(exception); end
10
+ def self.hide_action(*name); end
11
+
9
12
  include Chatterbox::RailsCatcher
10
- }.new
13
+ end.new
11
14
  end
12
15
 
13
- describe "configuration" do
14
- after do
15
- Chatterbox::RailsCatcher.configure { |c| c.ignore = Chatterbox::RailsCatcher.default_ignored_exceptions }
16
- end
17
-
18
- it "ignores common Rails exceptions by default" do
19
- Chatterbox::RailsCatcher.configuration.ignore.should == Chatterbox::RailsCatcher.default_ignored_exceptions
16
+ describe "rescue_action_in_public_with_chatterbox" do
17
+ describe "when request is not available" do
18
+ it "sends exception and request hash to ExceptionNotification" do
19
+ exception = stub_everything
20
+ helper.stubs(:request).returns(request = stub_everything)
21
+ Chatterbox::ExceptionNotification.expects(:handle).with(:exception => exception, :request => request)
22
+ helper.rescue_action_in_public_with_chatterbox(exception)
23
+ end
20
24
  end
21
25
 
22
- it "allows adding exceptions to the ignore list" do
23
- Chatterbox::RailsCatcher.configure do |config|
24
- config.ignore << "SomeOtherException"
26
+ describe "when request is not available" do
27
+ it "sends the exception hash on to ExceptionNotification" do
28
+ Chatterbox::ExceptionNotification.expects(:handle).with(:exception => (exception = stub))
29
+ helper.rescue_action_in_public_with_chatterbox(exception)
25
30
  end
26
- Chatterbox::RailsCatcher.configuration.ignore.should include("SomeOtherException")
27
31
  end
28
32
  end
29
33
  end
@@ -1,46 +1,26 @@
1
1
  module Chatterbox::ExceptionNotification
2
2
  class Extracter
3
- attr_reader :message
4
-
5
3
  def self.wrap(notification = {})
6
4
  new(notification).notice
7
5
  end
8
6
 
9
- def initialize(message = {})
10
- @message = message
7
+ def initialize(notification)
8
+ @notification = notification
11
9
  end
12
10
 
13
11
  def notice
14
- hash = normalize_message_to_hash(message)
15
- hash = exception_to_notice(hash)
16
- default_info.merge(hash)
17
- end
18
-
19
- def normalize_message_to_hash(message)
20
- case
21
- when Exception === message
22
- { :exception => message }
23
- when message.respond_to?(:to_hash)
24
- message.to_hash
25
- when message.respond_to?(:to_s)
26
- string_to_notice(message.to_s)
27
- end
12
+ hash = extract_exception_info(@notification)
13
+ hash = extract_ruby_info(hash)
14
+ extract_default_info(hash)
28
15
  end
29
16
 
30
- def default_info
31
- default_info = {
32
- :summary => "N/A",
33
- :environment => env
34
- }
35
- default_info = add_ruby_info(default_info)
36
- default_info
37
- end
38
-
39
- def string_to_notice(message)
40
- { :summary => message }
17
+ def extract_default_info(hash)
18
+ { :summary => "N/A",
19
+ :environment => ENV.to_hash
20
+ }.merge(hash)
41
21
  end
42
22
 
43
- def exception_to_notice(hash)
23
+ def extract_exception_info(hash)
44
24
  return hash unless hash.key?(:exception)
45
25
  exception = hash[:exception]
46
26
  {
@@ -51,25 +31,13 @@ module Chatterbox::ExceptionNotification
51
31
  }.merge(hash)
52
32
  end
53
33
 
54
- def add_ruby_info(data)
55
- data.merge({
34
+ def extract_ruby_info(hash)
35
+ hash.merge({
56
36
  :ruby_info => {
57
- :ruby_version => ruby_version,
58
- :ruby_platform => ruby_platform
37
+ :ruby_version => RUBY_VERSION,
38
+ :ruby_platform => RUBY_PLATFORM
59
39
  }
60
40
  })
61
41
  end
62
-
63
- def ruby_version
64
- RUBY_VERSION
65
- end
66
-
67
- def ruby_platform
68
- RUBY_PLATFORM
69
- end
70
-
71
- def env
72
- ENV.to_hash
73
- end
74
42
  end
75
43
  end
@@ -4,29 +4,28 @@ module Chatterbox::ExceptionNotification
4
4
  new(notification).notice
5
5
  end
6
6
 
7
- def initialize(message = {})
8
- @message = message
7
+ def initialize(notification)
8
+ @notification = notification
9
9
  end
10
10
 
11
11
  def notice
12
- hsh = extract_rails_info(@message)
12
+ hsh = extract_rails_info(@notification)
13
13
  hsh = extract_request_info(hsh)
14
- hsh = filter_rails_root(hsh)
15
- hsh
14
+ filter_rails_root(hsh)
16
15
  end
17
16
 
18
- def filter_rails_root(hsh)
19
- return hsh unless hsh[:backtrace]
17
+ def filter_rails_root(hash)
18
+ return hash unless hash[:backtrace]
20
19
  cleaner = ActiveSupport::BacktraceCleaner.new
21
20
  cleaner.add_filter { |line| line.gsub(rails_root, "[RAILS_ROOT]") }
22
- backtrace = cleaner.clean(hsh[:backtrace])
23
- hsh[:backtrace] = backtrace
24
- hsh
21
+ backtrace = cleaner.clean(hash[:backtrace])
22
+ hash[:backtrace] = backtrace
23
+ hash
25
24
  end
26
25
 
27
- def extract_rails_info(message)
28
- return message if rails_configuration.nil?
29
- message.merge({
26
+ def extract_rails_info(hash)
27
+ return hash if rails_configuration.nil?
28
+ hash.merge({
30
29
  :rails_info => {
31
30
  :rails_env => rails_configuration.env.to_s,
32
31
  :rails_root => rails_root,
@@ -35,10 +34,10 @@ module Chatterbox::ExceptionNotification
35
34
  })
36
35
  end
37
36
 
38
- def extract_request_info(message)
39
- return message unless message.key?(:request)
40
- request = message.delete(:request)
41
- message.merge({
37
+ def extract_request_info(hash)
38
+ return hash unless hash.key?(:request)
39
+ request = hash.delete(:request)
40
+ hash.merge({
42
41
  :request => {
43
42
  :url => request.url,
44
43
  :remote_ip => request.remote_ip,
@@ -1,5 +1,60 @@
1
+ require 'ostruct'
2
+
1
3
  module Chatterbox
2
4
  module ExceptionNotification
5
+
6
+ # Handle the exception
7
+ # Accepts either an exception, a hash, or an object that responds to to_s
8
+ # Exceptions are passed through like normal
9
+ # Hashes can have an :exception => exception in them, which will result in
10
+ # the same treatment as a literal exception passed
11
+ # Objects are simply treated as a 'summary' message were an exception may not be necessary
12
+ def handle(args)
13
+ hsh = normalize_to_hash(args)
14
+ return if on_ignore_list?(hsh[:exception])
15
+ hsh = Extracter.wrap(hsh)
16
+ hsh = RailsExtracter.wrap(hsh)
17
+ hsh = Presenter.render(hsh)
18
+ Chatterbox.notify(hsh)
19
+ end
20
+
21
+ def normalize_to_hash(args)
22
+ case
23
+ when Exception === args then { :exception => args }
24
+ when args.respond_to?(:to_hash) then args.to_hash
25
+ when args.respond_to?(:to_s) then { :summary => args.to_s }
26
+ end
27
+ end
28
+
29
+ def on_ignore_list?(exception)
30
+ configuration.ignore.include?(exception.class) ||
31
+ configuration.ignore.include?(exception.class.to_s)
32
+ end
33
+
34
+ def configuration
35
+ @configuration ||= OpenStruct.new(:ignore => default_ignored_exceptions)
36
+ end
37
+
38
+ # Configure ExceptionNotification
39
+ # ex:
40
+ # Chatterbox::ExceptionNotification.configure do |config|
41
+ # config.ignore << MyOwnExceptionToIgnore
42
+ # end
43
+ #
44
+ #
45
+ def configure
46
+ yield(configuration)
47
+ end
48
+
49
+ # Default exceptions that ExceptionNotification will ignore
50
+ def default_ignored_exceptions
51
+ ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError',
52
+ 'ActionController::InvalidAuthenticityToken', 'ActionController::UnknownAction',
53
+ 'CGI::Session::CookieStore::TamperedWithCookie' ]
54
+ end
55
+
56
+ extend self
57
+
3
58
  end
4
59
  end
5
60
 
@@ -1,23 +1,6 @@
1
- require 'ostruct'
2
-
3
1
  module Chatterbox
4
-
5
2
  module RailsCatcher
6
3
 
7
- def self.default_ignored_exceptions
8
- ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError',
9
- 'ActionController::InvalidAuthenticityToken', 'ActionController::UnknownAction',
10
- 'CGI::Session::CookieStore::TamperedWithCookie' ]
11
- end
12
-
13
- def self.configuration
14
- @configuration ||= OpenStruct.new(:ignore => default_ignored_exceptions)
15
- end
16
-
17
- def self.configure
18
- yield(configuration)
19
- end
20
-
21
4
  def self.included(base)
22
5
  if base.instance_methods.map(&:to_s).include? 'rescue_action_in_public' and !base.instance_methods.map(&:to_s).include? 'rescue_action_in_public_without_chatterbox'
23
6
  base.send(:alias_method, :rescue_action_in_public_without_chatterbox, :rescue_action_in_public)
@@ -29,29 +12,13 @@ module Chatterbox
29
12
  # Overrides the rescue_action method in ActionController::Base, but does not inhibit
30
13
  # any custom processing that is defined with Rails 2's exception helpers.
31
14
  def rescue_action_in_public_with_chatterbox(exception)
32
- Chatterbox.logger.debug { "Chatterbox caught exception #{exception} - about to handle" }
33
- unless on_ignore_list?(exception)
34
- Chatterbox.handle_notice(extract_exception_details(exception))
35
- end
36
- Chatterbox.logger.debug { "Chatterbox handing exception #{exception} off to normal rescue handling" }
15
+ Chatterbox.logger.debug { "Chatterbox caught exception '#{exception}' - about to handle" }
16
+ options = { :exception => exception }
17
+ options.merge!(:request => request) if self.respond_to?(:request)
18
+ Chatterbox::ExceptionNotification.handle(options)
19
+ Chatterbox.logger.debug { "Chatterbox handing exception '#{exception}' off to normal rescue handling" }
37
20
  rescue_action_in_public_without_chatterbox(exception)
38
21
  end
39
22
 
40
- private
41
-
42
- def on_ignore_list?(exception)
43
- Chatterbox::RailsCatcher.configuration.ignore.include?(exception.class) ||
44
- Chatterbox::RailsCatcher.configuration.ignore.include?(exception.class.to_s)
45
- end
46
-
47
- def extract_exception_details(exception)
48
- options = { :exception => exception, :request => request }
49
- options = Chatterbox::ExceptionNotification::Extracter.wrap(options)
50
- options = Chatterbox::ExceptionNotification::RailsExtracter.wrap(options)
51
- options = Chatterbox::ExceptionNotification::Presenter.render(options)
52
- options
53
- end
54
-
55
23
  end
56
-
57
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chatterbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Sanheim
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-13 00:00:00 -05:00
12
+ date: 2009-11-15 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -74,6 +74,7 @@ files:
74
74
  - examples/lib/chatterbox/exception_notification/extracter_example.rb
75
75
  - examples/lib/chatterbox/exception_notification/presenter_example.rb
76
76
  - examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
77
+ - examples/lib/chatterbox/exception_notification_example.rb
77
78
  - examples/lib/chatterbox/rails_catcher_controller_example.rb
78
79
  - examples/lib/chatterbox/rails_catcher_example.rb
79
80
  - examples/lib/chatterbox/services/email/mailer_example.rb
@@ -127,6 +128,7 @@ test_files:
127
128
  - examples/lib/chatterbox/exception_notification/extracter_example.rb
128
129
  - examples/lib/chatterbox/exception_notification/presenter_example.rb
129
130
  - examples/lib/chatterbox/exception_notification/rails_extracter_example.rb
131
+ - examples/lib/chatterbox/exception_notification_example.rb
130
132
  - examples/lib/chatterbox/rails_catcher_controller_example.rb
131
133
  - examples/lib/chatterbox/rails_catcher_example.rb
132
134
  - examples/lib/chatterbox/services/email/mailer_example.rb