chatterbox 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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