hoptoad_notifier 2.1.3 → 2.2.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 ADDED
@@ -0,0 +1,41 @@
1
+ Version 2.2.0 - 2010-02-18
2
+ ===============================================================================
3
+
4
+ Bumping the version from 2.1.4 to 2.2.0 since adding Rack support warrants a minor version.
5
+
6
+ Jason Morrison (1):
7
+ Stringify array elements when making assertions about Notice XML for 1.9 compatibility
8
+
9
+
10
+ Version 2.1.4 - 2010-02-12
11
+ ===============================================================================
12
+
13
+ Chad Pytel (2):
14
+ add more info to README for 1.2.6
15
+ fix gem unpack line for 1.2.6
16
+
17
+ Jason Morrison (2):
18
+ Adding additional instructions for Rails 1.2.6
19
+ Typesetting in README.rdoc
20
+
21
+ Joe Ferris (11):
22
+ Separating Rails functionality out more
23
+ Initial Rack middleware
24
+ Extract request info from rack env
25
+ Added integration tests for rescuing
26
+ Fixed reporting of Rails version
27
+ Small refactoring
28
+ Automatically add Rack middleware for Rails apps that support it (catches exceptions from Metal)
29
+ Added an integration test and docs for rack apps
30
+ Added integration/readme coverage of Sinatra apps
31
+ Added docs to HoptoadNotifier::Rack
32
+ Require rack in tests for older versions of Rails; use active_support instead of activesupport
33
+
34
+ Nick Quaranto (3):
35
+ Fixing the capistrano hook bit in the readme
36
+ Adding changeling:minor and changeling:patch to automate notifier releases
37
+ Adding rake changeling:push
38
+
39
+
40
+
41
+
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ to the Hoptoad server specified in your environment.
10
10
  * {IRC}[irc://irc.freenode.net/thoughtbot]
11
11
  * {mailing list}[http://groups.google.com/group/hoptoad-notifier-dev]
12
12
 
13
- == Installation
13
+ == Rails Installation
14
14
 
15
15
  === Remove exception_notifier
16
16
 
@@ -48,15 +48,37 @@ every server you deploy to has the gem installed or your application won't start
48
48
 
49
49
  === Rails 1.2.6
50
50
 
51
- Install the hoptoad_notifier Gem, and then add something like this at the
52
- bottom of your config/environment.rb:
51
+ Install the hoptoad_notifier gem:
53
52
 
53
+ gem install hoptoad_notifier
54
+
55
+ Once installed, you should vendor the hoptoad_notifier gem:
56
+
57
+ mkdir vendor/gems
58
+ cd vendor/gems
59
+ gem unpack hoptoad_notifier
60
+
61
+ And then add the following to the Rails::Initializer.run do |config|
62
+ block in environment.rb so that the vendored gem is loaded.
63
+
64
+ # Add the vendor/gems/*/lib directories to the LOAD_PATH
65
+ config.load_paths += Dir.glob(File.join(RAILS_ROOT, 'vendor', 'gems', '*', 'lib'))
66
+
67
+ Next add something like this at the bottom of your config/environment.rb:
68
+
69
+ require 'hoptoad_notifier'
70
+ require 'hoptoad_notifier/rails'
54
71
  HoptoadNotifier.configure do |config|
55
72
  config.api_key = 'your_key_here'
56
73
  end
57
74
 
58
- You will need to copy the hoptoad_notifier_tasks.rake file into your
59
- RAILS_ROOT/lib/tasks directory in order for the rake hoptoad:test task to work.
75
+ You will also need to copy the hoptoad_notifier_tasks.rake file into your
76
+ RAILS_ROOT/lib/tasks directory in order for the rake hoptoad:test task to work:
77
+
78
+ cp vendor/gems/hoptoad_notifier-2.1.3/generators/hoptoad/templates/hoptoad_notifier_tasks.rake lib/tasks
79
+
80
+ As always, if you choose not to vendor the hoptoad_notifier gem, make sure
81
+ every server you deploy to has the gem installed or your application won't start.
60
82
 
61
83
  === Testing it out
62
84
 
@@ -68,6 +90,45 @@ this rake task (from RAILS_ROOT):
68
90
  If everything is configured properly, that task will send a notice to Hoptoad
69
91
  which will be visible immediately.
70
92
 
93
+ == Rack
94
+
95
+ In order to use hoptoad_notifier in a non-Rails rack app, just load the
96
+ hoptoad_notifier, configure your API key, and use the HoptoadNotifier::Rack
97
+ middleware:
98
+
99
+ require 'rack'
100
+ require 'hoptoad_notifier'
101
+
102
+ HoptoadNotifier.configure do |config|
103
+ config.api_key = 'my_api_key'
104
+ end
105
+
106
+ app = Rack::Builder.app do
107
+ use HoptoadNotifier::Rack
108
+ run lambda { |env| raise "Rack down" }
109
+ end
110
+
111
+ == Sinatra
112
+
113
+ Using hoptoad_notifier in a Sinatra app is just like a Rack app, but you have
114
+ to disable Sinatra's error rescuing functionality:
115
+
116
+ require 'sinatra/base'
117
+ require 'hoptoad_notifier'
118
+
119
+ HoptoadNotifier.configure do |config|
120
+ config.api_key = 'my_api_key'
121
+ end
122
+
123
+ class MyApp < Sinatra::Default
124
+ use HoptoadNotifier::Rack
125
+ enable :raise_errors
126
+
127
+ get "/" do
128
+ raise "Sinatra has left the building"
129
+ end
130
+ end
131
+
71
132
  == Usage
72
133
 
73
134
  For the most part, Hoptoad works for itself. Once you've included the notifier
@@ -102,7 +163,7 @@ Additionally, it's possible to review the errors in Hoptoad that occurred before
102
163
 
103
164
  When Hoptoad is installed as a gem, you need to add
104
165
 
105
- require 'hoptoad_notifier/recipes/hoptoad'
166
+ require 'hoptoad_notifier/capistrano'
106
167
 
107
168
  to your deploy.rb
108
169
 
data/Rakefile CHANGED
@@ -22,6 +22,83 @@ task :ginger do
22
22
  load File.join(*%w[vendor ginger bin ginger])
23
23
  end
24
24
 
25
+ namespace :changeling do
26
+ desc "Bumps the version by a minor or patch version, depending on what was passed in."
27
+ task :bump, :part do |t, args|
28
+ # Thanks, Jeweler!
29
+ if HoptoadNotifier::VERSION =~ /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/
30
+ major = $1.to_i
31
+ minor = $2.to_i
32
+ patch = $3.to_i
33
+ build = $4
34
+ else
35
+ abort
36
+ end
37
+
38
+ case args[:part]
39
+ when /minor/
40
+ minor += 1
41
+ patch = 0
42
+ when /patch/
43
+ patch += 1
44
+ else
45
+ abort
46
+ end
47
+
48
+ version = [major, minor, patch, build].compact.join('.')
49
+
50
+ File.open(File.join("lib", "hoptoad_notifier", "version.rb"), "w") do |f|
51
+ f.write <<EOF
52
+ module HoptoadNotifier
53
+ VERSION = "#{version}".freeze
54
+ end
55
+ EOF
56
+ end
57
+ end
58
+
59
+ desc "Writes out the new CHANGELOG and prepares the release"
60
+ task :change do
61
+ load 'lib/hoptoad_notifier/version.rb'
62
+ file = "CHANGELOG"
63
+ old = File.read(file)
64
+ version = HoptoadNotifier::VERSION
65
+ message = "Bumping to version #{version}"
66
+
67
+ File.open(file, "w") do |f|
68
+ f.write <<EOF
69
+ Version #{version} - #{Date.today}
70
+ ===============================================================================
71
+
72
+ #{`git log $(git tag | tail -1)..HEAD | git shortlog`}
73
+ #{old}
74
+ EOF
75
+ end
76
+
77
+ exec ["#{ENV["EDITOR"]} #{file}",
78
+ "git commit -aqm '#{message}'",
79
+ "git tag -a -m '#{message}' v#{version}",
80
+ "echo '\n\n\033[32mMarked v#{version} /' `git show-ref -s refs/heads/master` 'for release. Run: rake changeling:push\033[0m\n\n'"].join(' && ')
81
+ end
82
+
83
+ desc "Bump by a minor version (1.2.3 => 1.3.0)"
84
+ task :minor do |t|
85
+ Rake::Task['changeling:bump'].invoke(t.name)
86
+ Rake::Task['changeling:change'].invoke
87
+ end
88
+
89
+ desc "Bump by a patch version, (1.2.3 => 1.2.4)"
90
+ task :patch do |t|
91
+ Rake::Task['changeling:bump'].invoke(t.name)
92
+ Rake::Task['changeling:change'].invoke
93
+ end
94
+
95
+ desc "Push the latest version and tags"
96
+ task :push do |t|
97
+ system("git push origin master")
98
+ system("git push origin $(git tag | tail -1)")
99
+ end
100
+ end
101
+
25
102
  begin
26
103
  require 'yard'
27
104
  YARD::Rake::YardocTask.new do |t|
@@ -81,7 +158,7 @@ end
81
158
 
82
159
  LOCAL_GEM_ROOT = File.join(GEM_ROOT, 'tmp', 'local_gems').freeze
83
160
  RAILS_VERSIONS = IO.read('SUPPORTED_RAILS_VERSIONS').strip.split("\n")
84
- LOCAL_GEMS = [['sham_rack', nil], ['capistrano', nil], ['sqlite3-ruby', nil]] +
161
+ LOCAL_GEMS = [['sham_rack', nil], ['capistrano', nil], ['sqlite3-ruby', nil], ['sinatra', nil]] +
85
162
  RAILS_VERSIONS.collect { |version| ['rails', version] }
86
163
 
87
164
  task :vendor_test_gems do
@@ -107,19 +184,18 @@ end
107
184
 
108
185
  task :cucumber => [:gemspec, :vendor_test_gems]
109
186
 
110
- OLD_RAILS_VERSIONS = RAILS_VERSIONS[0...-1]
111
-
112
187
  namespace :cucumber do
113
188
  namespace :rails do
114
- OLD_RAILS_VERSIONS.each do |version|
189
+ RAILS_VERSIONS.each do |version|
115
190
  desc "Test integration of the gem with Rails #{version}"
116
191
  task version do
192
+ puts "Testing Rails #{version}"
117
193
  ENV['RAILS_VERSION'] = version
118
194
  system("cucumber --format progress features/rails.feature")
119
195
  end
120
196
  end
121
197
 
122
198
  desc "Test integration of the gem with all Rails versions"
123
- task :all => [:cucumber, *OLD_RAILS_VERSIONS]
199
+ task :all => RAILS_VERSIONS
124
200
  end
125
201
  end
@@ -6,8 +6,8 @@ require 'hoptoad_notifier/version'
6
6
  require 'hoptoad_notifier/configuration'
7
7
  require 'hoptoad_notifier/notice'
8
8
  require 'hoptoad_notifier/sender'
9
- require 'hoptoad_notifier/catcher'
10
9
  require 'hoptoad_notifier/backtrace'
10
+ require 'hoptoad_notifier/rack'
11
11
 
12
12
  # Gem for applications to automatically post errors to the Hoptoad of their choice.
13
13
  module HoptoadNotifier
@@ -47,7 +47,7 @@ module HoptoadNotifier
47
47
  # Returns the Ruby version, Rails version, and current Rails environment
48
48
  def environment_info
49
49
  info = "[Ruby: #{RUBY_VERSION}]"
50
- info << " [Rails: #{::Rails::VERSION::STRING}]" if defined?(Rails)
50
+ info << " [#{configuration.framework}]"
51
51
  info << " [Env: #{configuration.environment_name}]"
52
52
  end
53
53
 
@@ -7,7 +7,7 @@ module HoptoadNotifier
7
7
  :http_open_timeout, :http_read_timeout, :ignore, :ignore_by_filters,
8
8
  :ignore_user_agent, :notifier_name, :notifier_url, :notifier_version,
9
9
  :params_filters, :project_root, :port, :protocol, :proxy_host,
10
- :proxy_pass, :proxy_port, :proxy_user, :secure].freeze
10
+ :proxy_pass, :proxy_port, :proxy_user, :secure, :framework].freeze
11
11
 
12
12
  # The API key for your project, found on the project edit form.
13
13
  attr_accessor :api_key
@@ -80,6 +80,9 @@ module HoptoadNotifier
80
80
  # The logger used by HoptoadNotifier
81
81
  attr_accessor :logger
82
82
 
83
+ # The framework HoptoadNotifier is configured to use
84
+ attr_accessor :framework
85
+
83
86
  DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
84
87
 
85
88
  DEFAULT_BACKTRACE_FILTERS = [
@@ -124,6 +127,7 @@ module HoptoadNotifier
124
127
  @notifier_name = 'Hoptoad Notifier'
125
128
  @notifier_version = VERSION
126
129
  @notifier_url = 'http://hoptoadapp.com'
130
+ @framework = 'Standalone'
127
131
  end
128
132
 
129
133
  # Takes a block and adds it to the list of backtrace filters. When the filters
@@ -68,7 +68,7 @@ module HoptoadNotifier
68
68
  self.exception = args[:exception]
69
69
  self.api_key = args[:api_key]
70
70
  self.project_root = args[:project_root]
71
- self.url = args[:url]
71
+ self.url = args[:url] || rack_env(:url)
72
72
 
73
73
  self.notifier_name = args[:notifier_name]
74
74
  self.notifier_version = args[:notifier_version]
@@ -78,12 +78,12 @@ module HoptoadNotifier
78
78
  self.ignore_by_filters = args[:ignore_by_filters] || []
79
79
  self.backtrace_filters = args[:backtrace_filters] || []
80
80
  self.params_filters = args[:params_filters] || []
81
- self.parameters = args[:parameters] || {}
81
+ self.parameters = args[:parameters] || rack_env(:params) || {}
82
82
  self.component = args[:component] || args[:controller]
83
83
  self.action = args[:action]
84
84
 
85
85
  self.environment_name = args[:environment_name]
86
- self.cgi_data = args[:cgi_data]
86
+ self.cgi_data = args[:cgi_data] || args[:rack_env]
87
87
  self.backtrace = Backtrace.parse(exception_attribute(:backtrace, caller), :filters => self.backtrace_filters)
88
88
  self.error_class = exception_attribute(:error_class) {|exception| exception.class.name }
89
89
  self.error_message = exception_attribute(:error_message, 'Notification') do |exception|
@@ -291,5 +291,15 @@ module HoptoadNotifier
291
291
  end
292
292
  end
293
293
  end
294
+
295
+ def rack_env(method)
296
+ rack_request.send(method) if rack_request
297
+ end
298
+
299
+ def rack_request
300
+ @rack_request ||= if args[:rack_env]
301
+ ::Rack::Request.new(args[:rack_env])
302
+ end
303
+ end
294
304
  end
295
305
  end
@@ -0,0 +1,40 @@
1
+ module HoptoadNotifier
2
+ # Middleware for Rack applications. Any errors raised by the upstream
3
+ # application will be delivered to Hoptoad and re-raised.
4
+ #
5
+ # Synopsis:
6
+ #
7
+ # require 'rack'
8
+ # require 'hoptoad_notifier'
9
+ #
10
+ # HoptoadNotifier.configure do |config|
11
+ # config.api_key = 'my_api_key'
12
+ # end
13
+ #
14
+ # app = Rack::Builder.app do
15
+ # use HoptoadNotifier::Rack
16
+ # run lambda { |env| raise "Rack down" }
17
+ # end
18
+ #
19
+ # Use a standard HoptoadNotifier.configure call to configure your api key.
20
+ class Rack
21
+ def initialize(app)
22
+ @app = app
23
+ end
24
+
25
+ def call(env)
26
+ begin
27
+ response = @app.call(env)
28
+ rescue Exception => raised
29
+ HoptoadNotifier.notify_or_ignore(raised, :rack_env => env)
30
+ raise
31
+ end
32
+
33
+ if env['rack.exception']
34
+ HoptoadNotifier.notify_or_ignore(env['rack.exception'], :rack_env => env)
35
+ end
36
+
37
+ response
38
+ end
39
+ end
40
+ end
@@ -1,11 +1,37 @@
1
- if defined?(ActionController::Base) && !ActionController::Base.include?(HoptoadNotifier::Catcher)
2
- ActionController::Base.send(:include, HoptoadNotifier::Catcher)
3
- end
1
+ require 'hoptoad_notifier'
2
+ require 'hoptoad_notifier/rails/controller_methods'
3
+ require 'hoptoad_notifier/rails/action_controller_catcher'
4
+ require 'hoptoad_notifier/rails/error_lookup'
5
+
6
+ module HoptoadNotifier
7
+ module Rails
8
+ def self.initialize
9
+ if defined?(ActionController::Base)
10
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ActionControllerCatcher)
11
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ErrorLookup)
12
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ControllerMethods)
13
+ end
14
+
15
+ rails_logger = if defined?(::Rails.logger)
16
+ ::Rails.logger
17
+ elsif defined?(RAILS_DEFAULT_LOGGER)
18
+ RAILS_DEFAULT_LOGGER
19
+ end
4
20
 
5
- require 'hoptoad_notifier/rails_initializer'
6
- HoptoadNotifier::RailsInitializer.initialize
21
+ if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
22
+ ::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
23
+ HoptoadNotifier::Rack
24
+ end
7
25
 
8
- HoptoadNotifier.configure(true) do |config|
9
- config.environment_name = RAILS_ENV
10
- config.project_root = RAILS_ROOT
26
+ HoptoadNotifier.configure(true) do |config|
27
+ config.logger = rails_logger
28
+ config.environment_name = RAILS_ENV if defined?(RAILS_ENV)
29
+ config.project_root = RAILS_ROOT if defined?(RAILS_ROOT)
30
+ config.framework = "Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION)
31
+ end
32
+ end
33
+ end
11
34
  end
35
+
36
+ HoptoadNotifier::Rails.initialize
37
+
@@ -0,0 +1,29 @@
1
+ module HoptoadNotifier
2
+ module Rails
3
+ module ActionControllerCatcher
4
+
5
+ # Sets up an alias chain to catch exceptions when Rails does
6
+ def self.included(base) #:nodoc:
7
+ base.send(:alias_method, :rescue_action_in_public_without_hoptoad, :rescue_action_in_public)
8
+ base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_hoptoad)
9
+ end
10
+
11
+ private
12
+
13
+ # Overrides the rescue_action method in ActionController::Base, but does not inhibit
14
+ # any custom processing that is defined with Rails 2's exception helpers.
15
+ def rescue_action_in_public_with_hoptoad(exception)
16
+ unless hoptoad_ignore_user_agent?
17
+ HoptoadNotifier.notify_or_ignore(exception, hoptoad_request_data)
18
+ end
19
+ rescue_action_in_public_without_hoptoad(exception)
20
+ end
21
+
22
+ def hoptoad_ignore_user_agent? #:nodoc:
23
+ # Rails 1.2.6 doesn't have request.user_agent, so check for it here
24
+ user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
25
+ HoptoadNotifier.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,59 @@
1
+ module HoptoadNotifier
2
+ module Rails
3
+ module ControllerMethods
4
+ private
5
+
6
+ # This method should be used for sending manual notifications while you are still
7
+ # inside the controller. Otherwise it works like HoptoadNotifier.notify.
8
+ def notify_hoptoad(hash_or_exception)
9
+ unless consider_all_requests_local || local_request?
10
+ HoptoadNotifier.notify(hash_or_exception, hoptoad_request_data)
11
+ end
12
+ end
13
+
14
+ def hoptoad_ignore_user_agent? #:nodoc:
15
+ # Rails 1.2.6 doesn't have request.user_agent, so check for it here
16
+ user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
17
+ HoptoadNotifier.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
18
+ end
19
+
20
+ def hoptoad_request_data
21
+ { :parameters => hoptoad_filter_if_filtering(params.to_hash),
22
+ :session_data => hoptoad_session_data,
23
+ :controller => params[:controller],
24
+ :action => params[:action],
25
+ :url => hoptoad_request_url,
26
+ :cgi_data => hoptoad_filter_if_filtering(request.env),
27
+ :environment_vars => hoptoad_filter_if_filtering(ENV) }
28
+ end
29
+
30
+ def hoptoad_filter_if_filtering(hash)
31
+ if respond_to?(:filter_parameters)
32
+ filter_parameters(hash) rescue hash
33
+ else
34
+ hash
35
+ end
36
+ end
37
+
38
+ def hoptoad_session_data
39
+ if session.respond_to?(:to_hash)
40
+ session.to_hash
41
+ else
42
+ session.data
43
+ end
44
+ end
45
+
46
+ def hoptoad_request_url
47
+ url = "#{request.protocol}#{request.host}"
48
+
49
+ unless [80, 443].include?(request.port)
50
+ url << ":#{request.port}"
51
+ end
52
+
53
+ url << request.request_uri
54
+ url
55
+ end
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,33 @@
1
+ module HoptoadNotifier
2
+ module Rails
3
+ module ErrorLookup
4
+
5
+ # Sets up an alias chain to catch exceptions when Rails does
6
+ def self.included(base) #:nodoc:
7
+ base.send(:alias_method, :rescue_action_locally_without_hoptoad, :rescue_action_locally)
8
+ base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_hoptoad)
9
+ end
10
+
11
+ private
12
+
13
+ def rescue_action_locally_with_hoptoad(exception)
14
+ result = rescue_action_locally_without_hoptoad(exception)
15
+
16
+ if HoptoadNotifier.configuration.development_lookup
17
+ path = File.join(File.dirname(__FILE__), '..', '..', 'templates', 'rescue.erb')
18
+ notice = HoptoadNotifier.build_lookup_hash_for(exception, hoptoad_request_data)
19
+
20
+ result << @template.render(
21
+ :file => path,
22
+ :use_full_path => false,
23
+ :locals => { :host => HoptoadNotifier.configuration.host,
24
+ :api_key => HoptoadNotifier.configuration.api_key,
25
+ :notice => notice })
26
+ end
27
+
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -21,10 +21,8 @@ namespace :hoptoad do
21
21
  RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
22
22
 
23
23
  require 'action_controller/test_process'
24
- require 'app/controllers/application' if File.exists?('app/controllers/application.rb')
25
24
 
26
- request = ActionController::TestRequest.new
27
- response = ActionController::TestResponse.new
25
+ Dir["app/controllers/application*.rb"].each { |file| require(file) }
28
26
 
29
27
  class HoptoadTestingException < RuntimeError; end
30
28
 
@@ -35,10 +33,11 @@ namespace :hoptoad do
35
33
 
36
34
  HoptoadNotifier.configuration.development_environments = []
37
35
 
38
- in_controller = ApplicationController.included_modules.include? HoptoadNotifier::Catcher
39
- in_base = ActionController::Base.included_modules.include? HoptoadNotifier::Catcher
36
+ catcher = HoptoadNotifier::Rails::ActionControllerCatcher
37
+ in_controller = ApplicationController.included_modules.include?(catcher)
38
+ in_base = ActionController::Base.included_modules.include?(catcher)
40
39
  if !in_controller || !in_base
41
- puts "HoptoadNotifier::Catcher must be included inside your ApplicationController class."
40
+ puts "Rails initialization did not occur"
42
41
  exit
43
42
  end
44
43
 
@@ -47,6 +46,11 @@ namespace :hoptoad do
47
46
  puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
48
47
  end
49
48
 
49
+ unless defined?(ApplicationController)
50
+ puts "No ApplicationController found"
51
+ exit
52
+ end
53
+
50
54
  puts 'Setting up the Controller.'
51
55
  class ApplicationController
52
56
  # This is to bypass any filters that may prevent access to the action.
@@ -56,7 +60,7 @@ namespace :hoptoad do
56
60
  raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
57
61
  end
58
62
 
59
- def rescue_action exception
63
+ def rescue_action(exception)
60
64
  rescue_action_in_public exception
61
65
  end
62
66
 
@@ -82,9 +86,11 @@ namespace :hoptoad do
82
86
  nil
83
87
  end
84
88
  end
89
+ class HoptoadVerificationController < ApplicationController; end
85
90
 
86
91
  puts 'Processing request.'
87
- class HoptoadVerificationController < ApplicationController; end
92
+ request = ActionController::TestRequest.new
93
+ response = ActionController::TestResponse.new
88
94
  HoptoadVerificationController.new.process(request, response)
89
95
  end
90
96
  end
@@ -1,3 +1,3 @@
1
1
  module HoptoadNotifier
2
- VERSION = "2.1.3".freeze
2
+ VERSION = "2.2.0".freeze
3
3
  end
data/test/catcher_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- class CatcherTest < Test::Unit::TestCase
3
+ class ActionControllerCatcherTest < Test::Unit::TestCase
4
4
 
5
5
  include DefinesConstants
6
6
 
@@ -17,7 +17,7 @@ class CatcherTest < Test::Unit::TestCase
17
17
 
18
18
  def build_controller_class(&definition)
19
19
  returning Class.new(ActionController::Base) do |klass|
20
- klass.__send__(:include, HoptoadNotifier::Catcher)
20
+ klass.__send__(:include, HoptoadNotifier::Rails::ActionControllerCatcher)
21
21
  klass.class_eval(&definition) if definition
22
22
  define_constant('HoptoadTestController', klass)
23
23
  end
@@ -29,13 +29,23 @@ class CatcherTest < Test::Unit::TestCase
29
29
  if value.respond_to?(:to_hash)
30
30
  assert_sent_hash value.to_hash, element_xpath
31
31
  else
32
- assert_sent_element value.to_s, element_xpath
32
+ assert_sent_element value, element_xpath
33
33
  end
34
34
  end
35
35
  end
36
36
 
37
37
  def assert_sent_element(value, xpath)
38
- assert_valid_node last_sent_notice_document, xpath, value
38
+ assert_valid_node last_sent_notice_document, xpath, stringify_array_elements(value).to_s
39
+ end
40
+
41
+ def stringify_array_elements(data)
42
+ if data.respond_to?(:to_ary)
43
+ data.collect do |value|
44
+ stringify_array_elements(value)
45
+ end
46
+ else
47
+ data.to_s
48
+ end
39
49
  end
40
50
 
41
51
  def assert_sent_request_info_for(request)
@@ -172,7 +182,7 @@ class CatcherTest < Test::Unit::TestCase
172
182
 
173
183
  should "not create actions from Hoptoad methods" do
174
184
  controller = build_controller_class.new
175
- assert_equal [], HoptoadNotifier::Catcher.instance_methods
185
+ assert_equal [], HoptoadNotifier::Rails::ActionControllerCatcher.instance_methods
176
186
  end
177
187
 
178
188
  should "ignore exceptions when user agent is being ignored by regular expression" do
@@ -28,6 +28,7 @@ class ConfigurationTest < Test::Unit::TestCase
28
28
  assert_config_default :ignore,
29
29
  HoptoadNotifier::Configuration::IGNORE_DEFAULT
30
30
  assert_config_default :development_lookup, true
31
+ assert_config_default :framework, 'Standalone'
31
32
  end
32
33
 
33
34
  should "provide default values for secure connections" do
data/test/helper.rb CHANGED
@@ -3,10 +3,12 @@ require 'rubygems'
3
3
 
4
4
  gem 'jferris-mocha', '>= 0.9.5.0.1241126838'
5
5
 
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. vendor ginger lib])
7
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
8
+
6
9
  require 'shoulda'
7
10
  require 'mocha'
8
11
 
9
- $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. vendor ginger lib])
10
12
  require 'ginger'
11
13
 
12
14
  require 'action_controller'
@@ -15,8 +17,9 @@ require 'active_record'
15
17
  require 'active_record/base'
16
18
  require 'active_support'
17
19
  require 'nokogiri'
20
+ require 'rack'
18
21
 
19
- require File.join(File.dirname(__FILE__), "..", "lib", "hoptoad_notifier")
22
+ require "hoptoad_notifier"
20
23
 
21
24
  begin require 'redgreen'; rescue LoadError; end
22
25
 
@@ -234,4 +237,3 @@ class FakeLogger
234
237
  def fatal(*args); end
235
238
  end
236
239
 
237
- RAILS_DEFAULT_LOGGER = FakeLogger.new
data/test/notice_test.rb CHANGED
@@ -143,7 +143,7 @@ class NoticeTest < Test::Unit::TestCase
143
143
  end
144
144
 
145
145
  should "use the caller as the backtrace for an exception without a backtrace" do
146
- filters = HoptoadNotifier.configuration.backtrace_filters
146
+ filters = HoptoadNotifier::Configuration.new.backtrace_filters
147
147
  backtrace = HoptoadNotifier::Backtrace.parse(caller, :filters => filters)
148
148
  notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
149
149
 
@@ -338,6 +338,21 @@ class NoticeTest < Test::Unit::TestCase
338
338
  end
339
339
  end
340
340
 
341
+ should "extract data from a rack environment hash" do
342
+ # TODO: extract session data
343
+ # TODO: extract controller
344
+ # TODO: extract action
345
+ url = "https://subdomain.happylane.com:100/test/file.rb?var=value&var2=value2"
346
+ parameters = { 'var' => 'value', 'var2' => 'value2' }
347
+ env = Rack::MockRequest.env_for(url)
348
+
349
+ notice = build_notice(:rack_env => env)
350
+
351
+ assert_equal url, notice.url
352
+ assert_equal parameters, notice.parameters
353
+ assert_equal 'GET', notice.cgi_data['REQUEST_METHOD']
354
+ end
355
+
341
356
  def assert_accepts_exception_attribute(attribute, args = {}, &block)
342
357
  exception = build_exception
343
358
  block ||= lambda { exception.send(attribute) }
data/test/rack_test.rb ADDED
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class RackTest < Test::Unit::TestCase
4
+
5
+ should "call the upstream app with the environment" do
6
+ environment = { 'key' => 'value' }
7
+ app = lambda { |env| ['response', {}, env] }
8
+ stack = HoptoadNotifier::Rack.new(app)
9
+
10
+ response = stack.call(environment)
11
+
12
+ assert_equal ['response', {}, environment], response
13
+ end
14
+
15
+ should "deliver an exception raised while calling an upstream app" do
16
+ HoptoadNotifier.stubs(:notify_or_ignore)
17
+
18
+ exception = build_exception
19
+ environment = { 'key' => 'value' }
20
+ app = lambda do |env|
21
+ raise exception
22
+ end
23
+
24
+ begin
25
+ stack = HoptoadNotifier::Rack.new(app)
26
+ stack.call(environment)
27
+ rescue Exception => raised
28
+ assert_equal exception, raised
29
+ else
30
+ flunk "Didn't raise an exception"
31
+ end
32
+
33
+ assert_received(HoptoadNotifier, :notify_or_ignore) do |expect|
34
+ expect.with(exception, :rack_env => environment)
35
+ end
36
+ end
37
+
38
+ should "deliver an exception in rack.exception" do
39
+ HoptoadNotifier.stubs(:notify_or_ignore)
40
+ exception = build_exception
41
+ environment = { 'key' => 'value' }
42
+
43
+ response = [200, {}, ['okay']]
44
+ app = lambda do |env|
45
+ env['rack.exception'] = exception
46
+ response
47
+ end
48
+ stack = HoptoadNotifier::Rack.new(app)
49
+
50
+ actual_response = stack.call(environment)
51
+
52
+ assert_equal response, actual_response
53
+ assert_received(HoptoadNotifier, :notify_or_ignore) do |expect|
54
+ expect.with(exception, :rack_env => environment)
55
+ end
56
+ end
57
+
58
+ end
@@ -1,5 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
- require File.join(File.dirname(__FILE__), '..', 'lib', 'hoptoad_notifier', 'rails_initializer')
2
+
3
+ require 'hoptoad_notifier/rails'
3
4
 
4
5
  class RailsInitializerTest < Test::Unit::TestCase
5
6
  include DefinesConstants
@@ -11,20 +12,20 @@ class RailsInitializerTest < Test::Unit::TestCase
11
12
  end
12
13
  end
13
14
  define_constant("Rails", rails)
14
- HoptoadNotifier::RailsInitializer.initialize
15
+ HoptoadNotifier::Rails.initialize
15
16
  assert_equal "RAILS LOGGER", HoptoadNotifier.logger
16
17
  end
17
18
 
18
19
  should "trigger use of Rails' default logger if logger isn't set and Rails.logger doesn't exist" do
19
20
  define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
20
21
 
21
- HoptoadNotifier::RailsInitializer.initialize
22
+ HoptoadNotifier::Rails.initialize
22
23
  assert_equal "RAILS DEFAULT LOGGER", HoptoadNotifier.logger
23
24
  end
24
25
 
25
26
  should "allow overriding of the logger if already assigned" do
26
27
  define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
27
- HoptoadNotifier::RailsInitializer.initialize
28
+ HoptoadNotifier::Rails.initialize
28
29
 
29
30
  HoptoadNotifier.configure(true) do |config|
30
31
  config.logger = "OVERRIDDEN LOGGER"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hoptoad_notifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot, inc
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-27 00:00:00 -05:00
12
+ date: 2010-02-18 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -81,6 +81,7 @@ extensions: []
81
81
  extra_rdoc_files:
82
82
  - README.rdoc
83
83
  files:
84
+ - CHANGELOG
84
85
  - INSTALL
85
86
  - MIT-LICENSE
86
87
  - Rakefile
@@ -95,11 +96,13 @@ files:
95
96
  - generators/hoptoad/templates/initializer.rb
96
97
  - lib/hoptoad_notifier/backtrace.rb
97
98
  - lib/hoptoad_notifier/capistrano.rb
98
- - lib/hoptoad_notifier/catcher.rb
99
99
  - lib/hoptoad_notifier/configuration.rb
100
100
  - lib/hoptoad_notifier/notice.rb
101
+ - lib/hoptoad_notifier/rack.rb
102
+ - lib/hoptoad_notifier/rails/action_controller_catcher.rb
103
+ - lib/hoptoad_notifier/rails/controller_methods.rb
104
+ - lib/hoptoad_notifier/rails/error_lookup.rb
101
105
  - lib/hoptoad_notifier/rails.rb
102
- - lib/hoptoad_notifier/rails_initializer.rb
103
106
  - lib/hoptoad_notifier/sender.rb
104
107
  - lib/hoptoad_notifier/tasks.rb
105
108
  - lib/hoptoad_notifier/version.rb
@@ -113,6 +116,7 @@ files:
113
116
  - test/logger_test.rb
114
117
  - test/notice_test.rb
115
118
  - test/notifier_test.rb
119
+ - test/rack_test.rb
116
120
  - test/rails_initializer_test.rb
117
121
  - test/sender_test.rb
118
122
  - rails/init.rb
@@ -156,5 +160,6 @@ test_files:
156
160
  - test/logger_test.rb
157
161
  - test/notice_test.rb
158
162
  - test/notifier_test.rb
163
+ - test/rack_test.rb
159
164
  - test/rails_initializer_test.rb
160
165
  - test/sender_test.rb
@@ -1,95 +0,0 @@
1
- module HoptoadNotifier
2
- # Include this module in Controllers in which you want to be notified of errors.
3
- module Catcher
4
-
5
- # Sets up an alias chain to catch exceptions when Rails does
6
- def self.included(base) #:nodoc:
7
- 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_hoptoad'
8
- base.send(:alias_method, :rescue_action_in_public_without_hoptoad, :rescue_action_in_public)
9
- base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_hoptoad)
10
- base.send(:alias_method, :rescue_action_locally_without_hoptoad, :rescue_action_locally)
11
- base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_hoptoad)
12
- end
13
- end
14
-
15
- private
16
-
17
- # Overrides the rescue_action method in ActionController::Base, but does not inhibit
18
- # any custom processing that is defined with Rails 2's exception helpers.
19
- def rescue_action_in_public_with_hoptoad(exception)
20
- unless hoptoad_ignore_user_agent?
21
- HoptoadNotifier.notify_or_ignore(exception, hoptoad_request_data)
22
- end
23
- rescue_action_in_public_without_hoptoad(exception)
24
- end
25
-
26
- def rescue_action_locally_with_hoptoad(exception)
27
- result = rescue_action_locally_without_hoptoad(exception)
28
-
29
- if HoptoadNotifier.configuration.development_lookup
30
- path = File.join(File.dirname(__FILE__), '..', 'templates', 'rescue.erb')
31
- notice = HoptoadNotifier.build_lookup_hash_for(exception, hoptoad_request_data)
32
-
33
- result << @template.render(
34
- :file => path,
35
- :use_full_path => false,
36
- :locals => { :host => HoptoadNotifier.configuration.host,
37
- :api_key => HoptoadNotifier.configuration.api_key,
38
- :notice => notice })
39
- end
40
-
41
- result
42
- end
43
-
44
- # This method should be used for sending manual notifications while you are still
45
- # inside the controller. Otherwise it works like HoptoadNotifier.notify.
46
- def notify_hoptoad(hash_or_exception)
47
- unless consider_all_requests_local || local_request?
48
- HoptoadNotifier.notify(hash_or_exception, hoptoad_request_data)
49
- end
50
- end
51
-
52
- def hoptoad_ignore_user_agent? #:nodoc:
53
- # Rails 1.2.6 doesn't have request.user_agent, so check for it here
54
- user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
55
- HoptoadNotifier.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
56
- end
57
-
58
- def hoptoad_request_data
59
- { :parameters => hoptoad_filter_if_filtering(params.to_hash),
60
- :session_data => hoptoad_session_data,
61
- :controller => params[:controller],
62
- :action => params[:action],
63
- :url => hoptoad_request_url,
64
- :cgi_data => hoptoad_filter_if_filtering(request.env),
65
- :environment_vars => hoptoad_filter_if_filtering(ENV) }
66
- end
67
-
68
- def hoptoad_filter_if_filtering(hash)
69
- if respond_to?(:filter_parameters)
70
- filter_parameters(hash) rescue hash
71
- else
72
- hash
73
- end
74
- end
75
-
76
- def hoptoad_session_data
77
- if session.respond_to?(:to_hash)
78
- session.to_hash
79
- else
80
- session.data
81
- end
82
- end
83
-
84
- def hoptoad_request_url
85
- url = "#{request.protocol}#{request.host}"
86
-
87
- unless [80, 443].include?(request.port)
88
- url << ":#{request.port}"
89
- end
90
-
91
- url << request.request_uri
92
- url
93
- end
94
- end
95
- end
@@ -1,16 +0,0 @@
1
- module HoptoadNotifier
2
- # used to initialize Rails-specific code
3
- class RailsInitializer
4
- def self.initialize
5
- rails_logger = if defined?(Rails.logger)
6
- Rails.logger
7
- elsif defined?(RAILS_DEFAULT_LOGGER)
8
- RAILS_DEFAULT_LOGGER
9
- end
10
-
11
- HoptoadNotifier.configure(true) do |config|
12
- config.logger = rails_logger if config.respond_to? :logger
13
- end
14
- end
15
- end
16
- end