Commit 8bf98094f5b7cd7538e04e49082497c0bf64a895

Authored by Dhruv Kapadia
1 parent 9f0ec712

Updating hoptoad

Showing 44 changed files with 4344 additions and 0 deletions   Show diff stats
config/initializers/hoptoad.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +HoptoadNotifier.configure do |config|
  2 + config.api_key = 'eb60e75f67c9a67558ec90b25e75dfaa'
  3 +end
... ...
lib/tasks/hoptoad_notifier_tasks.rake 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +# Don't load anything when running the gems:* tasks.
  2 +# Otherwise, hoptoad_notifier will be considered a framework gem.
  3 +# https://thoughtbot.lighthouseapp.com/projects/14221/tickets/629
  4 +unless ARGV.any? {|a| a =~ /^gems/}
  5 +
  6 + Dir[File.join(RAILS_ROOT, 'vendor', 'gems', 'hoptoad_notifier-*')].each do |vendored_notifier|
  7 + $: << File.join(vendored_notifier, 'lib')
  8 + end
  9 +
  10 + require 'hoptoad_notifier/tasks'
  11 +
  12 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/.specification 0 → 100644
... ... @@ -0,0 +1,184 @@
  1 +--- !ruby/object:Gem::Specification
  2 +name: hoptoad_notifier
  3 +version: !ruby/object:Gem::Version
  4 + prerelease: false
  5 + segments:
  6 + - 2
  7 + - 2
  8 + - 2
  9 + version: 2.2.2
  10 +platform: ruby
  11 +authors:
  12 +- thoughtbot, inc
  13 +autorequire:
  14 +bindir: bin
  15 +cert_chain: []
  16 +
  17 +date: 2010-03-10 00:00:00 -05:00
  18 +default_executable:
  19 +dependencies:
  20 +- !ruby/object:Gem::Dependency
  21 + name: activesupport
  22 + prerelease: false
  23 + requirement: &id001 !ruby/object:Gem::Requirement
  24 + requirements:
  25 + - - ">="
  26 + - !ruby/object:Gem::Version
  27 + segments:
  28 + - 0
  29 + version: "0"
  30 + type: :runtime
  31 + version_requirements: *id001
  32 +- !ruby/object:Gem::Dependency
  33 + name: activerecord
  34 + prerelease: false
  35 + requirement: &id002 !ruby/object:Gem::Requirement
  36 + requirements:
  37 + - - ">="
  38 + - !ruby/object:Gem::Version
  39 + segments:
  40 + - 0
  41 + version: "0"
  42 + type: :development
  43 + version_requirements: *id002
  44 +- !ruby/object:Gem::Dependency
  45 + name: actionpack
  46 + prerelease: false
  47 + requirement: &id003 !ruby/object:Gem::Requirement
  48 + requirements:
  49 + - - ">="
  50 + - !ruby/object:Gem::Version
  51 + segments:
  52 + - 0
  53 + version: "0"
  54 + type: :development
  55 + version_requirements: *id003
  56 +- !ruby/object:Gem::Dependency
  57 + name: jferris-mocha
  58 + prerelease: false
  59 + requirement: &id004 !ruby/object:Gem::Requirement
  60 + requirements:
  61 + - - ">="
  62 + - !ruby/object:Gem::Version
  63 + segments:
  64 + - 0
  65 + version: "0"
  66 + type: :development
  67 + version_requirements: *id004
  68 +- !ruby/object:Gem::Dependency
  69 + name: nokogiri
  70 + prerelease: false
  71 + requirement: &id005 !ruby/object:Gem::Requirement
  72 + requirements:
  73 + - - ">="
  74 + - !ruby/object:Gem::Version
  75 + segments:
  76 + - 0
  77 + version: "0"
  78 + type: :development
  79 + version_requirements: *id005
  80 +- !ruby/object:Gem::Dependency
  81 + name: shoulda
  82 + prerelease: false
  83 + requirement: &id006 !ruby/object:Gem::Requirement
  84 + requirements:
  85 + - - ">="
  86 + - !ruby/object:Gem::Version
  87 + segments:
  88 + - 0
  89 + version: "0"
  90 + type: :development
  91 + version_requirements: *id006
  92 +description:
  93 +email: support@hoptoadapp.com
  94 +executables: []
  95 +
  96 +extensions: []
  97 +
  98 +extra_rdoc_files:
  99 +- README.rdoc
  100 +files:
  101 +- CHANGELOG
  102 +- INSTALL
  103 +- MIT-LICENSE
  104 +- Rakefile
  105 +- README.rdoc
  106 +- SUPPORTED_RAILS_VERSIONS
  107 +- TESTING.rdoc
  108 +- generators/hoptoad/hoptoad_generator.rb
  109 +- generators/hoptoad/lib/insert_commands.rb
  110 +- generators/hoptoad/lib/rake_commands.rb
  111 +- generators/hoptoad/templates/capistrano_hook.rb
  112 +- generators/hoptoad/templates/hoptoad_notifier_tasks.rake
  113 +- generators/hoptoad/templates/initializer.rb
  114 +- lib/hoptoad_notifier/backtrace.rb
  115 +- lib/hoptoad_notifier/capistrano.rb
  116 +- lib/hoptoad_notifier/configuration.rb
  117 +- lib/hoptoad_notifier/notice.rb
  118 +- lib/hoptoad_notifier/rack.rb
  119 +- lib/hoptoad_notifier/rails/action_controller_catcher.rb
  120 +- lib/hoptoad_notifier/rails/controller_methods.rb
  121 +- lib/hoptoad_notifier/rails/error_lookup.rb
  122 +- lib/hoptoad_notifier/rails.rb
  123 +- lib/hoptoad_notifier/sender.rb
  124 +- lib/hoptoad_notifier/tasks.rb
  125 +- lib/hoptoad_notifier/version.rb
  126 +- lib/hoptoad_notifier.rb
  127 +- lib/hoptoad_tasks.rb
  128 +- test/backtrace_test.rb
  129 +- test/catcher_test.rb
  130 +- test/configuration_test.rb
  131 +- test/helper.rb
  132 +- test/hoptoad_tasks_test.rb
  133 +- test/logger_test.rb
  134 +- test/notice_test.rb
  135 +- test/notifier_test.rb
  136 +- test/rack_test.rb
  137 +- test/rails_initializer_test.rb
  138 +- test/sender_test.rb
  139 +- rails/init.rb
  140 +- script/integration_test.rb
  141 +- lib/templates/rescue.erb
  142 +has_rdoc: true
  143 +homepage: http://www.hoptoadapp.com
  144 +licenses: []
  145 +
  146 +post_install_message:
  147 +rdoc_options:
  148 +- --line-numbers
  149 +- --main
  150 +- README.rdoc
  151 +require_paths:
  152 +- lib
  153 +required_ruby_version: !ruby/object:Gem::Requirement
  154 + requirements:
  155 + - - ">="
  156 + - !ruby/object:Gem::Version
  157 + segments:
  158 + - 0
  159 + version: "0"
  160 +required_rubygems_version: !ruby/object:Gem::Requirement
  161 + requirements:
  162 + - - ">="
  163 + - !ruby/object:Gem::Version
  164 + segments:
  165 + - 0
  166 + version: "0"
  167 +requirements: []
  168 +
  169 +rubyforge_project:
  170 +rubygems_version: 1.3.6
  171 +signing_key:
  172 +specification_version: 3
  173 +summary: Send your application errors to our hosted service and reclaim your inbox.
  174 +test_files:
  175 +- test/backtrace_test.rb
  176 +- test/catcher_test.rb
  177 +- test/configuration_test.rb
  178 +- test/hoptoad_tasks_test.rb
  179 +- test/logger_test.rb
  180 +- test/notice_test.rb
  181 +- test/notifier_test.rb
  182 +- test/rack_test.rb
  183 +- test/rails_initializer_test.rb
  184 +- test/sender_test.rb
... ...
vendor/gems/hoptoad_notifier-2.2.2/CHANGELOG 0 → 100644
... ... @@ -0,0 +1,75 @@
  1 +Version 2.2.2 - 2010-03-10
  2 +===============================================================================
  3 +
  4 +Chad Pytel (1):
  5 + document proxy support
  6 +
  7 +Joe Ferris (8):
  8 + Added upgrade instructions to the README
  9 + Give a clearer error message when generating a Rails app fails
  10 + Fail loudly when a gem can't be vendored
  11 + Debugging rubygems issues
  12 + Explicitly specify the gem paths
  13 + Less noisy
  14 + Restore gem path after vendoring
  15 + Fixed a typo
  16 +
  17 +Jon Yurek (1):
  18 + Added notice about removing hoptoad rake tasks to upgrade gem
  19 +
  20 +Mike Burns (1):
  21 + Remove stray file with notes in it
  22 +
  23 +
  24 +Version 2.2.1 - 2010-03-10
  25 +===============================================================================
  26 +
  27 +Jason Morrison (3):
  28 + LH-629 Ensure notifier is not considered a framework gem
  29 + Removing things-the-generator-must-do file
  30 + Add rake cucumber:wip:rails* tasks for work-in-progress features
  31 +
  32 +
  33 +Version 2.2.0 - 2010-02-18
  34 +===============================================================================
  35 +
  36 +Bumping the version from 2.1.4 to 2.2.0 since adding Rack support warrants a minor version.
  37 +
  38 +Jason Morrison (1):
  39 + Stringify array elements when making assertions about Notice XML for 1.9 compatibility
  40 +
  41 +
  42 +Version 2.1.4 - 2010-02-12
  43 +===============================================================================
  44 +
  45 +Chad Pytel (2):
  46 + add more info to README for 1.2.6
  47 + fix gem unpack line for 1.2.6
  48 +
  49 +Jason Morrison (2):
  50 + Adding additional instructions for Rails 1.2.6
  51 + Typesetting in README.rdoc
  52 +
  53 +Joe Ferris (11):
  54 + Separating Rails functionality out more
  55 + Initial Rack middleware
  56 + Extract request info from rack env
  57 + Added integration tests for rescuing
  58 + Fixed reporting of Rails version
  59 + Small refactoring
  60 + Automatically add Rack middleware for Rails apps that support it (catches exceptions from Metal)
  61 + Added an integration test and docs for rack apps
  62 + Added integration/readme coverage of Sinatra apps
  63 + Added docs to HoptoadNotifier::Rack
  64 + Require rack in tests for older versions of Rails; use active_support instead of activesupport
  65 +
  66 +Nick Quaranto (3):
  67 + Fixing the capistrano hook bit in the readme
  68 + Adding changeling:minor and changeling:patch to automate notifier releases
  69 + Adding rake changeling:push
  70 +
  71 +
  72 +
  73 +
  74 +
  75 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/INSTALL 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +=== Configuration
  2 +
  3 +You should have something like this in config/initializers/hoptoad.rb.
  4 +
  5 + HoptoadNotifier.configure do |config|
  6 + config.api_key = '1234567890abcdef'
  7 + end
  8 +
  9 +(Please note that this configuration should be in a global configuration, and
  10 +is *not* environment-specific. Hoptoad is smart enough to know what errors are
  11 +caused by what environments, so your staging errors don't get mixed in with
  12 +your production errors.)
  13 +
  14 +You can test that Hoptoad is working in your production environment by using
  15 +this rake task (from RAILS_ROOT):
  16 +
  17 + rake hoptoad:test
  18 +
  19 +If everything is configured properly, that task will send a notice to Hoptoad
  20 +which will be visible immediately.
  21 +
  22 +NOTE FOR RAILS 1.2.* USERS:
  23 +
  24 +You will need to copy the hoptoad_notifier_tasks.rake file into your
  25 +RAILS_ROOT/lib/tasks directory in order for the rake hoptoad:test task to work.
... ...
vendor/gems/hoptoad_notifier-2.2.2/MIT-LICENSE 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +Copyright (c) 2007, Tammer Saleh, Thoughtbot, Inc.
  2 +
  3 +Permission is hereby granted, free of charge, to any person
  4 +obtaining a copy of this software and associated documentation
  5 +files (the "Software"), to deal in the Software without
  6 +restriction, including without limitation the rights to use,
  7 +copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 +copies of the Software, and to permit persons to whom the
  9 +Software is furnished to do so, subject to the following
  10 +conditions:
  11 +
  12 +The above copyright notice and this permission notice shall be
  13 +included in all copies or substantial portions of the Software.
  14 +
  15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17 +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19 +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20 +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22 +OTHER DEALINGS IN THE SOFTWARE.
... ...
vendor/gems/hoptoad_notifier-2.2.2/README.rdoc 0 → 100644
... ... @@ -0,0 +1,356 @@
  1 += HoptoadNotifier
  2 +
  3 +This is the notifier gem for integrating apps with Hoptoad.
  4 +
  5 +When an uncaught exception occurs, HoptoadNotifier will POST the relevant data
  6 +to the Hoptoad server specified in your environment.
  7 +
  8 +== Help
  9 +
  10 +* {IRC}[irc://irc.freenode.net/thoughtbot]
  11 +* {mailing list}[http://groups.google.com/group/hoptoad-notifier-dev]
  12 +
  13 +== Rails Installation
  14 +
  15 +=== Remove exception_notifier
  16 +
  17 +in your ApplicationController, REMOVE this line:
  18 +
  19 + include ExceptionNotifiable
  20 +
  21 +In your config/environment* files, remove all references to ExceptionNotifier
  22 +
  23 +Remove the vendor/plugins/exception_notifier directory.
  24 +
  25 +=== Remove hoptoad_notifier plugin
  26 +
  27 +Remove the vendor/plugins/hoptoad_notifier directory before installing the gem, or run:
  28 +
  29 + script/plugin remove hoptoad_notifier
  30 +
  31 +=== Rails 2.x
  32 +
  33 +Add the hoptoad_notifier gem to your app. In config/environment.rb:
  34 +
  35 + config.gem 'hoptoad_notifier'
  36 +
  37 +Then from your project's RAILS_ROOT, run:
  38 +
  39 + rake gems:install
  40 + script/generate hoptoad --api-key your_key_here
  41 +
  42 +Once installed, you should vendor the hoptoad_notifier gem.
  43 +
  44 + rake gems:unpack GEM=hoptoad_notifier
  45 +
  46 +As always, if you choose not to vendor the hoptoad_notifier gem, make sure
  47 +every server you deploy to has the gem installed or your application won't start.
  48 +
  49 +=== Rails 1.2.6
  50 +
  51 +Install the hoptoad_notifier gem:
  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'
  71 + HoptoadNotifier.configure do |config|
  72 + config.api_key = 'your_key_here'
  73 + end
  74 +
  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-*/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.
  82 +
  83 +=== Upgrading From Earlier Versions of Hoptoad
  84 +
  85 +If you're currently using the plugin version (if you have a
  86 +vendor/plugins/hoptoad_notifier directory, you are), you'll need to perform a
  87 +few extra steps when upgrading to the gem version.
  88 +
  89 +Add the hoptoad_notifier gem to your app. In config/environment.rb:
  90 +
  91 + config.gem 'hoptoad_notifier'
  92 +
  93 +Remove the plugin:
  94 +
  95 + rm -rf vendor/plugins/hoptoad_notifier
  96 +
  97 +Before running the hoptoad generator, you need to find your project's API key.
  98 +Log in to your account at hoptoadapp.com, and click on the "Projects" button.
  99 +Then, find your project in the list, and click on its name. In the left-hand
  100 +column, you'll see an "Edit this project" button. Click on that to get your
  101 +project's API. (If you accidentally use your personal API auth_token, you won't
  102 +be able to install the gem.)
  103 +
  104 +Then from your project's RAILS_ROOT, run:
  105 +
  106 + rake gems:install
  107 + script/generate hoptoad --api-key your_key_here
  108 +
  109 +Once installed, you should vendor the hoptoad_notifier gem.
  110 +
  111 + rake gems:unpack GEM=hoptoad_notifier
  112 +
  113 +As always, if you choose not to vendor the hoptoad_notifier gem, make sure
  114 +every server you deploy to has the gem installed or your application won't
  115 +start.
  116 +
  117 +== Upgrading from Earlier Versions of the Hoptoad Gem (with config.gem)
  118 +
  119 +If you're currently using the gem version of the hoptoad_notifier and have
  120 +a version of Rails that uses config.gem (in the 2.x series), there is
  121 +a step or two that you need to do to upgrade. First, you need to remove
  122 +the old version of the gem from vendor/gems:
  123 +
  124 + rm -rf vendor/gems/hoptoad_notifier-X.X.X
  125 +
  126 +Then you must remove the hoptoad_notifier_tasks.rake file from lib:
  127 +
  128 + rm lib/tasks/hoptoad_notifier_tasks.rake
  129 +
  130 +You can them continue to install normally. If you don't remove the rake file,
  131 +you will be unable to unpack this gem (Rails will think it's part of the
  132 +framework).
  133 +
  134 +=== Testing it out
  135 +
  136 +You can test that Hoptoad is working in your production environment by using
  137 +this rake task (from RAILS_ROOT):
  138 +
  139 + rake hoptoad:test
  140 +
  141 +If everything is configured properly, that task will send a notice to Hoptoad
  142 +which will be visible immediately.
  143 +
  144 +== Rack
  145 +
  146 +In order to use hoptoad_notifier in a non-Rails rack app, just load the
  147 +hoptoad_notifier, configure your API key, and use the HoptoadNotifier::Rack
  148 +middleware:
  149 +
  150 + require 'rack'
  151 + require 'hoptoad_notifier'
  152 +
  153 + HoptoadNotifier.configure do |config|
  154 + config.api_key = 'my_api_key'
  155 + end
  156 +
  157 + app = Rack::Builder.app do
  158 + use HoptoadNotifier::Rack
  159 + run lambda { |env| raise "Rack down" }
  160 + end
  161 +
  162 +== Sinatra
  163 +
  164 +Using hoptoad_notifier in a Sinatra app is just like a Rack app, but you have
  165 +to disable Sinatra's error rescuing functionality:
  166 +
  167 + require 'sinatra/base'
  168 + require 'hoptoad_notifier'
  169 +
  170 + HoptoadNotifier.configure do |config|
  171 + config.api_key = 'my_api_key'
  172 + end
  173 +
  174 + class MyApp < Sinatra::Default
  175 + use HoptoadNotifier::Rack
  176 + enable :raise_errors
  177 +
  178 + get "/" do
  179 + raise "Sinatra has left the building"
  180 + end
  181 + end
  182 +
  183 +== Usage
  184 +
  185 +For the most part, Hoptoad works for itself. Once you've included the notifier
  186 +in your ApplicationController (which is now done automatically by the gem),
  187 +all errors will be rescued by the #rescue_action_in_public provided by the gem.
  188 +
  189 +If you want to log arbitrary things which you've rescued yourself from a
  190 +controller, you can do something like this:
  191 +
  192 + ...
  193 + rescue => ex
  194 + notify_hoptoad(ex)
  195 + flash[:failure] = 'Encryptions could not be rerouted, try again.'
  196 + end
  197 + ...
  198 +
  199 +The #notify_hoptoad call will send the notice over to Hoptoad for later
  200 +analysis. While in your controllers you use the notify_hoptoad method, anywhere
  201 +else in your code, use HoptoadNotifier.notify.
  202 +
  203 +To perform custom error processing after Hoptoad has been notified, define the
  204 +instance method #rescue_action_in_public_without_hoptoad(exception) in your
  205 +controller.
  206 +
  207 +== Tracking deployments in Hoptoad
  208 +
  209 +Paying Hoptoad plans support the ability to track deployments of your application in Hoptoad.
  210 +By notifying Hoptoad of your application deployments, all errors are resolved when a deploy occurs,
  211 +so that you'll be notified again about any errors that reoccur after a deployment.
  212 +
  213 +Additionally, it's possible to review the errors in Hoptoad that occurred before and after a deploy.
  214 +
  215 +When Hoptoad is installed as a gem, you need to add
  216 +
  217 + require 'hoptoad_notifier/capistrano'
  218 +
  219 +to your deploy.rb
  220 +
  221 +== Going beyond exceptions
  222 +
  223 +You can also pass a hash to notify_hoptoad method and store whatever you want,
  224 +not just an exception. And you can also use it anywhere, not just in
  225 +controllers:
  226 +
  227 + begin
  228 + params = {
  229 + # params that you pass to a method that can throw an exception
  230 + }
  231 + my_unpredicable_method(params)
  232 + rescue => e
  233 + HoptoadNotifier.notify(
  234 + :error_class => "Special Error",
  235 + :error_message => "Special Error: #{e.message}",
  236 + :parameters => params
  237 + )
  238 + end
  239 +
  240 +While in your controllers you use the notify_hoptoad method, anywhere else in
  241 +your code, use HoptoadNotifier.notify. Hoptoad will get all the information
  242 +about the error itself. As for a hash, these are the keys you should pass:
  243 +
  244 +* :error_class - Use this to group similar errors together. When Hoptoad catches an exception it sends the class name of that exception object.
  245 +* :error_message - This is the title of the error you see in the errors list. For exceptions it is "#{exception.class.name}: #{exception.message}"
  246 +* :parameters - While there are several ways to send additional data to Hoptoad, passing a Hash as :parameters as in the example above is the most common use case. When Hoptoad catches an exception in a controller, the actual HTTP client request parameters are sent using this key.
  247 +
  248 +Hoptoad merges the hash you pass with these default options:
  249 +
  250 + {
  251 + :api_key => HoptoadNotifier.api_key,
  252 + :error_message => 'Notification',
  253 + :backtrace => caller,
  254 + :parameters => {},
  255 + :session => {}
  256 + }
  257 +
  258 +You can override any of those parameters.
  259 +
  260 +== Filtering
  261 +
  262 +You can specify a whitelist of errors, that Hoptoad will not report on. Use
  263 +this feature when you are so apathetic to certain errors that you don't want
  264 +them even logged.
  265 +
  266 +This filter will only be applied to automatic notifications, not manual
  267 +notifications (when #notify is called directly).
  268 +
  269 +Hoptoad ignores the following exceptions by default:
  270 +
  271 + ActiveRecord::RecordNotFound
  272 + ActionController::RoutingError
  273 + ActionController::InvalidAuthenticityToken
  274 + ActionController::UnknownAction
  275 + CGI::Session::CookieStore::TamperedWithCookie
  276 +
  277 +To ignore errors in addition to those, specify their names in your Hoptoad
  278 +configuration block.
  279 +
  280 + HoptoadNotifier.configure do |config|
  281 + config.api_key = '1234567890abcdef'
  282 + config.ignore << ActiveRecord::IgnoreThisError
  283 + end
  284 +
  285 +To ignore *only* certain errors (and override the defaults), use the
  286 +#ignore_only attribute.
  287 +
  288 + HoptoadNotifier.configure do |config|
  289 + config.api_key = '1234567890abcdef'
  290 + config.ignore_only = [ActiveRecord::IgnoreThisError]
  291 + end
  292 +
  293 +To ignore certain user agents, add in the #ignore_user_agent attribute as a
  294 +string or regexp:
  295 +
  296 + HoptoadNotifier.configure do |config|
  297 + config.api_key = '1234567890abcdef'
  298 + config.ignore_user_agent << /Ignored/
  299 + config.ignore_user_agent << 'IgnoredUserAgent'
  300 + end
  301 +
  302 +To ignore exceptions based on other conditions, use #ignore_by_filter:
  303 +
  304 + HoptoadNotifier.configure do |config|
  305 + config.api_key = '1234567890abcdef'
  306 + config.ignore_by_filter do |exception_data|
  307 + true if exception_data[:error_class] == "RuntimeError"
  308 + end
  309 + end
  310 +
  311 +To replace sensitive information sent to the Hoptoad service with [FILTERED] use #params_filters:
  312 +
  313 + HoptoadNotifier.configure do |config|
  314 + config.api_key = '1234567890abcdef'
  315 + config.params_filters << "credit_card_number"
  316 + end
  317 +
  318 +Note that, when rescuing exceptions within an ActionController method,
  319 +hoptoad_notifier will reuse filters specified by #filter_params_logging.
  320 +
  321 +== Testing
  322 +
  323 +When you run your tests, you might notice that the Hoptoad service is recording
  324 +notices generated using #notify when you don't expect it to. You can
  325 +use code like this in your test_helper.rb to redefine that method so those
  326 +errors are not reported while running tests.
  327 +
  328 + module HoptoadNotifier
  329 + def self.notify(thing)
  330 + # do nothing.
  331 + end
  332 + end
  333 +
  334 +== Proxy Support
  335 +
  336 +The notifier supports using a proxy, if your server is not able to directly reach the Hoptoad servers. To configure the proxy settings, added the following information to your Hoptoad configuration block.
  337 +
  338 + HoptoadNotifier.configure do |config|
  339 + config.proxy_host = ...
  340 + config.proxy_port = ...
  341 + config.proxy_user = ...
  342 + config.proxy_pass = ...
  343 +
  344 +== Supported Rails versions
  345 +
  346 +See SUPPORTED_RAILS_VERSIONS for a list of official supported versions of
  347 +Rails.
  348 +
  349 +Please open up a support ticket on Tender ( http://help.hoptoadapp.com ) if
  350 +you're using a version of Rails that is not listed above and the notifier is
  351 +not working properly.
  352 +
  353 +== Thanks
  354 +
  355 +Thanks to Eugene Bolshakov for the excellent write-up on GOING BEYOND
  356 +EXCEPTIONS, which we have included above.
... ...
vendor/gems/hoptoad_notifier-2.2.2/Rakefile 0 → 100644
... ... @@ -0,0 +1,217 @@
  1 +require 'rake'
  2 +require 'rake/testtask'
  3 +require 'rake/rdoctask'
  4 +require 'rake/gempackagetask'
  5 +require 'cucumber/rake/task'
  6 +
  7 +desc 'Default: run unit tests.'
  8 +task :default => [:test, :cucumber]
  9 +
  10 +desc 'Test the hoptoad_notifier gem.'
  11 +Rake::TestTask.new(:test) do |t|
  12 + t.libs << 'lib'
  13 + t.pattern = 'test/**/*_test.rb'
  14 + t.verbose = true
  15 +end
  16 +
  17 +desc 'Run ginger tests'
  18 +task :ginger do
  19 + $LOAD_PATH << File.join(*%w[vendor ginger lib])
  20 + ARGV.clear
  21 + ARGV << 'test'
  22 + load File.join(*%w[vendor ginger bin ginger])
  23 +end
  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 +
  102 +begin
  103 + require 'yard'
  104 + YARD::Rake::YardocTask.new do |t|
  105 + t.files = ['lib/**/*.rb', 'TESTING.rdoc']
  106 + end
  107 +rescue LoadError
  108 +end
  109 +
  110 +GEM_ROOT = File.dirname(__FILE__).freeze
  111 +VERSION_FILE = File.join(GEM_ROOT, 'lib', 'hoptoad_notifier', 'version')
  112 +
  113 +require VERSION_FILE
  114 +
  115 +gemspec = Gem::Specification.new do |s|
  116 + s.name = %q{hoptoad_notifier}
  117 + s.version = HoptoadNotifier::VERSION
  118 + s.summary = %q{Send your application errors to our hosted service and reclaim your inbox.}
  119 +
  120 + s.files = FileList['[A-Z]*', 'generators/**/*.*', 'lib/**/*.rb',
  121 + 'test/**/*.rb', 'rails/**/*.rb', 'script/*',
  122 + 'lib/templates/*.erb']
  123 + s.require_path = 'lib'
  124 + s.test_files = Dir[*['test/**/*_test.rb']]
  125 +
  126 + s.has_rdoc = true
  127 + s.extra_rdoc_files = ["README.rdoc"]
  128 + s.rdoc_options = ['--line-numbers', "--main", "README.rdoc"]
  129 +
  130 + s.add_runtime_dependency("activesupport")
  131 + s.add_development_dependency("activerecord")
  132 + s.add_development_dependency("actionpack")
  133 + s.add_development_dependency("jferris-mocha")
  134 + s.add_development_dependency("nokogiri")
  135 + s.add_development_dependency("shoulda")
  136 +
  137 + s.authors = ["thoughtbot, inc"]
  138 + s.email = %q{support@hoptoadapp.com}
  139 + s.homepage = "http://www.hoptoadapp.com"
  140 +
  141 + s.platform = Gem::Platform::RUBY
  142 +end
  143 +
  144 +Rake::GemPackageTask.new gemspec do |pkg|
  145 + pkg.need_tar = true
  146 + pkg.need_zip = true
  147 +end
  148 +
  149 +desc "Clean files generated by rake tasks"
  150 +task :clobber => [:clobber_rdoc, :clobber_package]
  151 +
  152 +desc "Generate a gemspec file"
  153 +task :gemspec do
  154 + File.open("#{gemspec.name}.gemspec", 'w') do |f|
  155 + f.write gemspec.to_ruby
  156 + end
  157 +end
  158 +
  159 +LOCAL_GEM_ROOT = File.join(GEM_ROOT, 'tmp', 'local_gems').freeze
  160 +RAILS_VERSIONS = IO.read('SUPPORTED_RAILS_VERSIONS').strip.split("\n")
  161 +LOCAL_GEMS = [['sham_rack', nil], ['capistrano', nil], ['sqlite3-ruby', nil], ['sinatra', nil]] +
  162 + RAILS_VERSIONS.collect { |version| ['rails', version] }
  163 +
  164 +task :vendor_test_gems do
  165 + old_gem_path = ENV['GEM_PATH']
  166 + old_gem_home = ENV['GEM_HOME']
  167 + ENV['GEM_PATH'] = LOCAL_GEM_ROOT
  168 + ENV['GEM_HOME'] = LOCAL_GEM_ROOT
  169 + LOCAL_GEMS.each do |gem_name, version|
  170 + gem_file_pattern = [gem_name, version || '*'].compact.join('-')
  171 + version_option = version ? "-v #{version}" : ''
  172 + pattern = File.join(LOCAL_GEM_ROOT, 'gems', "#{gem_file_pattern}")
  173 + existing = Dir.glob(pattern).first
  174 + unless existing
  175 + command = "gem install -i #{LOCAL_GEM_ROOT} --no-ri --no-rdoc --backtrace #{version_option} #{gem_name}"
  176 + puts "Vendoring #{gem_file_pattern}..."
  177 + unless system("#{command} 2>&1")
  178 + puts "Command failed: #{command}"
  179 + exit(1)
  180 + end
  181 + end
  182 + end
  183 + ENV['GEM_PATH'] = old_gem_path
  184 + ENV['GEM_HOME'] = old_gem_home
  185 +end
  186 +
  187 +Cucumber::Rake::Task.new(:cucumber) do |t|
  188 + t.fork = true
  189 + t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
  190 +end
  191 +
  192 +task :cucumber => [:gemspec, :vendor_test_gems]
  193 +
  194 +def define_rails_cucumber_tasks(additional_cucumber_args = '')
  195 + namespace :rails do
  196 + RAILS_VERSIONS.each do |version|
  197 + desc "Test integration of the gem with Rails #{version}"
  198 + task version do
  199 + puts "Testing Rails #{version}"
  200 + ENV['RAILS_VERSION'] = version
  201 + system("cucumber --format progress #{additional_cucumber_args} features/rails.feature")
  202 + end
  203 + end
  204 +
  205 + desc "Test integration of the gem with all Rails versions"
  206 + task :all => RAILS_VERSIONS
  207 + end
  208 +end
  209 +
  210 +namespace :cucumber do
  211 + namespace :wip do
  212 + define_rails_cucumber_tasks('--tags @wip')
  213 + end
  214 +
  215 + define_rails_cucumber_tasks
  216 +end
  217 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/SUPPORTED_RAILS_VERSIONS 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +1.2.6
  2 +2.0.2
  3 +2.1.0
  4 +2.1.2
  5 +2.2.2
  6 +2.3.2
  7 +2.3.4
  8 +2.3.5
... ...
vendor/gems/hoptoad_notifier-2.2.2/TESTING.rdoc 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 += For Maintainers:
  2 +
  3 +When developing the Hoptoad Notifier, be sure to use the integration test
  4 +against an existing project on staging before pushing to master.
  5 +
  6 ++./script/integration_test.rb <test project's api key> <staging server hostname>+
  7 +
  8 ++./script/integration_test.rb <test project's api key> <staging server hostname> secure+
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/hoptoad_generator.rb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")
  2 +require File.expand_path(File.dirname(__FILE__) + "/lib/rake_commands.rb")
  3 +
  4 +class HoptoadGenerator < Rails::Generator::Base
  5 + def add_options!(opt)
  6 + opt.on('-k', '--api-key=key', String, "Your Hoptoad API key") {|v| options[:api_key] = v}
  7 + end
  8 +
  9 + def manifest
  10 + if !api_key_configured? && !options[:api_key]
  11 + puts "Must pass --api-key or create config/initializers/hoptoad.rb"
  12 + exit
  13 + end
  14 + if plugin_is_present?
  15 + puts "You must first remove the hoptoad_notifier plugin. Please run: script/plugin remove hoptoad_notifier"
  16 + exit
  17 + end
  18 + record do |m|
  19 + m.directory 'lib/tasks'
  20 + m.file 'hoptoad_notifier_tasks.rake', 'lib/tasks/hoptoad_notifier_tasks.rake'
  21 + if File.exists?('config/deploy.rb')
  22 + m.append_to 'config/deploy.rb', capistrano_hook
  23 + end
  24 + if options[:api_key]
  25 + if use_initializer?
  26 + m.template 'initializer.rb', 'config/initializers/hoptoad.rb',
  27 + :assigns => {:api_key => options[:api_key]}
  28 + else
  29 + m.template 'initializer.rb', 'config/hoptoad.rb',
  30 + :assigns => {:api_key => options[:api_key]}
  31 + m.append_to 'config/environment.rb', "require 'config/hoptoad'"
  32 + end
  33 + end
  34 + m.rake "hoptoad:test", :generate_only => true
  35 + end
  36 + end
  37 +
  38 + def use_initializer?
  39 + Rails::VERSION::MAJOR > 1
  40 + end
  41 +
  42 + def api_key_configured?
  43 + File.exists?('config/initializers/hoptoad.rb') ||
  44 + system("grep HoptoadNotifier config/environment.rb")
  45 + end
  46 +
  47 + def capistrano_hook
  48 + IO.read(source_path('capistrano_hook.rb'))
  49 + end
  50 +
  51 + def plugin_is_present?
  52 + File.exists?('vendor/plugins/hoptoad_notifier')
  53 + end
  54 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/lib/insert_commands.rb 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +# Mostly pinched from http://github.com/ryanb/nifty-generators/tree/master
  2 +
  3 +Rails::Generator::Commands::Base.class_eval do
  4 + def file_contains?(relative_destination, line)
  5 + File.read(destination_path(relative_destination)).include?(line)
  6 + end
  7 +end
  8 +
  9 +Rails::Generator::Commands::Create.class_eval do
  10 + def append_to(file, line)
  11 + logger.insert "#{line} appended to #{file}"
  12 + unless options[:pretend] || file_contains?(file, line)
  13 + File.open(file, "a") do |file|
  14 + file.puts
  15 + file.puts line
  16 + end
  17 + end
  18 + end
  19 +end
  20 +
  21 +Rails::Generator::Commands::Destroy.class_eval do
  22 + def append_to(file, line)
  23 + logger.remove "#{line} removed from #{file}"
  24 + unless options[:pretend]
  25 + gsub_file file, "\n#{line}", ''
  26 + end
  27 + end
  28 +end
  29 +
  30 +Rails::Generator::Commands::List.class_eval do
  31 + def append_to(file, line)
  32 + logger.insert "#{line} appended to #{file}"
  33 + end
  34 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/lib/rake_commands.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +Rails::Generator::Commands::Create.class_eval do
  2 + def rake(cmd, opts = {})
  3 + logger.rake "rake #{cmd}"
  4 + unless system("rake #{cmd}")
  5 + logger.rake "#{cmd} failed. Rolling back"
  6 + command(:destroy).invoke!
  7 + end
  8 + end
  9 +end
  10 +
  11 +Rails::Generator::Commands::Destroy.class_eval do
  12 + def rake(cmd, opts = {})
  13 + unless opts[:generate_only]
  14 + logger.rake "rake #{cmd}"
  15 + system "rake #{cmd}"
  16 + end
  17 + end
  18 +end
  19 +
  20 +Rails::Generator::Commands::List.class_eval do
  21 + def rake(cmd, opts = {})
  22 + logger.rake "rake #{cmd}"
  23 + end
  24 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/templates/capistrano_hook.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +
  2 +Dir[File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'hoptoad_notifier-*')].each do |vendored_notifier|
  3 + $: << File.join(vendored_notifier, 'lib')
  4 +end
  5 +
  6 +require 'hoptoad_notifier/capistrano'
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/templates/hoptoad_notifier_tasks.rake 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +# Don't load anything when running the gems:* tasks.
  2 +# Otherwise, hoptoad_notifier will be considered a framework gem.
  3 +# https://thoughtbot.lighthouseapp.com/projects/14221/tickets/629
  4 +unless ARGV.any? {|a| a =~ /^gems/}
  5 +
  6 + Dir[File.join(RAILS_ROOT, 'vendor', 'gems', 'hoptoad_notifier-*')].each do |vendored_notifier|
  7 + $: << File.join(vendored_notifier, 'lib')
  8 + end
  9 +
  10 + require 'hoptoad_notifier/tasks'
  11 +
  12 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/generators/hoptoad/templates/initializer.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +<% if Rails::VERSION::MINOR < 2 -%>
  2 +require 'hoptoad_notifier/rails'
  3 +<% end -%>
  4 +HoptoadNotifier.configure do |config|
  5 + config.api_key = '<%= api_key %>'
  6 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier.rb 0 → 100644
... ... @@ -0,0 +1,146 @@
  1 +require 'net/http'
  2 +require 'net/https'
  3 +require 'rubygems'
  4 +require 'active_support'
  5 +require 'hoptoad_notifier/version'
  6 +require 'hoptoad_notifier/configuration'
  7 +require 'hoptoad_notifier/notice'
  8 +require 'hoptoad_notifier/sender'
  9 +require 'hoptoad_notifier/backtrace'
  10 +require 'hoptoad_notifier/rack'
  11 +
  12 +# Gem for applications to automatically post errors to the Hoptoad of their choice.
  13 +module HoptoadNotifier
  14 +
  15 + API_VERSION = "2.0"
  16 + LOG_PREFIX = "** [Hoptoad] "
  17 +
  18 + HEADERS = {
  19 + 'Content-type' => 'text/xml',
  20 + 'Accept' => 'text/xml, application/xml'
  21 + }
  22 +
  23 + class << self
  24 + # The sender object is responsible for delivering formatted data to the Hoptoad server.
  25 + # Must respond to #send_to_hoptoad. See HoptoadNotifier::Sender.
  26 + attr_accessor :sender
  27 +
  28 + # A Hoptoad configuration object. Must act like a hash and return sensible
  29 + # values for all Hoptoad configuration options. See HoptoadNotifier::Configuration.
  30 + attr_accessor :configuration
  31 +
  32 + # Tell the log that the Notifier is good to go
  33 + def report_ready
  34 + write_verbose_log("Notifier #{VERSION} ready to catch errors")
  35 + end
  36 +
  37 + # Prints out the environment info to the log for debugging help
  38 + def report_environment_info
  39 + write_verbose_log("Environment Info: #{environment_info}")
  40 + end
  41 +
  42 + # Prints out the response body from Hoptoad for debugging help
  43 + def report_response_body(response)
  44 + write_verbose_log("Response from Hoptoad: \n#{response}")
  45 + end
  46 +
  47 + # Returns the Ruby version, Rails version, and current Rails environment
  48 + def environment_info
  49 + info = "[Ruby: #{RUBY_VERSION}]"
  50 + info << " [#{configuration.framework}]"
  51 + info << " [Env: #{configuration.environment_name}]"
  52 + end
  53 +
  54 + # Writes out the given message to the #logger
  55 + def write_verbose_log(message)
  56 + logger.info LOG_PREFIX + message if logger
  57 + end
  58 +
  59 + # Look for the Rails logger currently defined
  60 + def logger
  61 + self.configuration.logger
  62 + end
  63 +
  64 + # Call this method to modify defaults in your initializers.
  65 + #
  66 + # @example
  67 + # HoptoadNotifier.configure do |config|
  68 + # config.api_key = '1234567890abcdef'
  69 + # config.secure = false
  70 + # end
  71 + def configure(silent = false)
  72 + self.configuration ||= Configuration.new
  73 + yield(configuration)
  74 + self.sender = Sender.new(configuration)
  75 + report_ready unless silent
  76 + end
  77 +
  78 + # Sends an exception manually using this method, even when you are not in a controller.
  79 + #
  80 + # @param [Exception] exception The exception you want to notify Hoptoad about.
  81 + # @param [Hash] opts Data that will be sent to Hoptoad.
  82 + #
  83 + # @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Hoptoad uses for identification.
  84 + # @option opts [String] :error_message The error returned by the exception (or the message you want to log).
  85 + # @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
  86 + # @option opts [String] :request The controller's request object.
  87 + # @option opts [String] :session The contents of the user's session.
  88 + # @option opts [String] :environment ENV merged with the contents of the request's environment.
  89 + def notify(exception, opts = {})
  90 + send_notice(build_notice_for(exception, opts))
  91 + end
  92 +
  93 + # Sends the notice unless it is one of the default ignored exceptions
  94 + # @see HoptoadNotifier.notify
  95 + def notify_or_ignore(exception, opts = {})
  96 + notice = build_notice_for(exception, opts)
  97 + send_notice(notice) unless notice.ignore?
  98 + end
  99 +
  100 + def build_lookup_hash_for(exception, options = {})
  101 + notice = build_notice_for(exception, options)
  102 +
  103 + result = {}
  104 + result[:action] = notice.action rescue nil
  105 + result[:component] = notice.component rescue nil
  106 + result[:error_class] = notice.error_class if notice.error_class
  107 + result[:environment_name] = 'production'
  108 +
  109 + unless notice.backtrace.lines.empty?
  110 + result[:file] = notice.backtrace.lines.first.file
  111 + result[:line_number] = notice.backtrace.lines.first.number
  112 + end
  113 +
  114 + result
  115 + end
  116 +
  117 + private
  118 +
  119 + def send_notice(notice)
  120 + if configuration.public?
  121 + sender.send_to_hoptoad(notice.to_xml)
  122 + end
  123 + end
  124 +
  125 + def build_notice_for(exception, opts = {})
  126 + exception = unwrap_exception(exception)
  127 + if exception.respond_to?(:to_hash)
  128 + opts = opts.merge(exception)
  129 + else
  130 + opts = opts.merge(:exception => exception)
  131 + end
  132 + Notice.new(configuration.merge(opts))
  133 + end
  134 +
  135 + def unwrap_exception(exception)
  136 + if exception.respond_to?(:original_exception)
  137 + exception.original_exception
  138 + elsif exception.respond_to?(:continued_exception)
  139 + exception.continued_exception
  140 + else
  141 + exception
  142 + end
  143 + end
  144 + end
  145 +end
  146 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/backtrace.rb 0 → 100644
... ... @@ -0,0 +1,99 @@
  1 +module HoptoadNotifier
  2 + # Front end to parsing the backtrace for each notice
  3 + class Backtrace
  4 +
  5 + # Handles backtrace parsing line by line
  6 + class Line
  7 +
  8 + INPUT_FORMAT = %r{^([^:]+):(\d+)(?::in `([^']+)')?$}.freeze
  9 +
  10 + # The file portion of the line (such as app/models/user.rb)
  11 + attr_reader :file
  12 +
  13 + # The line number portion of the line
  14 + attr_reader :number
  15 +
  16 + # The method of the line (such as index)
  17 + attr_reader :method
  18 +
  19 + # Parses a single line of a given backtrace
  20 + # @param [String] unparsed_line The raw line from +caller+ or some backtrace
  21 + # @return [Line] The parsed backtrace line
  22 + def self.parse(unparsed_line)
  23 + _, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
  24 + new(file, number, method)
  25 + end
  26 +
  27 + def initialize(file, number, method)
  28 + self.file = file
  29 + self.number = number
  30 + self.method = method
  31 + end
  32 +
  33 + # Reconstructs the line in a readable fashion
  34 + def to_s
  35 + "#{file}:#{number}:in `#{method}'"
  36 + end
  37 +
  38 + def ==(other)
  39 + to_s == other.to_s
  40 + end
  41 +
  42 + def inspect
  43 + "<Line:#{to_s}>"
  44 + end
  45 +
  46 + private
  47 +
  48 + attr_writer :file, :number, :method
  49 + end
  50 +
  51 + # holder for an Array of Backtrace::Line instances
  52 + attr_reader :lines
  53 +
  54 + def self.parse(ruby_backtrace, opts = {})
  55 + ruby_lines = split_multiline_backtrace(ruby_backtrace)
  56 +
  57 + filters = opts[:filters] || []
  58 + filtered_lines = ruby_lines.to_a.map do |line|
  59 + filters.inject(line) do |line, proc|
  60 + proc.call(line)
  61 + end
  62 + end.compact
  63 +
  64 + lines = filtered_lines.collect do |unparsed_line|
  65 + Line.parse(unparsed_line)
  66 + end
  67 +
  68 + instance = new(lines)
  69 + end
  70 +
  71 + def initialize(lines)
  72 + self.lines = lines
  73 + end
  74 +
  75 + def inspect
  76 + "<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
  77 + end
  78 +
  79 + def ==(other)
  80 + if other.respond_to?(:lines)
  81 + lines == other.lines
  82 + else
  83 + false
  84 + end
  85 + end
  86 +
  87 + private
  88 +
  89 + attr_writer :lines
  90 +
  91 + def self.split_multiline_backtrace(backtrace)
  92 + if backtrace.to_a.size == 1
  93 + backtrace.to_a.first.split(/\n\s*/)
  94 + else
  95 + backtrace
  96 + end
  97 + end
  98 + end
  99 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/capistrano.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +# Defines deploy:notify_hoptoad which will send information about the deploy to Hoptoad.
  2 +
  3 +Capistrano::Configuration.instance(:must_exist).load do
  4 + after "deploy", "deploy:notify_hoptoad"
  5 + after "deploy:migrations", "deploy:notify_hoptoad"
  6 +
  7 + namespace :deploy do
  8 + desc "Notify Hoptoad of the deployment"
  9 + task :notify_hoptoad, :except => { :no_release => true } do
  10 + rails_env = fetch(:hoptoad_env, fetch(:rails_env, "production"))
  11 + local_user = ENV['USER'] || ENV['USERNAME']
  12 + executable = RUBY_PLATFORM.downcase.include?('mswin') ? 'rake.bat' : 'rake'
  13 + notify_command = "#{executable} hoptoad:deploy TO=#{rails_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
  14 + notify_command << " API_KEY=#{ENV['API_KEY']}" if ENV['API_KEY']
  15 + puts "Notifying Hoptoad of Deploy (#{notify_command})"
  16 + `#{notify_command}`
  17 + puts "Hoptoad Notification Complete."
  18 + end
  19 + end
  20 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/configuration.rb 0 → 100644
... ... @@ -0,0 +1,232 @@
  1 +module HoptoadNotifier
  2 + # Used to set up and modify settings for the notifier.
  3 + class Configuration
  4 +
  5 + OPTIONS = [:api_key, :backtrace_filters, :development_environments,
  6 + :development_lookup, :environment_name, :host,
  7 + :http_open_timeout, :http_read_timeout, :ignore, :ignore_by_filters,
  8 + :ignore_user_agent, :notifier_name, :notifier_url, :notifier_version,
  9 + :params_filters, :project_root, :port, :protocol, :proxy_host,
  10 + :proxy_pass, :proxy_port, :proxy_user, :secure, :framework].freeze
  11 +
  12 + # The API key for your project, found on the project edit form.
  13 + attr_accessor :api_key
  14 +
  15 + # The host to connect to (defaults to hoptoadapp.com).
  16 + attr_accessor :host
  17 +
  18 + # The port on which your Hoptoad server runs (defaults to 443 for secure
  19 + # connections, 80 for insecure connections).
  20 + attr_accessor :port
  21 +
  22 + # +true+ for https connections, +false+ for http connections.
  23 + attr_accessor :secure
  24 +
  25 + # The HTTP open timeout in seconds (defaults to 2).
  26 + attr_accessor :http_open_timeout
  27 +
  28 + # The HTTP read timeout in seconds (defaults to 5).
  29 + attr_accessor :http_read_timeout
  30 +
  31 + # The hostname of your proxy server (if using a proxy)
  32 + attr_accessor :proxy_host
  33 +
  34 + # The port of your proxy server (if using a proxy)
  35 + attr_accessor :proxy_port
  36 +
  37 + # The username to use when logging into your proxy server (if using a proxy)
  38 + attr_accessor :proxy_user
  39 +
  40 + # The password to use when logging into your proxy server (if using a proxy)
  41 + attr_accessor :proxy_pass
  42 +
  43 + # A list of parameters that should be filtered out of what is sent to Hoptoad.
  44 + # By default, all "password" attributes will have their contents replaced.
  45 + attr_reader :params_filters
  46 +
  47 + # A list of filters for cleaning and pruning the backtrace. See #filter_backtrace.
  48 + attr_reader :backtrace_filters
  49 +
  50 + # A list of filters for ignoring exceptions. See #ignore_by_filter.
  51 + attr_reader :ignore_by_filters
  52 +
  53 + # A list of exception classes to ignore. The array can be appended to.
  54 + attr_reader :ignore
  55 +
  56 + # A list of user agents that are being ignored. The array can be appended to.
  57 + attr_reader :ignore_user_agent
  58 +
  59 + # A list of environments in which notifications should not be sent.
  60 + attr_accessor :development_environments
  61 +
  62 + # +true+ if you want to check for production errors matching development errors, +false+ otherwise.
  63 + attr_accessor :development_lookup
  64 +
  65 + # The name of the environment the application is running in
  66 + attr_accessor :environment_name
  67 +
  68 + # The path to the project in which the error occurred, such as the RAILS_ROOT
  69 + attr_accessor :project_root
  70 +
  71 + # The name of the notifier library being used to send notifications (such as "Hoptoad Notifier")
  72 + attr_accessor :notifier_name
  73 +
  74 + # The version of the notifier library being used to send notifications (such as "1.0.2")
  75 + attr_accessor :notifier_version
  76 +
  77 + # The url of the notifier library being used to send notifications
  78 + attr_accessor :notifier_url
  79 +
  80 + # The logger used by HoptoadNotifier
  81 + attr_accessor :logger
  82 +
  83 + # The framework HoptoadNotifier is configured to use
  84 + attr_accessor :framework
  85 +
  86 + DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
  87 +
  88 + DEFAULT_BACKTRACE_FILTERS = [
  89 + lambda { |line|
  90 + if defined?(HoptoadNotifier.configuration.project_root) && HoptoadNotifier.configuration.project_root.to_s != ''
  91 + line.gsub(/#{HoptoadNotifier.configuration.project_root}/, "[PROJECT_ROOT]")
  92 + else
  93 + line
  94 + end
  95 + },
  96 + lambda { |line| line.gsub(/^\.\//, "") },
  97 + lambda { |line|
  98 + if defined?(Gem)
  99 + Gem.path.inject(line) do |line, path|
  100 + line.gsub(/#{path}/, "[GEM_ROOT]")
  101 + end
  102 + end
  103 + },
  104 + lambda { |line| line if line !~ %r{lib/hoptoad_notifier} }
  105 + ].freeze
  106 +
  107 + IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
  108 + 'ActionController::RoutingError',
  109 + 'ActionController::InvalidAuthenticityToken',
  110 + 'CGI::Session::CookieStore::TamperedWithCookie',
  111 + 'ActionController::UnknownAction']
  112 +
  113 + alias_method :secure?, :secure
  114 +
  115 + def initialize
  116 + @secure = false
  117 + @host = 'hoptoadapp.com'
  118 + @http_open_timeout = 2
  119 + @http_read_timeout = 5
  120 + @params_filters = DEFAULT_PARAMS_FILTERS.dup
  121 + @backtrace_filters = DEFAULT_BACKTRACE_FILTERS.dup
  122 + @ignore_by_filters = []
  123 + @ignore = IGNORE_DEFAULT.dup
  124 + @ignore_user_agent = []
  125 + @development_environments = %w(development test cucumber)
  126 + @development_lookup = true
  127 + @notifier_name = 'Hoptoad Notifier'
  128 + @notifier_version = VERSION
  129 + @notifier_url = 'http://hoptoadapp.com'
  130 + @framework = 'Standalone'
  131 + end
  132 +
  133 + # Takes a block and adds it to the list of backtrace filters. When the filters
  134 + # run, the block will be handed each line of the backtrace and can modify
  135 + # it as necessary.
  136 + #
  137 + # @example
  138 + # config.filter_bracktrace do |line|
  139 + # line.gsub(/^#{Rails.root}/, "[RAILS_ROOT]")
  140 + # end
  141 + #
  142 + # @param [Proc] block The new backtrace filter.
  143 + # @yieldparam [String] line A line in the backtrace.
  144 + def filter_backtrace(&block)
  145 + self.backtrace_filters << block
  146 + end
  147 +
  148 + # Takes a block and adds it to the list of ignore filters.
  149 + # When the filters run, the block will be handed the exception.
  150 + # @example
  151 + # config.ignore_by_filter do |exception_data|
  152 + # true if exception_data[:error_class] == "RuntimeError"
  153 + # end
  154 + #
  155 + # @param [Proc] block The new ignore filter
  156 + # @yieldparam [Hash] data The exception data given to +HoptoadNotifier.notify+
  157 + # @yieldreturn [Boolean] If the block returns true the exception will be ignored, otherwise it will be processed by hoptoad.
  158 + def ignore_by_filter(&block)
  159 + self.ignore_by_filters << block
  160 + end
  161 +
  162 + # Overrides the list of default ignored errors.
  163 + #
  164 + # @param [Array<Exception>] names A list of exceptions to ignore.
  165 + def ignore_only=(names)
  166 + @ignore = [names].flatten
  167 + end
  168 +
  169 + # Overrides the list of default ignored user agents
  170 + #
  171 + # @param [Array<String>] A list of user agents to ignore
  172 + def ignore_user_agent_only=(names)
  173 + @ignore_user_agent = [names].flatten
  174 + end
  175 +
  176 + # Allows config options to be read like a hash
  177 + #
  178 + # @param [Symbol] option Key for a given attribute
  179 + def [](option)
  180 + send(option)
  181 + end
  182 +
  183 + # Returns a hash of all configurable options
  184 + def to_hash
  185 + OPTIONS.inject({}) do |hash, option|
  186 + hash.merge(option.to_sym => send(option))
  187 + end
  188 + end
  189 +
  190 + # Returns a hash of all configurable options merged with +hash+
  191 + #
  192 + # @param [Hash] hash A set of configuration options that will take precedence over the defaults
  193 + def merge(hash)
  194 + to_hash.merge(hash)
  195 + end
  196 +
  197 + # Determines if the notifier will send notices.
  198 + # @return [Boolean] Returns +false+ if in a development environment, +true+ otherwise.
  199 + def public?
  200 + !development_environments.include?(environment_name)
  201 + end
  202 +
  203 + def port
  204 + @port || default_port
  205 + end
  206 +
  207 + def protocol
  208 + if secure?
  209 + 'https'
  210 + else
  211 + 'http'
  212 + end
  213 + end
  214 +
  215 + def environment_filters
  216 + warn 'config.environment_filters has been deprecated and has no effect.'
  217 + []
  218 + end
  219 +
  220 + private
  221 +
  222 + def default_port
  223 + if secure?
  224 + 443
  225 + else
  226 + 80
  227 + end
  228 + end
  229 +
  230 + end
  231 +
  232 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/notice.rb 0 → 100644
... ... @@ -0,0 +1,305 @@
  1 +module HoptoadNotifier
  2 + class Notice
  3 +
  4 + # The exception that caused this notice, if any
  5 + attr_reader :exception
  6 +
  7 + # The API key for the project to which this notice should be sent
  8 + attr_reader :api_key
  9 +
  10 + # The backtrace from the given exception or hash.
  11 + attr_reader :backtrace
  12 +
  13 + # The name of the class of error (such as RuntimeError)
  14 + attr_reader :error_class
  15 +
  16 + # The name of the server environment (such as "production")
  17 + attr_reader :environment_name
  18 +
  19 + # CGI variables such as HTTP_METHOD
  20 + attr_reader :cgi_data
  21 +
  22 + # The message from the exception, or a general description of the error
  23 + attr_reader :error_message
  24 +
  25 + # See Configuration#backtrace_filters
  26 + attr_reader :backtrace_filters
  27 +
  28 + # See Configuration#params_filters
  29 + attr_reader :params_filters
  30 +
  31 + # A hash of parameters from the query string or post body.
  32 + attr_reader :parameters
  33 + alias_method :params, :parameters
  34 +
  35 + # The component (if any) which was used in this request (usually the controller)
  36 + attr_reader :component
  37 + alias_method :controller, :component
  38 +
  39 + # The action (if any) that was called in this request
  40 + attr_reader :action
  41 +
  42 + # A hash of session data from the request
  43 + attr_reader :session_data
  44 +
  45 + # The path to the project that caused the error (usually RAILS_ROOT)
  46 + attr_reader :project_root
  47 +
  48 + # The URL at which the error occurred (if any)
  49 + attr_reader :url
  50 +
  51 + # See Configuration#ignore
  52 + attr_reader :ignore
  53 +
  54 + # See Configuration#ignore_by_filters
  55 + attr_reader :ignore_by_filters
  56 +
  57 + # The name of the notifier library sending this notice, such as "Hoptoad Notifier"
  58 + attr_reader :notifier_name
  59 +
  60 + # The version number of the notifier library sending this notice, such as "2.1.3"
  61 + attr_reader :notifier_version
  62 +
  63 + # A URL for more information about the notifier library sending this notice
  64 + attr_reader :notifier_url
  65 +
  66 + def initialize(args)
  67 + self.args = args
  68 + self.exception = args[:exception]
  69 + self.api_key = args[:api_key]
  70 + self.project_root = args[:project_root]
  71 + self.url = args[:url] || rack_env(:url)
  72 +
  73 + self.notifier_name = args[:notifier_name]
  74 + self.notifier_version = args[:notifier_version]
  75 + self.notifier_url = args[:notifier_url]
  76 +
  77 + self.ignore = args[:ignore] || []
  78 + self.ignore_by_filters = args[:ignore_by_filters] || []
  79 + self.backtrace_filters = args[:backtrace_filters] || []
  80 + self.params_filters = args[:params_filters] || []
  81 + self.parameters = args[:parameters] || rack_env(:params) || {}
  82 + self.component = args[:component] || args[:controller]
  83 + self.action = args[:action]
  84 +
  85 + self.environment_name = args[:environment_name]
  86 + self.cgi_data = args[:cgi_data] || args[:rack_env]
  87 + self.backtrace = Backtrace.parse(exception_attribute(:backtrace, caller), :filters => self.backtrace_filters)
  88 + self.error_class = exception_attribute(:error_class) {|exception| exception.class.name }
  89 + self.error_message = exception_attribute(:error_message, 'Notification') do |exception|
  90 + "#{exception.class.name}: #{exception.message}"
  91 + end
  92 +
  93 + find_session_data
  94 + clean_params
  95 + end
  96 +
  97 + # Converts the given notice to XML
  98 + def to_xml
  99 + builder = Builder::XmlMarkup.new
  100 + builder.instruct!
  101 + xml = builder.notice(:version => HoptoadNotifier::API_VERSION) do |notice|
  102 + notice.tag!("api-key", api_key)
  103 + notice.notifier do |notifier|
  104 + notifier.name(notifier_name)
  105 + notifier.version(notifier_version)
  106 + notifier.url(notifier_url)
  107 + end
  108 + notice.error do |error|
  109 + error.tag!('class', error_class)
  110 + error.message(error_message)
  111 + error.backtrace do |backtrace|
  112 + self.backtrace.lines.each do |line|
  113 + backtrace.line(:number => line.number,
  114 + :file => line.file,
  115 + :method => line.method)
  116 + end
  117 + end
  118 + end
  119 + if url ||
  120 + controller ||
  121 + action ||
  122 + !parameters.blank? ||
  123 + !cgi_data.blank? ||
  124 + !session_data.blank?
  125 + notice.request do |request|
  126 + request.url(url)
  127 + request.component(controller)
  128 + request.action(action)
  129 + unless parameters.blank?
  130 + request.params do |params|
  131 + xml_vars_for(params, parameters)
  132 + end
  133 + end
  134 + unless session_data.blank?
  135 + request.session do |session|
  136 + xml_vars_for(session, session_data)
  137 + end
  138 + end
  139 + unless cgi_data.blank?
  140 + request.tag!("cgi-data") do |cgi_datum|
  141 + xml_vars_for(cgi_datum, cgi_data)
  142 + end
  143 + end
  144 + end
  145 + end
  146 + notice.tag!("server-environment") do |env|
  147 + env.tag!("project-root", project_root)
  148 + env.tag!("environment-name", environment_name)
  149 + end
  150 + end
  151 + xml.to_s
  152 + end
  153 +
  154 + # Determines if this notice should be ignored
  155 + def ignore?
  156 + ignored_class_names.include?(error_class) ||
  157 + ignore_by_filters.any? {|filter| filter.call(self) }
  158 + end
  159 +
  160 + # Allows properties to be accessed using a hash-like syntax
  161 + #
  162 + # @example
  163 + # notice[:error_message]
  164 + # @param [String] method The given key for an attribute
  165 + # @return The attribute value, or self if given +:request+
  166 + def [](method)
  167 + case method
  168 + when :request
  169 + self
  170 + else
  171 + send(method)
  172 + end
  173 + end
  174 +
  175 + private
  176 +
  177 + attr_writer :exception, :api_key, :backtrace, :error_class, :error_message,
  178 + :backtrace_filters, :parameters, :params_filters,
  179 + :environment_filters, :session_data, :project_root, :url, :ignore,
  180 + :ignore_by_filters, :notifier_name, :notifier_url, :notifier_version,
  181 + :component, :action, :cgi_data, :environment_name
  182 +
  183 + # Arguments given in the initializer
  184 + attr_accessor :args
  185 +
  186 + # Gets a property named +attribute+ of an exception, either from an actual
  187 + # exception or a hash.
  188 + #
  189 + # If an exception is available, #from_exception will be used. Otherwise,
  190 + # a key named +attribute+ will be used from the #args.
  191 + #
  192 + # If no exception or hash key is available, +default+ will be used.
  193 + def exception_attribute(attribute, default = nil, &block)
  194 + (exception && from_exception(attribute, &block)) || args[attribute] || default
  195 + end
  196 +
  197 + # Gets a property named +attribute+ from an exception.
  198 + #
  199 + # If a block is given, it will be used when getting the property from an
  200 + # exception. The block should accept and exception and return the value for
  201 + # the property.
  202 + #
  203 + # If no block is given, a method with the same name as +attribute+ will be
  204 + # invoked for the value.
  205 + def from_exception(attribute)
  206 + if block_given?
  207 + yield(exception)
  208 + else
  209 + exception.send(attribute)
  210 + end
  211 + end
  212 +
  213 + # Removes non-serializable data from the given attribute.
  214 + # See #clean_unserializable_data
  215 + def clean_unserializable_data_from(attribute)
  216 + self.send(:"#{attribute}=", clean_unserializable_data(send(attribute)))
  217 + end
  218 +
  219 + # Removes non-serializable data. Allowed data types are strings, arrays,
  220 + # and hashes. All other types are converted to strings.
  221 + # TODO: move this onto Hash
  222 + def clean_unserializable_data(data)
  223 + if data.respond_to?(:to_hash)
  224 + data.to_hash.inject({}) do |result, (key, value)|
  225 + result.merge(key => clean_unserializable_data(value))
  226 + end
  227 + elsif data.respond_to?(:to_ary)
  228 + data.collect do |value|
  229 + clean_unserializable_data(value)
  230 + end
  231 + else
  232 + data.to_s
  233 + end
  234 + end
  235 +
  236 + # Replaces the contents of params that match params_filters.
  237 + # TODO: extract this to a different class
  238 + def clean_params
  239 + clean_unserializable_data_from(:parameters)
  240 + filter(parameters)
  241 + if cgi_data
  242 + clean_unserializable_data_from(:cgi_data)
  243 + filter(cgi_data)
  244 + end
  245 + if session_data
  246 + clean_unserializable_data_from(:session_data)
  247 + end
  248 + end
  249 +
  250 + def filter(hash)
  251 + if params_filters
  252 + hash.each do |key, value|
  253 + if filter_key?(key)
  254 + hash[key] = "[FILTERED]"
  255 + elsif value.respond_to?(:to_hash)
  256 + filter(hash[key])
  257 + end
  258 + end
  259 + end
  260 + end
  261 +
  262 + def filter_key?(key)
  263 + params_filters.any? do |filter|
  264 + key.to_s.include?(filter)
  265 + end
  266 + end
  267 +
  268 + def find_session_data
  269 + self.session_data = args[:session_data] || args[:session] || {}
  270 + self.session_data = session_data[:data] if session_data[:data]
  271 + end
  272 +
  273 + # Converts the mixed class instances and class names into just names
  274 + # TODO: move this into Configuration or another class
  275 + def ignored_class_names
  276 + ignore.collect do |string_or_class|
  277 + if string_or_class.respond_to?(:name)
  278 + string_or_class.name
  279 + else
  280 + string_or_class
  281 + end
  282 + end
  283 + end
  284 +
  285 + def xml_vars_for(builder, hash)
  286 + hash.each do |key, value|
  287 + if value.respond_to?(:to_hash)
  288 + builder.var(:key => key){|b| xml_vars_for(b, value.to_hash) }
  289 + else
  290 + builder.var(value.to_s, :key => key)
  291 + end
  292 + end
  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
  304 + end
  305 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/rack.rb 0 → 100644
... ... @@ -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
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/rails.rb 0 → 100644
... ... @@ -0,0 +1,37 @@
  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
  20 +
  21 + if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
  22 + ::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
  23 + HoptoadNotifier::Rack
  24 + end
  25 +
  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
  34 +end
  35 +
  36 +HoptoadNotifier::Rails.initialize
  37 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/rails/action_controller_catcher.rb 0 → 100644
... ... @@ -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
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/rails/controller_methods.rb 0 → 100644
... ... @@ -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 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/rails/error_lookup.rb 0 → 100644
... ... @@ -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 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/sender.rb 0 → 100644
... ... @@ -0,0 +1,63 @@
  1 +module HoptoadNotifier
  2 + # Sends out the notice to Hoptoad
  3 + class Sender
  4 +
  5 + NOTICES_URI = '/notifier_api/v2/notices/'.freeze
  6 +
  7 + def initialize(options = {})
  8 + [:proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
  9 + :host, :port, :secure, :http_open_timeout, :http_read_timeout].each do |option|
  10 + instance_variable_set("@#{option}", options[option])
  11 + end
  12 + end
  13 +
  14 + # Sends the notice data off to Hoptoad for processing.
  15 + #
  16 + # @param [String] data The XML notice to be sent off
  17 + def send_to_hoptoad(data)
  18 + logger.debug { "Sending request to #{url.to_s}:\n#{data}" } if logger
  19 +
  20 + http =
  21 + Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).
  22 + new(url.host, url.port)
  23 +
  24 + http.read_timeout = http_read_timeout
  25 + http.open_timeout = http_open_timeout
  26 + http.use_ssl = secure
  27 +
  28 + response = begin
  29 + http.post(url.path, data, HEADERS)
  30 + rescue TimeoutError => e
  31 + log :error, "Timeout while contacting the Hoptoad server."
  32 + nil
  33 + end
  34 +
  35 + case response
  36 + when Net::HTTPSuccess then
  37 + log :info, "Success: #{response.class}", response
  38 + else
  39 + log :error, "Failure: #{response.class}", response
  40 + end
  41 + end
  42 +
  43 + private
  44 +
  45 + attr_reader :proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
  46 + :host, :port, :secure, :http_open_timeout, :http_read_timeout
  47 +
  48 + def url
  49 + URI.parse("#{protocol}://#{host}:#{port}").merge(NOTICES_URI)
  50 + end
  51 +
  52 + def log(level, message, response = nil)
  53 + logger.send level, LOG_PREFIX + message if logger
  54 + HoptoadNotifier.report_environment_info
  55 + HoptoadNotifier.report_response_body(response.body) if response && response.respond_to?(:body)
  56 + end
  57 +
  58 + def logger
  59 + HoptoadNotifier.logger
  60 + end
  61 +
  62 + end
  63 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/tasks.rb 0 → 100644
... ... @@ -0,0 +1,97 @@
  1 +require 'hoptoad_notifier'
  2 +
  3 +namespace :hoptoad do
  4 + desc "Notify Hoptoad of a new deploy."
  5 + task :deploy => :environment do
  6 + require 'hoptoad_tasks'
  7 + HoptoadTasks.deploy(:rails_env => ENV['TO'],
  8 + :scm_revision => ENV['REVISION'],
  9 + :scm_repository => ENV['REPO'],
  10 + :local_username => ENV['USER'],
  11 + :api_key => ENV['API_KEY'])
  12 + end
  13 +
  14 + task :log_stdout do
  15 + require 'logger'
  16 + RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
  17 + end
  18 +
  19 + desc "Verify your gem installation by sending a test exception to the hoptoad service"
  20 + task :test => ['hoptoad:log_stdout', :environment] do
  21 + RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
  22 +
  23 + require 'action_controller/test_process'
  24 +
  25 + Dir["app/controllers/application*.rb"].each { |file| require(file) }
  26 +
  27 + class HoptoadTestingException < RuntimeError; end
  28 +
  29 + unless HoptoadNotifier.configuration.api_key
  30 + puts "Hoptoad needs an API key configured! Check the README to see how to add it."
  31 + exit
  32 + end
  33 +
  34 + HoptoadNotifier.configuration.development_environments = []
  35 +
  36 + catcher = HoptoadNotifier::Rails::ActionControllerCatcher
  37 + in_controller = ApplicationController.included_modules.include?(catcher)
  38 + in_base = ActionController::Base.included_modules.include?(catcher)
  39 + if !in_controller || !in_base
  40 + puts "Rails initialization did not occur"
  41 + exit
  42 + end
  43 +
  44 + puts "Configuration:"
  45 + HoptoadNotifier.configuration.to_hash.each do |key, value|
  46 + puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
  47 + end
  48 +
  49 + unless defined?(ApplicationController)
  50 + puts "No ApplicationController found"
  51 + exit
  52 + end
  53 +
  54 + puts 'Setting up the Controller.'
  55 + class ApplicationController
  56 + # This is to bypass any filters that may prevent access to the action.
  57 + prepend_before_filter :test_hoptoad
  58 + def test_hoptoad
  59 + puts "Raising '#{exception_class.name}' to simulate application failure."
  60 + raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
  61 + end
  62 +
  63 + def rescue_action(exception)
  64 + rescue_action_in_public exception
  65 + end
  66 +
  67 + # Ensure we actually have an action to go to.
  68 + def verify; end
  69 +
  70 + def consider_all_requests_local
  71 + false
  72 + end
  73 +
  74 + def local_request?
  75 + false
  76 + end
  77 +
  78 + def exception_class
  79 + exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
  80 + Object.const_get(exception_name)
  81 + rescue
  82 + Object.const_set(exception_name, Class.new(Exception))
  83 + end
  84 +
  85 + def logger
  86 + nil
  87 + end
  88 + end
  89 + class HoptoadVerificationController < ApplicationController; end
  90 +
  91 + puts 'Processing request.'
  92 + request = ActionController::TestRequest.new
  93 + response = ActionController::TestResponse.new
  94 + HoptoadVerificationController.new.process(request, response)
  95 + end
  96 +end
  97 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_notifier/version.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +module HoptoadNotifier
  2 + VERSION = "2.2.2".freeze
  3 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/hoptoad_tasks.rb 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +require 'net/http'
  2 +require 'uri'
  3 +require 'active_support'
  4 +
  5 +# Capistrano tasks for notifying Hoptoad of deploys
  6 +module HoptoadTasks
  7 +
  8 + # Alerts Hoptoad of a deploy.
  9 + #
  10 + # @param [Hash] opts Data about the deploy that is set to Hoptoad
  11 + #
  12 + # @option opts [String] :rails_env Environment of the deploy (production, staging)
  13 + # @option opts [String] :scm_revision The given revision/sha that is being deployed
  14 + # @option opts [String] :scm_repository Address of your repository to help with code lookups
  15 + # @option opts [String] :local_username Who is deploying
  16 + def self.deploy(opts = {})
  17 + if HoptoadNotifier.configuration.api_key.blank?
  18 + puts "I don't seem to be configured with an API key. Please check your configuration."
  19 + return false
  20 + end
  21 +
  22 + if opts[:rails_env].blank?
  23 + puts "I don't know to which Rails environment you are deploying (use the TO=production option)."
  24 + return false
  25 + end
  26 +
  27 + params = {'api_key' => opts.delete(:api_key) ||
  28 + HoptoadNotifier.configuration.api_key}
  29 + opts.each {|k,v| params["deploy[#{k}]"] = v }
  30 +
  31 + url = URI.parse("http://#{HoptoadNotifier.configuration.host || 'hoptoadapp.com'}/deploys.txt")
  32 + response = Net::HTTP.post_form(url, params)
  33 + puts response.body
  34 + return Net::HTTPSuccess === response
  35 + end
  36 +end
  37 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/lib/templates/rescue.erb 0 → 100644
... ... @@ -0,0 +1,91 @@
  1 +<script type="text/javascript">
  2 +var Hoptoad = {
  3 + host : <%= host.to_json %>,
  4 + api_key : <%= api_key.to_json %>,
  5 + notice : <%= notice.to_json %>,
  6 + message : 'This error exists in production!',
  7 +
  8 + initialize: function() {
  9 + if (this.initialized) {
  10 + return;
  11 + } else {
  12 + this.initialized = true;
  13 + }
  14 +
  15 + var data = [];
  16 +
  17 + for (var key in this.notice) {
  18 + data[data.length] = 'notice[' + key + ']=' + this.notice[key];
  19 + }
  20 +
  21 + data[data.length] = 'notice[api_key]=' + this.api_key;
  22 + data[data.length] = 'callback=Hoptoad.onSuccess';
  23 + data[data.length] = '_=' + (new Date()).getTime();
  24 +
  25 + var head = document.getElementsByTagName('head')[0];
  26 + var done = false;
  27 +
  28 + var
  29 + script = document.createElement('script');
  30 + script.src = 'http://' + this.host + '/notices_api/v1/notices/exist?' +
  31 + data.join('&');
  32 + script.type = 'text/javascript';
  33 + script.onload = script.onreadystatechange = function(){
  34 + if (!done && (!this.readyState ||
  35 + this.readyState == 'loaded' || this.readyState == 'complete')) {
  36 +
  37 + done = true;
  38 +
  39 + // Handle memory leak in IE. (via jQuery)
  40 + script.onload = script.onreadystatechange = null;
  41 + head.removeChild(script);
  42 + }
  43 + };
  44 +
  45 + head.appendChild(script);
  46 + },
  47 +
  48 + onSuccess: function(error) {
  49 + var body = document.getElementsByTagName('body')[0];
  50 + var text = document.createTextNode(this.message);
  51 + var element = document.createElement('a');
  52 +
  53 + element.id = 'hoptoad';
  54 + element.href = 'http://' + error.subdomain + '.' + this.host +
  55 + '/projects/' + error.project_id + '/errors/' + error.id;
  56 + element.appendChild(text);
  57 +
  58 + body.insertBefore(element, body.firstChild);
  59 +
  60 + var h1 = document.getElementsByTagName('h1')[0];
  61 + var pre = document.getElementsByTagName('pre')[0];
  62 + var wrapper = document.createElement('div');
  63 +
  64 + wrapper.id = 'wrapper';
  65 + wrapper.appendChild(h1);
  66 + wrapper.appendChild(pre);
  67 +
  68 + body.insertBefore(wrapper, body.children[1]);
  69 + }
  70 +};
  71 +
  72 +window.onload = function() {
  73 + Hoptoad.initialize.apply(Hoptoad);
  74 +};
  75 +</script>
  76 +
  77 +<style type="text/css">
  78 +#hoptoad {
  79 + background: #FFF url(http://hoptoadapp.com/images/fell-off-the-toad.gif) no-repeat top right;
  80 + color: #F00;
  81 + padding: 45px 101px 45px 12px;
  82 + font-size: 14px;
  83 + font-weight: bold;
  84 + display: block;
  85 + float: right;
  86 +}
  87 +
  88 +#wrapper {
  89 + padding-right: 360px;
  90 +}
  91 +</style>
... ...
vendor/gems/hoptoad_notifier-2.2.2/rails/init.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require 'hoptoad_notifier/rails'
... ...
vendor/gems/hoptoad_notifier-2.2.2/script/integration_test.rb 0 → 100755
... ... @@ -0,0 +1,38 @@
  1 +#!/usr/bin/env ruby
  2 +
  3 +require 'logger'
  4 +require 'fileutils'
  5 +
  6 +RAILS_ENV = "production"
  7 +RAILS_ROOT = FileUtils.pwd
  8 +RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
  9 +
  10 +$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
  11 +require 'hoptoad_notifier'
  12 +require 'rails/init'
  13 +
  14 +fail "Please supply an API Key as the first argument" if ARGV.empty?
  15 +
  16 +host = ARGV[1]
  17 +host ||= "hoptoadapp.com"
  18 +
  19 +secure = (ARGV[2] == "secure")
  20 +
  21 +exception = begin
  22 + raise "Testing hoptoad notifier with secure = #{secure}. If you can see this, it works."
  23 + rescue => foo
  24 + foo
  25 + end
  26 +
  27 +HoptoadNotifier.configure do |config|
  28 + config.secure = secure
  29 + config.host = host
  30 + config.api_key = ARGV.first
  31 +end
  32 +puts "Configuration:"
  33 +HoptoadNotifier.configuration.to_hash.each do |key, value|
  34 + puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
  35 +end
  36 +puts "Sending #{secure ? "" : "in"}secure notification to project with key #{ARGV.first}"
  37 +HoptoadNotifier.notify(exception)
  38 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/backtrace_test.rb 0 → 100644
... ... @@ -0,0 +1,118 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class BacktraceTest < Test::Unit::TestCase
  4 +
  5 + should "parse a backtrace into lines" do
  6 + array = [
  7 + "app/models/user.rb:13:in `magic'",
  8 + "app/controllers/users_controller.rb:8:in `index'"
  9 + ]
  10 +
  11 + backtrace = HoptoadNotifier::Backtrace.parse(array)
  12 +
  13 + line = backtrace.lines.first
  14 + assert_equal '13', line.number
  15 + assert_equal 'app/models/user.rb', line.file
  16 + assert_equal 'magic', line.method
  17 +
  18 + line = backtrace.lines.last
  19 + assert_equal '8', line.number
  20 + assert_equal 'app/controllers/users_controller.rb', line.file
  21 + assert_equal 'index', line.method
  22 + end
  23 +
  24 + should "be equal with equal lines" do
  25 + one = build_backtrace_array
  26 + two = one.dup
  27 + assert_equal one, two
  28 +
  29 + assert_equal HoptoadNotifier::Backtrace.parse(one), HoptoadNotifier::Backtrace.parse(two)
  30 + end
  31 +
  32 + should "parse massive one-line exceptions into multiple lines" do
  33 + original_backtrace = HoptoadNotifier::Backtrace.
  34 + parse(["one:1:in `one'\n two:2:in `two'\n three:3:in `three`"])
  35 + expected_backtrace = HoptoadNotifier::Backtrace.
  36 + parse(["one:1:in `one'", "two:2:in `two'", "three:3:in `three`"])
  37 +
  38 + assert_equal expected_backtrace, original_backtrace
  39 + end
  40 +
  41 + context "with a project root" do
  42 + setup do
  43 + @project_root = '/some/path'
  44 + HoptoadNotifier.configure {|config| config.project_root = @project_root }
  45 + end
  46 +
  47 + teardown do
  48 + reset_config
  49 + end
  50 +
  51 + should "filter out the project root" do
  52 + backtrace_with_root = HoptoadNotifier::Backtrace.parse(
  53 + ["#{@project_root}/app/models/user.rb:7:in `latest'",
  54 + "#{@project_root}/app/controllers/users_controller.rb:13:in `index'",
  55 + "/lib/something.rb:41:in `open'"],
  56 + :filters => default_filters)
  57 + backtrace_without_root = HoptoadNotifier::Backtrace.parse(
  58 + ["[PROJECT_ROOT]/app/models/user.rb:7:in `latest'",
  59 + "[PROJECT_ROOT]/app/controllers/users_controller.rb:13:in `index'",
  60 + "/lib/something.rb:41:in `open'"])
  61 +
  62 + assert_equal backtrace_without_root, backtrace_with_root
  63 + end
  64 + end
  65 +
  66 + context "with a blank project root" do
  67 + setup do
  68 + HoptoadNotifier.configure {|config| config.project_root = '' }
  69 + end
  70 +
  71 + teardown do
  72 + reset_config
  73 + end
  74 +
  75 + should "not filter line numbers with respect to any project root" do
  76 + backtrace = ["/app/models/user.rb:7:in `latest'",
  77 + "/app/controllers/users_controller.rb:13:in `index'",
  78 + "/lib/something.rb:41:in `open'"]
  79 +
  80 + backtrace_with_root =
  81 + HoptoadNotifier::Backtrace.parse(backtrace, :filters => default_filters)
  82 +
  83 + backtrace_without_root =
  84 + HoptoadNotifier::Backtrace.parse(backtrace)
  85 +
  86 + assert_equal backtrace_without_root, backtrace_with_root
  87 + end
  88 + end
  89 +
  90 + should "remove notifier trace" do
  91 + inside_notifier = ['lib/hoptoad_notifier.rb:13:in `voodoo`']
  92 + outside_notifier = ['users_controller:8:in `index`']
  93 +
  94 + without_inside = HoptoadNotifier::Backtrace.parse(outside_notifier)
  95 + with_inside = HoptoadNotifier::Backtrace.parse(inside_notifier + outside_notifier,
  96 + :filters => default_filters)
  97 +
  98 + assert_equal without_inside, with_inside
  99 + end
  100 +
  101 + should "run filters on the backtrace" do
  102 + filters = [lambda { |line| line.sub('foo', 'bar') }]
  103 + input = HoptoadNotifier::Backtrace.parse(["foo:13:in `one'", "baz:14:in `two'"],
  104 + :filters => filters)
  105 + expected = HoptoadNotifier::Backtrace.parse(["bar:13:in `one'", "baz:14:in `two'"])
  106 + assert_equal expected, input
  107 + end
  108 +
  109 + def build_backtrace_array
  110 + ["app/models/user.rb:13:in `magic'",
  111 + "app/controllers/users_controller.rb:8:in `index'"]
  112 + end
  113 +
  114 + def default_filters
  115 + HoptoadNotifier::Configuration::DEFAULT_BACKTRACE_FILTERS
  116 + end
  117 +
  118 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/catcher_test.rb 0 → 100644
... ... @@ -0,0 +1,324 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class ActionControllerCatcherTest < Test::Unit::TestCase
  4 +
  5 + include DefinesConstants
  6 +
  7 + def setup
  8 + super
  9 + reset_config
  10 + HoptoadNotifier.sender = CollectingSender.new
  11 + define_constant('RAILS_ROOT', '/path/to/rails/root')
  12 + end
  13 +
  14 + def ignore(exception_class)
  15 + HoptoadNotifier.configuration.ignore << exception_class
  16 + end
  17 +
  18 + def build_controller_class(&definition)
  19 + returning Class.new(ActionController::Base) do |klass|
  20 + klass.__send__(:include, HoptoadNotifier::Rails::ActionControllerCatcher)
  21 + klass.class_eval(&definition) if definition
  22 + define_constant('HoptoadTestController', klass)
  23 + end
  24 + end
  25 +
  26 + def assert_sent_hash(hash, xpath)
  27 + hash.each do |key, value|
  28 + element_xpath = "#{xpath}/var[@key = '#{key}']"
  29 + if value.respond_to?(:to_hash)
  30 + assert_sent_hash value.to_hash, element_xpath
  31 + else
  32 + assert_sent_element value, element_xpath
  33 + end
  34 + end
  35 + end
  36 +
  37 + def assert_sent_element(value, xpath)
  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
  49 + end
  50 +
  51 + def assert_sent_request_info_for(request)
  52 + params = request.parameters.to_hash
  53 + assert_sent_hash params, '/notice/request/params'
  54 + assert_sent_element params['controller'], '/notice/request/component'
  55 + assert_sent_element params['action'], '/notice/request/action'
  56 + assert_sent_element url_from_request(request), '/notice/request/url'
  57 + assert_sent_hash request.env, '/notice/request/cgi-data'
  58 + end
  59 +
  60 + def url_from_request(request)
  61 + url = "#{request.protocol}#{request.host}"
  62 +
  63 + unless [80, 443].include?(request.port)
  64 + url << ":#{request.port}"
  65 + end
  66 +
  67 + url << request.request_uri
  68 + url
  69 + end
  70 +
  71 + def sender
  72 + HoptoadNotifier.sender
  73 + end
  74 +
  75 + def last_sent_notice_xml
  76 + sender.collected.last
  77 + end
  78 +
  79 + def last_sent_notice_document
  80 + assert_not_nil xml = last_sent_notice_xml, "No xml was sent"
  81 + Nokogiri::XML.parse(xml)
  82 + end
  83 +
  84 + def process_action(opts = {}, &action)
  85 + opts[:request] ||= ActionController::TestRequest.new
  86 + opts[:response] ||= ActionController::TestResponse.new
  87 + klass = build_controller_class do
  88 + cattr_accessor :local
  89 + define_method(:index, &action)
  90 + def local_request?
  91 + local
  92 + end
  93 + end
  94 + if opts[:filters]
  95 + klass.filter_parameter_logging *opts[:filters]
  96 + end
  97 + if opts[:user_agent]
  98 + if opts[:request].respond_to?(:user_agent=)
  99 + opts[:request].user_agent = opts[:user_agent]
  100 + else
  101 + opts[:request].env["HTTP_USER_AGENT"] = opts[:user_agent]
  102 + end
  103 + end
  104 + if opts[:port]
  105 + opts[:request].port = opts[:port]
  106 + end
  107 + klass.consider_all_requests_local = opts[:all_local]
  108 + klass.local = opts[:local]
  109 + controller = klass.new
  110 + controller.stubs(:rescue_action_in_public_without_hoptoad)
  111 + opts[:request].query_parameters = opts[:request].query_parameters.merge(opts[:params] || {})
  112 + opts[:request].session = ActionController::TestSession.new(opts[:session] || {})
  113 + controller.process(opts[:request], opts[:response])
  114 + controller
  115 + end
  116 +
  117 + def process_action_with_manual_notification(args = {})
  118 + process_action(args) do
  119 + notify_hoptoad(:error_message => 'fail')
  120 + # Rails will raise a template error if we don't render something
  121 + render :nothing => true
  122 + end
  123 + end
  124 +
  125 + def process_action_with_automatic_notification(args = {})
  126 + process_action(args) { raise "Hello" }
  127 + end
  128 +
  129 + should "deliver notices from exceptions raised in public requests" do
  130 + process_action_with_automatic_notification
  131 + assert_caught_and_sent
  132 + end
  133 +
  134 + should "not deliver notices from exceptions in local requests" do
  135 + process_action_with_automatic_notification(:local => true)
  136 + assert_caught_and_not_sent
  137 + end
  138 +
  139 + should "not deliver notices from exceptions when all requests are local" do
  140 + process_action_with_automatic_notification(:all_local => true)
  141 + assert_caught_and_not_sent
  142 + end
  143 +
  144 + should "not deliver notices from actions that don't raise" do
  145 + controller = process_action { render :text => 'Hello' }
  146 + assert_caught_and_not_sent
  147 + assert_equal 'Hello', controller.response.body
  148 + end
  149 +
  150 + should "not deliver ignored exceptions raised by actions" do
  151 + ignore(RuntimeError)
  152 + process_action_with_automatic_notification
  153 + assert_caught_and_not_sent
  154 + end
  155 +
  156 + should "deliver ignored exception raised manually" do
  157 + ignore(RuntimeError)
  158 + process_action_with_manual_notification
  159 + assert_caught_and_sent
  160 + end
  161 +
  162 + should "deliver manually sent notices in public requests" do
  163 + process_action_with_manual_notification
  164 + assert_caught_and_sent
  165 + end
  166 +
  167 + should "not deliver manually sent notices in local requests" do
  168 + process_action_with_manual_notification(:local => true)
  169 + assert_caught_and_not_sent
  170 + end
  171 +
  172 + should "not deliver manually sent notices when all requests are local" do
  173 + process_action_with_manual_notification(:all_local => true)
  174 + assert_caught_and_not_sent
  175 + end
  176 +
  177 + should "continue with default behavior after delivering an exception" do
  178 + controller = process_action_with_automatic_notification(:public => true)
  179 + # TODO: can we test this without stubbing?
  180 + assert_received(controller, :rescue_action_in_public_without_hoptoad)
  181 + end
  182 +
  183 + should "not create actions from Hoptoad methods" do
  184 + controller = build_controller_class.new
  185 + assert_equal [], HoptoadNotifier::Rails::ActionControllerCatcher.instance_methods
  186 + end
  187 +
  188 + should "ignore exceptions when user agent is being ignored by regular expression" do
  189 + HoptoadNotifier.configuration.ignore_user_agent_only = [/Ignored/]
  190 + process_action_with_automatic_notification(:user_agent => 'ShouldBeIgnored')
  191 + assert_caught_and_not_sent
  192 + end
  193 +
  194 + should "ignore exceptions when user agent is being ignored by string" do
  195 + HoptoadNotifier.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
  196 + process_action_with_automatic_notification(:user_agent => 'IgnoredUserAgent')
  197 + assert_caught_and_not_sent
  198 + end
  199 +
  200 + should "not ignore exceptions when user agent is not being ignored" do
  201 + HoptoadNotifier.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
  202 + process_action_with_automatic_notification(:user_agent => 'NonIgnoredAgent')
  203 + assert_caught_and_sent
  204 + end
  205 +
  206 + should "send session data for manual notifications" do
  207 + data = { 'one' => 'two' }
  208 + process_action_with_manual_notification(:session => data)
  209 + assert_sent_hash data, "/notice/request/session"
  210 + end
  211 +
  212 + should "send session data for automatic notification" do
  213 + data = { 'one' => 'two' }
  214 + process_action_with_automatic_notification(:session => data)
  215 + assert_sent_hash data, "/notice/request/session"
  216 + end
  217 +
  218 + should "send request data for manual notification" do
  219 + params = { 'controller' => "hoptoad_test", 'action' => "index" }
  220 + controller = process_action_with_manual_notification(:params => params)
  221 + assert_sent_request_info_for controller.request
  222 + end
  223 +
  224 + should "send request data for manual notification with non-standard port" do
  225 + params = { 'controller' => "hoptoad_test", 'action' => "index" }
  226 + controller = process_action_with_manual_notification(:params => params, :port => 81)
  227 + assert_sent_request_info_for controller.request
  228 + end
  229 +
  230 + should "send request data for automatic notification" do
  231 + params = { 'controller' => "hoptoad_test", 'action' => "index" }
  232 + controller = process_action_with_automatic_notification(:params => params)
  233 + assert_sent_request_info_for controller.request
  234 + end
  235 +
  236 + should "send request data for automatic notification with non-standard port" do
  237 + params = { 'controller' => "hoptoad_test", 'action' => "index" }
  238 + controller = process_action_with_automatic_notification(:params => params, :port => 81)
  239 + assert_sent_request_info_for controller.request
  240 + end
  241 +
  242 + should "use standard rails logging filters on params and env" do
  243 + filtered_params = { "abc" => "123",
  244 + "def" => "456",
  245 + "ghi" => "[FILTERED]" }
  246 + ENV['ghi'] = 'abc'
  247 + filtered_env = { 'ghi' => '[FILTERED]' }
  248 + filtered_cgi = { 'REQUEST_METHOD' => '[FILTERED]' }
  249 +
  250 + process_action_with_automatic_notification(:filters => [:ghi, :request_method],
  251 + :params => { "abc" => "123",
  252 + "def" => "456",
  253 + "ghi" => "789" })
  254 + assert_sent_hash filtered_params, '/notice/request/params'
  255 + assert_sent_hash filtered_cgi, '/notice/request/cgi-data'
  256 + end
  257 +
  258 + context "for a local error with development lookup enabled" do
  259 + setup do
  260 + HoptoadNotifier.configuration.development_lookup = true
  261 + HoptoadNotifier.stubs(:build_lookup_hash_for).returns({ :awesome => 2 })
  262 +
  263 + @controller = process_action_with_automatic_notification(:local => true)
  264 + @response = @controller.response
  265 + end
  266 +
  267 + should "append custom CSS and JS to response body for a local error" do
  268 + assert_match /text\/css/, @response.body
  269 + assert_match /text\/javascript/, @response.body
  270 + end
  271 +
  272 + should "contain host, API key and notice JSON" do
  273 + assert_match HoptoadNotifier.configuration.host.to_json, @response.body
  274 + assert_match HoptoadNotifier.configuration.api_key.to_json, @response.body
  275 + assert_match ({ :awesome => 2 }).to_json, @response.body
  276 + end
  277 + end
  278 +
  279 + context "for a local error with development lookup disabled" do
  280 + setup do
  281 + HoptoadNotifier.configuration.development_lookup = false
  282 +
  283 + @controller = process_action_with_automatic_notification(:local => true)
  284 + @response = @controller.response
  285 + end
  286 +
  287 + should "not append custom CSS and JS to response for a local error" do
  288 + assert_no_match /text\/css/, @response.body
  289 + assert_no_match /text\/javascript/, @response.body
  290 + end
  291 + end
  292 +
  293 + should "call session.to_hash if available" do
  294 + hash_data = {:key => :value}
  295 +
  296 + session = ActionController::TestSession.new
  297 + ActionController::TestSession.stubs(:new).returns(session)
  298 + session.stubs(:to_hash).returns(hash_data)
  299 +
  300 + process_action_with_automatic_notification
  301 + assert_received(session, :to_hash)
  302 + assert_received(session, :data) { |expect| expect.never }
  303 + assert_caught_and_sent
  304 + end
  305 +
  306 + should "call session.data if session.to_hash is undefined" do
  307 + hash_data = {:key => :value}
  308 +
  309 + session = ActionController::TestSession.new
  310 + ActionController::TestSession.stubs(:new).returns(session)
  311 + session.stubs(:data).returns(hash_data)
  312 + if session.respond_to?(:to_hash)
  313 + class << session
  314 + undef to_hash
  315 + end
  316 + end
  317 +
  318 + process_action_with_automatic_notification
  319 + assert_received(session, :to_hash) { |expect| expect.never }
  320 + assert_received(session, :data) { |expect| expect.at_least_once }
  321 + assert_caught_and_sent
  322 + end
  323 +
  324 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/configuration_test.rb 0 → 100644
... ... @@ -0,0 +1,208 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class ConfigurationTest < Test::Unit::TestCase
  4 +
  5 + include DefinesConstants
  6 +
  7 + should "provide default values" do
  8 + assert_config_default :proxy_host, nil
  9 + assert_config_default :proxy_port, nil
  10 + assert_config_default :proxy_user, nil
  11 + assert_config_default :proxy_pass, nil
  12 + assert_config_default :project_root, nil
  13 + assert_config_default :environment_name, nil
  14 + assert_config_default :logger, nil
  15 + assert_config_default :notifier_version, HoptoadNotifier::VERSION
  16 + assert_config_default :notifier_name, 'Hoptoad Notifier'
  17 + assert_config_default :notifier_url, 'http://hoptoadapp.com'
  18 + assert_config_default :secure, false
  19 + assert_config_default :host, 'hoptoadapp.com'
  20 + assert_config_default :http_open_timeout, 2
  21 + assert_config_default :http_read_timeout, 5
  22 + assert_config_default :ignore_by_filters, []
  23 + assert_config_default :ignore_user_agent, []
  24 + assert_config_default :params_filters,
  25 + HoptoadNotifier::Configuration::DEFAULT_PARAMS_FILTERS
  26 + assert_config_default :backtrace_filters,
  27 + HoptoadNotifier::Configuration::DEFAULT_BACKTRACE_FILTERS
  28 + assert_config_default :ignore,
  29 + HoptoadNotifier::Configuration::IGNORE_DEFAULT
  30 + assert_config_default :development_lookup, true
  31 + assert_config_default :framework, 'Standalone'
  32 + end
  33 +
  34 + should "provide default values for secure connections" do
  35 + config = HoptoadNotifier::Configuration.new
  36 + config.secure = true
  37 + assert_equal 443, config.port
  38 + assert_equal 'https', config.protocol
  39 + end
  40 +
  41 + should "provide default values for insecure connections" do
  42 + config = HoptoadNotifier::Configuration.new
  43 + config.secure = false
  44 + assert_equal 80, config.port
  45 + assert_equal 'http', config.protocol
  46 + end
  47 +
  48 + should "not cache inferred ports" do
  49 + config = HoptoadNotifier::Configuration.new
  50 + config.secure = false
  51 + config.port
  52 + config.secure = true
  53 + assert_equal 443, config.port
  54 + end
  55 +
  56 + should "allow values to be overwritten" do
  57 + assert_config_overridable :proxy_host
  58 + assert_config_overridable :proxy_port
  59 + assert_config_overridable :proxy_user
  60 + assert_config_overridable :proxy_pass
  61 + assert_config_overridable :secure
  62 + assert_config_overridable :host
  63 + assert_config_overridable :port
  64 + assert_config_overridable :http_open_timeout
  65 + assert_config_overridable :http_read_timeout
  66 + assert_config_overridable :project_root
  67 + assert_config_overridable :notifier_version
  68 + assert_config_overridable :notifier_name
  69 + assert_config_overridable :notifier_url
  70 + assert_config_overridable :environment_name
  71 + assert_config_overridable :development_lookup
  72 + assert_config_overridable :logger
  73 + end
  74 +
  75 + should "have an api key" do
  76 + assert_config_overridable :api_key
  77 + end
  78 +
  79 + should "act like a hash" do
  80 + config = HoptoadNotifier::Configuration.new
  81 + hash = config.to_hash
  82 + [:api_key, :backtrace_filters, :development_environments,
  83 + :environment_name, :host, :http_open_timeout,
  84 + :http_read_timeout, :ignore, :ignore_by_filters, :ignore_user_agent,
  85 + :notifier_name, :notifier_url, :notifier_version, :params_filters,
  86 + :project_root, :port, :protocol, :proxy_host, :proxy_pass, :proxy_port,
  87 + :proxy_user, :secure, :development_lookup].each do |option|
  88 + assert_equal config[option], hash[option], "Wrong value for #{option}"
  89 + end
  90 + end
  91 +
  92 + should "be mergable" do
  93 + config = HoptoadNotifier::Configuration.new
  94 + hash = config.to_hash
  95 + assert_equal hash.merge(:key => 'value'), config.merge(:key => 'value')
  96 + end
  97 +
  98 + should "allow param filters to be appended" do
  99 + assert_appends_value :params_filters
  100 + end
  101 +
  102 + should "warn when attempting to read environment filters" do
  103 + config = HoptoadNotifier::Configuration.new
  104 + config.
  105 + expects(:warn).
  106 + with(regexp_matches(/deprecated/i))
  107 + assert_equal [], config.environment_filters
  108 + end
  109 +
  110 + should "allow ignored user agents to be appended" do
  111 + assert_appends_value :ignore_user_agent
  112 + end
  113 +
  114 + should "allow backtrace filters to be appended" do
  115 + assert_appends_value(:backtrace_filters) do |config|
  116 + new_filter = lambda {}
  117 + config.filter_backtrace(&new_filter)
  118 + new_filter
  119 + end
  120 + end
  121 +
  122 + should "allow ignore by filters to be appended" do
  123 + assert_appends_value(:ignore_by_filters) do |config|
  124 + new_filter = lambda {}
  125 + config.ignore_by_filter(&new_filter)
  126 + new_filter
  127 + end
  128 + end
  129 +
  130 + should "allow ignored exceptions to be appended" do
  131 + config = HoptoadNotifier::Configuration.new
  132 + original_filters = config.ignore.dup
  133 + new_filter = 'hello'
  134 + config.ignore << new_filter
  135 + assert_same_elements original_filters + [new_filter], config.ignore
  136 + end
  137 +
  138 + should "allow ignored exceptions to be replaced" do
  139 + assert_replaces(:ignore, :ignore_only=)
  140 + end
  141 +
  142 + should "allow ignored user agents to be replaced" do
  143 + assert_replaces(:ignore_user_agent, :ignore_user_agent_only=)
  144 + end
  145 +
  146 + should "use development and test as development environments by default" do
  147 + config = HoptoadNotifier::Configuration.new
  148 + assert_same_elements %w(development test cucumber), config.development_environments
  149 + end
  150 +
  151 + should "be public in a public environment" do
  152 + config = HoptoadNotifier::Configuration.new
  153 + config.development_environments = %w(development)
  154 + config.environment_name = 'production'
  155 + assert config.public?
  156 + end
  157 +
  158 + should "not be public in a development environment" do
  159 + config = HoptoadNotifier::Configuration.new
  160 + config.development_environments = %w(staging)
  161 + config.environment_name = 'staging'
  162 + assert !config.public?
  163 + end
  164 +
  165 + should "be public without an environment name" do
  166 + config = HoptoadNotifier::Configuration.new
  167 + assert config.public?
  168 + end
  169 +
  170 + should "use the assigned logger if set" do
  171 + config = HoptoadNotifier::Configuration.new
  172 + config.logger = "CUSTOM LOGGER"
  173 + assert_equal "CUSTOM LOGGER", config.logger
  174 + end
  175 +
  176 + def assert_config_default(option, default_value, config = nil)
  177 + config ||= HoptoadNotifier::Configuration.new
  178 + assert_equal default_value, config.send(option)
  179 + end
  180 +
  181 + def assert_config_overridable(option, value = 'a value')
  182 + config = HoptoadNotifier::Configuration.new
  183 + config.send(:"#{option}=", value)
  184 + assert_equal value, config.send(option)
  185 + end
  186 +
  187 + def assert_appends_value(option, &block)
  188 + config = HoptoadNotifier::Configuration.new
  189 + original_values = config.send(option).dup
  190 + block ||= lambda do |config|
  191 + new_value = 'hello'
  192 + config.send(option) << new_value
  193 + new_value
  194 + end
  195 + new_value = block.call(config)
  196 + assert_same_elements original_values + [new_value], config.send(option)
  197 + end
  198 +
  199 + def assert_replaces(option, setter)
  200 + config = HoptoadNotifier::Configuration.new
  201 + new_value = 'hello'
  202 + config.send(setter, [new_value])
  203 + assert_equal [new_value], config.send(option)
  204 + config.send(setter, new_value)
  205 + assert_equal [new_value], config.send(option)
  206 + end
  207 +
  208 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/helper.rb 0 → 100644
... ... @@ -0,0 +1,239 @@
  1 +require 'test/unit'
  2 +require 'rubygems'
  3 +
  4 +gem 'jferris-mocha', '>= 0.9.5.0.1241126838'
  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 +
  9 +require 'shoulda'
  10 +require 'mocha'
  11 +
  12 +require 'ginger'
  13 +
  14 +require 'action_controller'
  15 +require 'action_controller/test_process'
  16 +require 'active_record'
  17 +require 'active_record/base'
  18 +require 'active_support'
  19 +require 'nokogiri'
  20 +require 'rack'
  21 +
  22 +require "hoptoad_notifier"
  23 +
  24 +begin require 'redgreen'; rescue LoadError; end
  25 +
  26 +module TestMethods
  27 + def rescue_action e
  28 + raise e
  29 + end
  30 +
  31 + def do_raise
  32 + raise "Hoptoad"
  33 + end
  34 +
  35 + def do_not_raise
  36 + render :text => "Success"
  37 + end
  38 +
  39 + def do_raise_ignored
  40 + raise ActiveRecord::RecordNotFound.new("404")
  41 + end
  42 +
  43 + def do_raise_not_ignored
  44 + raise ActiveRecord::StatementInvalid.new("Statement invalid")
  45 + end
  46 +
  47 + def manual_notify
  48 + notify_hoptoad(Exception.new)
  49 + render :text => "Success"
  50 + end
  51 +
  52 + def manual_notify_ignored
  53 + notify_hoptoad(ActiveRecord::RecordNotFound.new("404"))
  54 + render :text => "Success"
  55 + end
  56 +end
  57 +
  58 +class HoptoadController < ActionController::Base
  59 + include TestMethods
  60 +end
  61 +
  62 +class Test::Unit::TestCase
  63 + def request(action = nil, method = :get, user_agent = nil, params = {})
  64 + @request = ActionController::TestRequest.new
  65 + @request.action = action ? action.to_s : ""
  66 +
  67 + if user_agent
  68 + if @request.respond_to?(:user_agent=)
  69 + @request.user_agent = user_agent
  70 + else
  71 + @request.env["HTTP_USER_AGENT"] = user_agent
  72 + end
  73 + end
  74 + @request.query_parameters = @request.query_parameters.merge(params)
  75 + @response = ActionController::TestResponse.new
  76 + @controller.process(@request, @response)
  77 + end
  78 +
  79 + # Borrowed from ActiveSupport 2.3.2
  80 + def assert_difference(expression, difference = 1, message = nil, &block)
  81 + b = block.send(:binding)
  82 + exps = Array.wrap(expression)
  83 + before = exps.map { |e| eval(e, b) }
  84 +
  85 + yield
  86 +
  87 + exps.each_with_index do |e, i|
  88 + error = "#{e.inspect} didn't change by #{difference}"
  89 + error = "#{message}.\n#{error}" if message
  90 + assert_equal(before[i] + difference, eval(e, b), error)
  91 + end
  92 + end
  93 +
  94 + def assert_no_difference(expression, message = nil, &block)
  95 + assert_difference expression, 0, message, &block
  96 + end
  97 +
  98 + def stub_sender
  99 + stub('sender', :send_to_hoptoad => nil)
  100 + end
  101 +
  102 + def stub_sender!
  103 + HoptoadNotifier.sender = stub_sender
  104 + end
  105 +
  106 + def stub_notice
  107 + stub('notice', :to_xml => 'some yaml', :ignore? => false)
  108 + end
  109 +
  110 + def stub_notice!
  111 + returning stub_notice do |notice|
  112 + HoptoadNotifier::Notice.stubs(:new => notice)
  113 + end
  114 + end
  115 +
  116 + def create_dummy
  117 + HoptoadNotifier::DummySender.new
  118 + end
  119 +
  120 + def reset_config
  121 + HoptoadNotifier.configuration = nil
  122 + HoptoadNotifier.configure do |config|
  123 + config.api_key = 'abc123'
  124 + end
  125 + end
  126 +
  127 + def clear_backtrace_filters
  128 + HoptoadNotifier.configuration.backtrace_filters.clear
  129 + end
  130 +
  131 + def build_exception
  132 + raise
  133 + rescue => caught_exception
  134 + caught_exception
  135 + end
  136 +
  137 + def build_notice_data(exception = nil)
  138 + exception ||= build_exception
  139 + {
  140 + :api_key => 'abc123',
  141 + :error_class => exception.class.name,
  142 + :error_message => "#{exception.class.name}: #{exception.message}",
  143 + :backtrace => exception.backtrace,
  144 + :environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
  145 + :request => {
  146 + :params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
  147 + :rails_root => '/path/to/application',
  148 + :url => "http://test.host/users/1"
  149 + },
  150 + :session => {
  151 + :key => '123abc',
  152 + :data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
  153 + }
  154 + }
  155 + end
  156 +
  157 + def assert_caught_and_sent
  158 + assert !HoptoadNotifier.sender.collected.empty?
  159 + end
  160 +
  161 + def assert_caught_and_not_sent
  162 + assert HoptoadNotifier.sender.collected.empty?
  163 + end
  164 +
  165 + def assert_array_starts_with(expected, actual)
  166 + assert_respond_to actual, :to_ary
  167 + array = actual.to_ary.reverse
  168 + expected.reverse.each_with_index do |value, i|
  169 + assert_equal value, array[i]
  170 + end
  171 + end
  172 +
  173 + def assert_valid_node(document, xpath, content)
  174 + nodes = document.xpath(xpath)
  175 + assert nodes.any?{|node| node.content == content },
  176 + "Expected xpath #{xpath} to have content #{content}, " +
  177 + "but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
  178 + "Document:\n#{document.to_s}"
  179 + end
  180 +end
  181 +
  182 +module DefinesConstants
  183 + def setup
  184 + @defined_constants = []
  185 + end
  186 +
  187 + def teardown
  188 + @defined_constants.each do |constant|
  189 + Object.__send__(:remove_const, constant)
  190 + end
  191 + end
  192 +
  193 + def define_constant(name, value)
  194 + Object.const_set(name, value)
  195 + @defined_constants << name
  196 + end
  197 +end
  198 +
  199 +# Also stolen from AS 2.3.2
  200 +class Array
  201 + # Wraps the object in an Array unless it's an Array. Converts the
  202 + # object to an Array using #to_ary if it implements that.
  203 + def self.wrap(object)
  204 + case object
  205 + when nil
  206 + []
  207 + when self
  208 + object
  209 + else
  210 + if object.respond_to?(:to_ary)
  211 + object.to_ary
  212 + else
  213 + [object]
  214 + end
  215 + end
  216 + end
  217 +
  218 +end
  219 +
  220 +class CollectingSender
  221 + attr_reader :collected
  222 +
  223 + def initialize
  224 + @collected = []
  225 + end
  226 +
  227 + def send_to_hoptoad(data)
  228 + @collected << data
  229 + end
  230 +end
  231 +
  232 +class FakeLogger
  233 + def info(*args); end
  234 + def debug(*args); end
  235 + def warn(*args); end
  236 + def error(*args); end
  237 + def fatal(*args); end
  238 +end
  239 +
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/hoptoad_tasks_test.rb 0 → 100644
... ... @@ -0,0 +1,138 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +require 'rubygems'
  3 +
  4 +require File.dirname(__FILE__) + '/../lib/hoptoad_tasks'
  5 +require 'fakeweb'
  6 +
  7 +FakeWeb.allow_net_connect = false
  8 +
  9 +class HoptoadTasksTest < Test::Unit::TestCase
  10 + def successful_response(body = "")
  11 + response = Net::HTTPSuccess.new('1.2', '200', 'OK')
  12 + response.stubs(:body).returns(body)
  13 + return response
  14 + end
  15 +
  16 + def unsuccessful_response(body = "")
  17 + response = Net::HTTPClientError.new('1.2', '200', 'OK')
  18 + response.stubs(:body).returns(body)
  19 + return response
  20 + end
  21 +
  22 + context "being quiet" do
  23 + setup { HoptoadTasks.stubs(:puts) }
  24 +
  25 + context "in a configured project" do
  26 + setup { HoptoadNotifier.configure { |config| config.api_key = "1234123412341234" } }
  27 +
  28 + context "on deploy({})" do
  29 + setup { @output = HoptoadTasks.deploy({}) }
  30 +
  31 + before_should "complain about missing rails env" do
  32 + HoptoadTasks.expects(:puts).with(regexp_matches(/rails environment/i))
  33 + end
  34 +
  35 + should "return false" do
  36 + assert !@output
  37 + end
  38 + end
  39 +
  40 + context "given valid options" do
  41 + setup { @options = {:rails_env => "staging"} }
  42 +
  43 + context "on deploy(options)" do
  44 + setup { @output = HoptoadTasks.deploy(@options) }
  45 +
  46 + before_should "post to http://hoptoadapp.com/deploys.txt" do
  47 + URI.stubs(:parse).with('http://hoptoadapp.com/deploys.txt').returns(:uri)
  48 + Net::HTTP.expects(:post_form).with(:uri, kind_of(Hash)).returns(successful_response)
  49 + end
  50 +
  51 + before_should "use the project api key" do
  52 + Net::HTTP.expects(:post_form).
  53 + with(kind_of(URI), has_entries('api_key' => "1234123412341234")).
  54 + returns(successful_response)
  55 + end
  56 +
  57 + before_should "use send the rails_env param" do
  58 + Net::HTTP.expects(:post_form).
  59 + with(kind_of(URI), has_entries("deploy[rails_env]" => "staging")).
  60 + returns(successful_response)
  61 + end
  62 +
  63 + [:local_username, :scm_repository, :scm_revision].each do |key|
  64 + before_should "use send the #{key} param if it's passed in." do
  65 + @options[key] = "value"
  66 + Net::HTTP.expects(:post_form).
  67 + with(kind_of(URI), has_entries("deploy[#{key}]" => "value")).
  68 + returns(successful_response)
  69 + end
  70 + end
  71 +
  72 + before_should "use the :api_key param if it's passed in." do
  73 + @options[:api_key] = "value"
  74 + Net::HTTP.expects(:post_form).
  75 + with(kind_of(URI), has_entries("api_key" => "value")).
  76 + returns(successful_response)
  77 + end
  78 +
  79 + before_should "puts the response body on success" do
  80 + HoptoadTasks.expects(:puts).with("body")
  81 + Net::HTTP.expects(:post_form).with(any_parameters).returns(successful_response('body'))
  82 + end
  83 +
  84 + before_should "puts the response body on failure" do
  85 + HoptoadTasks.expects(:puts).with("body")
  86 + Net::HTTP.expects(:post_form).with(any_parameters).returns(unsuccessful_response('body'))
  87 + end
  88 +
  89 + should "return false on failure", :before => lambda {
  90 + Net::HTTP.expects(:post_form).with(any_parameters).returns(unsuccessful_response('body'))
  91 + } do
  92 + assert !@output
  93 + end
  94 +
  95 + should "return true on success", :before => lambda {
  96 + Net::HTTP.expects(:post_form).with(any_parameters).returns(successful_response('body'))
  97 + } do
  98 + assert @output
  99 + end
  100 + end
  101 + end
  102 + end
  103 +
  104 + context "in a configured project with custom host" do
  105 + setup do
  106 + HoptoadNotifier.configure do |config|
  107 + config.api_key = "1234123412341234"
  108 + config.host = "custom.host"
  109 + end
  110 + end
  111 +
  112 + context "on deploy(:rails_env => 'staging')" do
  113 + setup { @output = HoptoadTasks.deploy(:rails_env => "staging") }
  114 +
  115 + before_should "post to the custom host" do
  116 + URI.stubs(:parse).with('http://custom.host/deploys.txt').returns(:uri)
  117 + Net::HTTP.expects(:post_form).with(:uri, kind_of(Hash)).returns(successful_response)
  118 + end
  119 + end
  120 + end
  121 +
  122 + context "when not configured" do
  123 + setup { HoptoadNotifier.configure { |config| config.api_key = "" } }
  124 +
  125 + context "on deploy(:rails_env => 'staging')" do
  126 + setup { @output = HoptoadTasks.deploy(:rails_env => "staging") }
  127 +
  128 + before_should "complain about missing api key" do
  129 + HoptoadTasks.expects(:puts).with(regexp_matches(/api key/i))
  130 + end
  131 +
  132 + should "return false" do
  133 + assert !@output
  134 + end
  135 + end
  136 + end
  137 + end
  138 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/logger_test.rb 0 → 100644
... ... @@ -0,0 +1,85 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class LoggerTest < Test::Unit::TestCase
  4 + def stub_http(response, body = nil)
  5 + response.stubs(:body => body) if body
  6 + @http = stub(:post => response,
  7 + :read_timeout= => nil,
  8 + :open_timeout= => nil,
  9 + :use_ssl= => nil)
  10 + Net::HTTP.stubs(:new).returns(@http)
  11 + end
  12 +
  13 + def send_notice
  14 + HoptoadNotifier.sender.send_to_hoptoad('data')
  15 + end
  16 +
  17 + def stub_verbose_log
  18 + HoptoadNotifier.stubs(:write_verbose_log)
  19 + end
  20 +
  21 + def assert_logged(expected)
  22 + assert_received(HoptoadNotifier, :write_verbose_log) do |expect|
  23 + expect.with {|actual| actual =~ expected }
  24 + end
  25 + end
  26 +
  27 + def assert_not_logged(expected)
  28 + assert_received(HoptoadNotifier, :write_verbose_log) do |expect|
  29 + expect.with {|actual| actual =~ expected }.never
  30 + end
  31 + end
  32 +
  33 + def configure
  34 + HoptoadNotifier.configure { |config| }
  35 + end
  36 +
  37 + should "report that notifier is ready when configured" do
  38 + stub_verbose_log
  39 + configure
  40 + assert_logged /Notifier (.*) ready/
  41 + end
  42 +
  43 + should "not report that notifier is ready when internally configured" do
  44 + stub_verbose_log
  45 + HoptoadNotifier.configure(true) { |config| }
  46 + assert_not_logged /.*/
  47 + end
  48 +
  49 + should "print environment info a successful notification without a body" do
  50 + reset_config
  51 + stub_verbose_log
  52 + stub_http(Net::HTTPSuccess)
  53 + send_notice
  54 + assert_logged /Environment Info:/
  55 + assert_not_logged /Response from Hoptoad:/
  56 + end
  57 +
  58 + should "print environment info on a failed notification without a body" do
  59 + reset_config
  60 + stub_verbose_log
  61 + stub_http(Net::HTTPError)
  62 + send_notice
  63 + assert_logged /Environment Info:/
  64 + assert_not_logged /Response from Hoptoad:/
  65 + end
  66 +
  67 + should "print environment info and response on a success with a body" do
  68 + reset_config
  69 + stub_verbose_log
  70 + stub_http(Net::HTTPSuccess, 'test')
  71 + send_notice
  72 + assert_logged /Environment Info:/
  73 + assert_logged /Response from Hoptoad:/
  74 + end
  75 +
  76 + should "print environment info and response on a failure with a body" do
  77 + reset_config
  78 + stub_verbose_log
  79 + stub_http(Net::HTTPError, 'test')
  80 + send_notice
  81 + assert_logged /Environment Info:/
  82 + assert_logged /Response from Hoptoad:/
  83 + end
  84 +
  85 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/notice_test.rb 0 → 100644
... ... @@ -0,0 +1,417 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class NoticeTest < Test::Unit::TestCase
  4 +
  5 + include DefinesConstants
  6 +
  7 + def configure
  8 + returning HoptoadNotifier::Configuration.new do |config|
  9 + config.api_key = 'abc123def456'
  10 + end
  11 + end
  12 +
  13 + def build_notice(args = {})
  14 + configuration = args.delete(:configuration) || configure
  15 + HoptoadNotifier::Notice.new(configuration.merge(args))
  16 + end
  17 +
  18 + def stub_request(attrs = {})
  19 + stub('request', { :parameters => { 'one' => 'two' },
  20 + :protocol => 'http',
  21 + :host => 'some.host',
  22 + :request_uri => '/some/uri',
  23 + :session => { :to_hash => { 'a' => 'b' } },
  24 + :env => { 'three' => 'four' } }.update(attrs))
  25 + end
  26 +
  27 + should "set the api key" do
  28 + api_key = 'key'
  29 + notice = build_notice(:api_key => api_key)
  30 + assert_equal api_key, notice.api_key
  31 + end
  32 +
  33 + should "accept a project root" do
  34 + project_root = '/path/to/project'
  35 + notice = build_notice(:project_root => project_root)
  36 + assert_equal project_root, notice.project_root
  37 + end
  38 +
  39 + should "accept a component" do
  40 + assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
  41 + end
  42 +
  43 + should "alias the component as controller" do
  44 + assert_equal 'users_controller', build_notice(:controller => 'users_controller').component
  45 + assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
  46 + end
  47 +
  48 + should "accept a action" do
  49 + assert_equal 'index', build_notice(:action => 'index').action
  50 + end
  51 +
  52 + should "accept a url" do
  53 + url = 'http://some.host/uri'
  54 + notice = build_notice(:url => url)
  55 + assert_equal url, notice.url
  56 + end
  57 +
  58 + should "accept a backtrace from an exception or hash" do
  59 + array = ["user.rb:34:in `crazy'"]
  60 + exception = build_exception
  61 + exception.set_backtrace array
  62 + backtrace = HoptoadNotifier::Backtrace.parse(array)
  63 + notice_from_exception = build_notice(:exception => exception)
  64 +
  65 +
  66 + assert_equal backtrace,
  67 + notice_from_exception.backtrace,
  68 + "backtrace was not correctly set from an exception"
  69 +
  70 + notice_from_hash = build_notice(:backtrace => array)
  71 + assert_equal backtrace,
  72 + notice_from_hash.backtrace,
  73 + "backtrace was not correctly set from a hash"
  74 + end
  75 +
  76 + should "pass its backtrace filters for parsing" do
  77 + backtrace_array = ['my/file/backtrace:3']
  78 + exception = build_exception
  79 + exception.set_backtrace(backtrace_array)
  80 + HoptoadNotifier::Backtrace.expects(:parse).with(backtrace_array, {:filters => 'foo'})
  81 +
  82 + notice = HoptoadNotifier::Notice.new({:exception => exception, :backtrace_filters => 'foo'})
  83 + end
  84 +
  85 + should "set the error class from an exception or hash" do
  86 + assert_accepts_exception_attribute :error_class do |exception|
  87 + exception.class.name
  88 + end
  89 + end
  90 +
  91 + should "set the error message from an exception or hash" do
  92 + assert_accepts_exception_attribute :error_message do |exception|
  93 + "#{exception.class.name}: #{exception.message}"
  94 + end
  95 + end
  96 +
  97 + should "accept parameters from a request or hash" do
  98 + parameters = { 'one' => 'two' }
  99 + notice_from_hash = build_notice(:parameters => parameters)
  100 + assert_equal notice_from_hash.parameters, parameters
  101 + end
  102 +
  103 + should "accept session data from a session[:data] hash" do
  104 + data = { 'one' => 'two' }
  105 + notice = build_notice(:session => { :data => data })
  106 + assert_equal data, notice.session_data
  107 + end
  108 +
  109 + should "accept session data from a session_data hash" do
  110 + data = { 'one' => 'two' }
  111 + notice = build_notice(:session_data => data)
  112 + assert_equal data, notice.session_data
  113 + end
  114 +
  115 + should "accept an environment name" do
  116 + assert_equal 'development', build_notice(:environment_name => 'development').environment_name
  117 + end
  118 +
  119 + should "accept CGI data from a hash" do
  120 + data = { 'string' => 'value' }
  121 + notice = build_notice(:cgi_data => data)
  122 + assert_equal data, notice.cgi_data, "should take CGI data from a hash"
  123 + end
  124 +
  125 + should "accept notifier information" do
  126 + params = { :notifier_name => 'a name for a notifier',
  127 + :notifier_version => '1.0.5',
  128 + :notifier_url => 'http://notifiers.r.us/download' }
  129 + notice = build_notice(params)
  130 + assert_equal params[:notifier_name], notice.notifier_name
  131 + assert_equal params[:notifier_version], notice.notifier_version
  132 + assert_equal params[:notifier_url], notice.notifier_url
  133 + end
  134 +
  135 + should "set sensible defaults without an exception" do
  136 + backtrace = HoptoadNotifier::Backtrace.parse(build_backtrace_array)
  137 + notice = build_notice(:backtrace => build_backtrace_array)
  138 +
  139 + assert_equal 'Notification', notice.error_message
  140 + assert_array_starts_with backtrace.lines, notice.backtrace.lines
  141 + assert_equal({}, notice.parameters)
  142 + assert_equal({}, notice.session_data)
  143 + end
  144 +
  145 + should "use the caller as the backtrace for an exception without a backtrace" do
  146 + filters = HoptoadNotifier::Configuration.new.backtrace_filters
  147 + backtrace = HoptoadNotifier::Backtrace.parse(caller, :filters => filters)
  148 + notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
  149 +
  150 + assert_array_starts_with backtrace.lines, notice.backtrace.lines
  151 + end
  152 +
  153 + should "convert unserializable objects to strings" do
  154 + assert_serializes_hash(:parameters)
  155 + assert_serializes_hash(:cgi_data)
  156 + assert_serializes_hash(:session_data)
  157 + end
  158 +
  159 + should "filter parameters" do
  160 + assert_filters_hash(:parameters)
  161 + end
  162 +
  163 + should "filter cgi data" do
  164 + assert_filters_hash(:cgi_data)
  165 + end
  166 +
  167 + context "a Notice turned into XML" do
  168 + setup do
  169 + HoptoadNotifier.configure do |config|
  170 + config.api_key = "1234567890"
  171 + end
  172 +
  173 + @exception = build_exception
  174 +
  175 + @notice = build_notice({
  176 + :notifier_name => 'a name',
  177 + :notifier_version => '1.2.3',
  178 + :notifier_url => 'http://some.url/path',
  179 + :exception => @exception,
  180 + :controller => "controller",
  181 + :action => "action",
  182 + :url => "http://url.com",
  183 + :parameters => { "paramskey" => "paramsvalue",
  184 + "nestparentkey" => { "nestkey" => "nestvalue" } },
  185 + :session_data => { "sessionkey" => "sessionvalue" },
  186 + :cgi_data => { "cgikey" => "cgivalue" },
  187 + :project_root => "RAILS_ROOT",
  188 + :environment_name => "RAILS_ENV"
  189 + })
  190 +
  191 + @xml = @notice.to_xml
  192 +
  193 + @document = Nokogiri::XML::Document.parse(@xml)
  194 + end
  195 +
  196 + should "validate against the XML schema" do
  197 + assert_valid_notice_document @document
  198 + end
  199 +
  200 + should "serialize a Notice to XML when sent #to_xml" do
  201 + assert_valid_node(@document, "//api-key", @notice.api_key)
  202 +
  203 + assert_valid_node(@document, "//notifier/name", @notice.notifier_name)
  204 + assert_valid_node(@document, "//notifier/version", @notice.notifier_version)
  205 + assert_valid_node(@document, "//notifier/url", @notice.notifier_url)
  206 +
  207 + assert_valid_node(@document, "//error/class", @notice.error_class)
  208 + assert_valid_node(@document, "//error/message", @notice.error_message)
  209 +
  210 + assert_valid_node(@document, "//error/backtrace/line/@number", @notice.backtrace.lines.first.number)
  211 + assert_valid_node(@document, "//error/backtrace/line/@file", @notice.backtrace.lines.first.file)
  212 + assert_valid_node(@document, "//error/backtrace/line/@method", @notice.backtrace.lines.first.method)
  213 +
  214 + assert_valid_node(@document, "//request/url", @notice.url)
  215 + assert_valid_node(@document, "//request/component", @notice.controller)
  216 + assert_valid_node(@document, "//request/action", @notice.action)
  217 +
  218 + assert_valid_node(@document, "//request/params/var/@key", "paramskey")
  219 + assert_valid_node(@document, "//request/params/var", "paramsvalue")
  220 + assert_valid_node(@document, "//request/params/var/@key", "nestparentkey")
  221 + assert_valid_node(@document, "//request/params/var/var/@key", "nestkey")
  222 + assert_valid_node(@document, "//request/params/var/var", "nestvalue")
  223 + assert_valid_node(@document, "//request/session/var/@key", "sessionkey")
  224 + assert_valid_node(@document, "//request/session/var", "sessionvalue")
  225 + assert_valid_node(@document, "//request/cgi-data/var/@key", "cgikey")
  226 + assert_valid_node(@document, "//request/cgi-data/var", "cgivalue")
  227 +
  228 + assert_valid_node(@document, "//server-environment/project-root", "RAILS_ROOT")
  229 + assert_valid_node(@document, "//server-environment/environment-name", "RAILS_ENV")
  230 + end
  231 + end
  232 +
  233 + should "not send empty request data" do
  234 + notice = build_notice
  235 + assert_nil notice.url
  236 + assert_nil notice.controller
  237 + assert_nil notice.action
  238 +
  239 + xml = notice.to_xml
  240 + document = Nokogiri::XML.parse(xml)
  241 + assert_nil document.at('//request/url')
  242 + assert_nil document.at('//request/component')
  243 + assert_nil document.at('//request/action')
  244 +
  245 + assert_valid_notice_document document
  246 + end
  247 +
  248 + %w(url controller action).each do |var|
  249 + should "send a request if #{var} is present" do
  250 + notice = build_notice(var.to_sym => 'value')
  251 + xml = notice.to_xml
  252 + document = Nokogiri::XML.parse(xml)
  253 + assert_not_nil document.at('//request')
  254 + end
  255 + end
  256 +
  257 + %w(parameters cgi_data session_data).each do |var|
  258 + should "send a request if #{var} is present" do
  259 + notice = build_notice(var.to_sym => { 'key' => 'value' })
  260 + xml = notice.to_xml
  261 + document = Nokogiri::XML.parse(xml)
  262 + assert_not_nil document.at('//request')
  263 + end
  264 + end
  265 +
  266 + should "not ignore an exception not matching ignore filters" do
  267 + notice = build_notice(:error_class => 'ArgumentError',
  268 + :ignore => ['Argument'],
  269 + :ignore_by_filters => [lambda { |notice| false }])
  270 + assert !notice.ignore?
  271 + end
  272 +
  273 + should "ignore an exception with a matching error class" do
  274 + notice = build_notice(:error_class => 'ArgumentError',
  275 + :ignore => [ArgumentError])
  276 + assert notice.ignore?
  277 + end
  278 +
  279 + should "ignore an exception with a matching error class name" do
  280 + notice = build_notice(:error_class => 'ArgumentError',
  281 + :ignore => ['ArgumentError'])
  282 + assert notice.ignore?
  283 + end
  284 +
  285 + should "ignore an exception with a matching filter" do
  286 + filter = lambda {|notice| notice.error_class == 'ArgumentError' }
  287 + notice = build_notice(:error_class => 'ArgumentError',
  288 + :ignore_by_filters => [filter])
  289 + assert notice.ignore?
  290 + end
  291 +
  292 + should "not raise without an ignore list" do
  293 + notice = build_notice(:ignore => nil, :ignore_by_filters => nil)
  294 + assert_nothing_raised do
  295 + notice.ignore?
  296 + end
  297 + end
  298 +
  299 + should "ignore RecordNotFound error by default" do
  300 + notice = build_notice(:error_class => 'ActiveRecord::RecordNotFound')
  301 + assert notice.ignore?
  302 + end
  303 +
  304 + should "ignore RoutingError error by default" do
  305 + notice = build_notice(:error_class => 'ActionController::RoutingError')
  306 + assert notice.ignore?
  307 + end
  308 +
  309 + should "ignore InvalidAuthenticityToken error by default" do
  310 + notice = build_notice(:error_class => 'ActionController::InvalidAuthenticityToken')
  311 + assert notice.ignore?
  312 + end
  313 +
  314 + should "ignore TamperedWithCookie error by default" do
  315 + notice = build_notice(:error_class => 'CGI::Session::CookieStore::TamperedWithCookie')
  316 + assert notice.ignore?
  317 + end
  318 +
  319 + should "ignore UnknownAction error by default" do
  320 + notice = build_notice(:error_class => 'ActionController::UnknownAction')
  321 + assert notice.ignore?
  322 + end
  323 +
  324 + should "act like a hash" do
  325 + notice = build_notice(:error_message => 'some message')
  326 + assert_equal notice.error_message, notice[:error_message]
  327 + end
  328 +
  329 + should "return params on notice[:request][:params]" do
  330 + params = { 'one' => 'two' }
  331 + notice = build_notice(:parameters => params)
  332 + assert_equal params, notice[:request][:params]
  333 + end
  334 +
  335 + should "ensure #to_hash is called on objects that support it" do
  336 + assert_nothing_raised do
  337 + build_notice(:session => { :object => stub(:to_hash => {}) })
  338 + end
  339 + end
  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 +
  356 + def assert_accepts_exception_attribute(attribute, args = {}, &block)
  357 + exception = build_exception
  358 + block ||= lambda { exception.send(attribute) }
  359 + value = block.call(exception)
  360 +
  361 + notice_from_exception = build_notice(args.merge(:exception => exception))
  362 +
  363 + assert_equal notice_from_exception.send(attribute),
  364 + value,
  365 + "#{attribute} was not correctly set from an exception"
  366 +
  367 + notice_from_hash = build_notice(args.merge(attribute => value))
  368 + assert_equal notice_from_hash.send(attribute),
  369 + value,
  370 + "#{attribute} was not correctly set from a hash"
  371 + end
  372 +
  373 + def assert_serializes_hash(attribute)
  374 + [File.open(__FILE__), Proc.new { puts "boo!" }, Module.new].each do |object|
  375 + hash = {
  376 + :strange_object => object,
  377 + :sub_hash => {
  378 + :sub_object => object
  379 + },
  380 + :array => [object]
  381 + }
  382 + notice = build_notice(attribute => hash)
  383 + hash = notice.send(attribute)
  384 + assert_equal object.to_s, hash[:strange_object], "objects should be serialized"
  385 + assert_kind_of Hash, hash[:sub_hash], "subhashes should be kept"
  386 + assert_equal object.to_s, hash[:sub_hash][:sub_object], "subhash members should be serialized"
  387 + assert_kind_of Array, hash[:array], "arrays should be kept"
  388 + assert_equal object.to_s, hash[:array].first, "array members should be serialized"
  389 + end
  390 + end
  391 +
  392 + def assert_valid_notice_document(document)
  393 + xsd_path = File.join(File.dirname(__FILE__), "hoptoad_2_0.xsd")
  394 + schema = Nokogiri::XML::Schema.new(IO.read(xsd_path))
  395 + errors = schema.validate(document)
  396 + assert errors.empty?, errors.collect{|e| e.message }.join
  397 + end
  398 +
  399 + def assert_filters_hash(attribute)
  400 + filters = %w(abc def)
  401 + original = { 'abc' => "123", 'def' => "456", 'ghi' => "789", 'nested' => { 'abc' => '100' } }
  402 + filtered = { 'abc' => "[FILTERED]",
  403 + 'def' => "[FILTERED]",
  404 + 'ghi' => "789",
  405 + 'nested' => { 'abc' => '[FILTERED]' } }
  406 +
  407 + notice = build_notice(:params_filters => filters, attribute => original)
  408 +
  409 + assert_equal(filtered,
  410 + notice.send(attribute))
  411 + end
  412 +
  413 + def build_backtrace_array
  414 + ["app/models/user.rb:13:in `magic'",
  415 + "app/controllers/users_controller.rb:8:in `index'"]
  416 + end
  417 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/notifier_test.rb 0 → 100644
... ... @@ -0,0 +1,222 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class NotifierTest < Test::Unit::TestCase
  4 +
  5 + class OriginalException < Exception
  6 + end
  7 +
  8 + class ContinuedException < Exception
  9 + end
  10 +
  11 + include DefinesConstants
  12 +
  13 + def setup
  14 + super
  15 + reset_config
  16 + end
  17 +
  18 + def assert_sent(notice, notice_args)
  19 + assert_received(HoptoadNotifier::Notice, :new) {|expect| expect.with(has_entries(notice_args)) }
  20 + assert_received(notice, :to_xml)
  21 + assert_received(HoptoadNotifier.sender, :send_to_hoptoad) {|expect| expect.with(notice.to_xml) }
  22 + end
  23 +
  24 + def set_public_env
  25 + HoptoadNotifier.configure { |config| config.environment_name = 'production' }
  26 + end
  27 +
  28 + def set_development_env
  29 + HoptoadNotifier.configure { |config| config.environment_name = 'development' }
  30 + end
  31 +
  32 + should "yield and save a configuration when configuring" do
  33 + yielded_configuration = nil
  34 + HoptoadNotifier.configure do |config|
  35 + yielded_configuration = config
  36 + end
  37 +
  38 + assert_kind_of HoptoadNotifier::Configuration, yielded_configuration
  39 + assert_equal yielded_configuration, HoptoadNotifier.configuration
  40 + end
  41 +
  42 + should "not remove existing config options when configuring twice" do
  43 + first_config = nil
  44 + HoptoadNotifier.configure do |config|
  45 + first_config = config
  46 + end
  47 + HoptoadNotifier.configure do |config|
  48 + assert_equal first_config, config
  49 + end
  50 + end
  51 +
  52 + should "configure the sender" do
  53 + sender = stub_sender
  54 + HoptoadNotifier::Sender.stubs(:new => sender)
  55 + configuration = nil
  56 +
  57 + HoptoadNotifier.configure { |yielded_config| configuration = yielded_config }
  58 +
  59 + assert_received(HoptoadNotifier::Sender, :new) { |expect| expect.with(configuration) }
  60 + assert_equal sender, HoptoadNotifier.sender
  61 + end
  62 +
  63 + should "create and send a notice for an exception" do
  64 + set_public_env
  65 + exception = build_exception
  66 + stub_sender!
  67 + notice = stub_notice!
  68 +
  69 + HoptoadNotifier.notify(exception)
  70 +
  71 + assert_sent notice, :exception => exception
  72 + end
  73 +
  74 + should "create and send a notice for a hash" do
  75 + set_public_env
  76 + notice = stub_notice!
  77 + notice_args = { :error_message => 'uh oh' }
  78 + stub_sender!
  79 +
  80 + HoptoadNotifier.notify(notice_args)
  81 +
  82 + assert_sent(notice, notice_args)
  83 + end
  84 +
  85 + should "create and sent a notice for an exception and hash" do
  86 + set_public_env
  87 + exception = build_exception
  88 + notice = stub_notice!
  89 + notice_args = { :error_message => 'uh oh' }
  90 + stub_sender!
  91 +
  92 + HoptoadNotifier.notify(exception, notice_args)
  93 +
  94 + assert_sent(notice, notice_args.merge(:exception => exception))
  95 + end
  96 +
  97 + should "not create a notice in a development environment" do
  98 + set_development_env
  99 + sender = stub_sender!
  100 +
  101 + HoptoadNotifier.notify(build_exception)
  102 + HoptoadNotifier.notify_or_ignore(build_exception)
  103 +
  104 + assert_received(sender, :send_to_hoptoad) {|expect| expect.never }
  105 + end
  106 +
  107 + should "not deliver an ignored exception when notifying implicitly" do
  108 + set_public_env
  109 + exception = build_exception
  110 + sender = stub_sender!
  111 + notice = stub_notice!
  112 + notice.stubs(:ignore? => true)
  113 +
  114 + HoptoadNotifier.notify_or_ignore(exception)
  115 +
  116 + assert_received(sender, :send_to_hoptoad) {|expect| expect.never }
  117 + end
  118 +
  119 + should "deliver an ignored exception when notifying manually" do
  120 + set_public_env
  121 + exception = build_exception
  122 + sender = stub_sender!
  123 + notice = stub_notice!
  124 + notice.stubs(:ignore? => true)
  125 +
  126 + HoptoadNotifier.notify(exception)
  127 +
  128 + assert_sent(notice, :exception => exception)
  129 + end
  130 +
  131 + should "pass config to created notices" do
  132 + exception = build_exception
  133 + config_opts = { 'one' => 'two', 'three' => 'four' }
  134 + notice = stub_notice!
  135 + stub_sender!
  136 + HoptoadNotifier.configuration = stub('config', :merge => config_opts, :public? => true)
  137 +
  138 + HoptoadNotifier.notify(exception)
  139 +
  140 + assert_received(HoptoadNotifier::Notice, :new) do |expect|
  141 + expect.with(has_entries(config_opts))
  142 + end
  143 + end
  144 +
  145 + context "building notice JSON for an exception" do
  146 + setup do
  147 + @params = { :controller => "users", :action => "create" }
  148 + @exception = build_exception
  149 + @hash = HoptoadNotifier.build_lookup_hash_for(@exception, @params)
  150 + end
  151 +
  152 + should "set action" do
  153 + assert_equal @params[:action], @hash[:action]
  154 + end
  155 +
  156 + should "set controller" do
  157 + assert_equal @params[:controller], @hash[:component]
  158 + end
  159 +
  160 + should "set line number" do
  161 + assert @hash[:line_number] =~ /\d+/
  162 + end
  163 +
  164 + should "set file" do
  165 + assert_match /test\/helper\.rb$/, @hash[:file]
  166 + end
  167 +
  168 + should "set rails_env to production" do
  169 + assert_equal 'production', @hash[:environment_name]
  170 + end
  171 +
  172 + should "set error class" do
  173 + assert_equal 'RuntimeError', @hash[:error_class]
  174 + end
  175 +
  176 + should "not set file or line number with no backtrace" do
  177 + @exception.stubs(:backtrace).returns([])
  178 +
  179 + @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
  180 +
  181 + assert_nil @hash[:line_number]
  182 + assert_nil @hash[:file]
  183 + end
  184 +
  185 + should "not set action or controller when not provided" do
  186 + @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
  187 +
  188 + assert_nil @hash[:action]
  189 + assert_nil @hash[:controller]
  190 + end
  191 +
  192 + context "when an exception that provides #original_exception is raised" do
  193 + setup do
  194 + @exception.stubs(:original_exception).returns(begin
  195 + raise NotifierTest::OriginalException.new
  196 + rescue Exception => e
  197 + e
  198 + end)
  199 + end
  200 +
  201 + should "unwrap exceptions that provide #original_exception" do
  202 + @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
  203 + assert_equal "NotifierTest::OriginalException", @hash[:error_class]
  204 + end
  205 + end
  206 +
  207 + context "when an exception that provides #continued_exception is raised" do
  208 + setup do
  209 + @exception.stubs(:continued_exception).returns(begin
  210 + raise NotifierTest::ContinuedException.new
  211 + rescue Exception => e
  212 + e
  213 + end)
  214 + end
  215 +
  216 + should "unwrap exceptions that provide #continued_exception" do
  217 + @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
  218 + assert_equal "NotifierTest::ContinuedException", @hash[:error_class]
  219 + end
  220 + end
  221 + end
  222 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/rack_test.rb 0 → 100644
... ... @@ -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
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/rails_initializer_test.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +require 'hoptoad_notifier/rails'
  4 +
  5 +class RailsInitializerTest < Test::Unit::TestCase
  6 + include DefinesConstants
  7 +
  8 + should "trigger use of Rails' logger if logger isn't set and Rails' logger exists" do
  9 + rails = Module.new do
  10 + def self.logger
  11 + "RAILS LOGGER"
  12 + end
  13 + end
  14 + define_constant("Rails", rails)
  15 + HoptoadNotifier::Rails.initialize
  16 + assert_equal "RAILS LOGGER", HoptoadNotifier.logger
  17 + end
  18 +
  19 + should "trigger use of Rails' default logger if logger isn't set and Rails.logger doesn't exist" do
  20 + define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
  21 +
  22 + HoptoadNotifier::Rails.initialize
  23 + assert_equal "RAILS DEFAULT LOGGER", HoptoadNotifier.logger
  24 + end
  25 +
  26 + should "allow overriding of the logger if already assigned" do
  27 + define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
  28 + HoptoadNotifier::Rails.initialize
  29 +
  30 + HoptoadNotifier.configure(true) do |config|
  31 + config.logger = "OVERRIDDEN LOGGER"
  32 + end
  33 +
  34 + assert_equal "OVERRIDDEN LOGGER", HoptoadNotifier.logger
  35 + end
  36 +end
... ...
vendor/gems/hoptoad_notifier-2.2.2/test/sender_test.rb 0 → 100644
... ... @@ -0,0 +1,123 @@
  1 +require File.dirname(__FILE__) + '/helper'
  2 +
  3 +class SenderTest < Test::Unit::TestCase
  4 +
  5 + def setup
  6 + reset_config
  7 + end
  8 +
  9 + def build_sender(opts = {})
  10 + config = HoptoadNotifier::Configuration.new
  11 + opts.each {|opt, value| config.send(:"#{opt}=", value) }
  12 + HoptoadNotifier::Sender.new(config)
  13 + end
  14 +
  15 + def send_exception(args = {})
  16 + notice = args.delete(:notice) || build_notice_data
  17 + sender = args.delete(:sender) || build_sender(args)
  18 + sender.send_to_hoptoad(notice)
  19 + sender
  20 + end
  21 +
  22 + def stub_http
  23 + response = stub(:body => 'body')
  24 + http = stub(:post => response,
  25 + :read_timeout= => nil,
  26 + :open_timeout= => nil,
  27 + :use_ssl= => nil)
  28 + Net::HTTP.stubs(:new => http)
  29 + http
  30 + end
  31 +
  32 + should "post to Hoptoad when using an HTTP proxy" do
  33 + response = stub(:body => 'body')
  34 + http = stub(:post => response,
  35 + :read_timeout= => nil,
  36 + :open_timeout= => nil,
  37 + :use_ssl= => nil)
  38 + proxy = stub(:new => http)
  39 + Net::HTTP.stubs(:Proxy => proxy)
  40 +
  41 + url = "http://hoptoadapp.com:80#{HoptoadNotifier::Sender::NOTICES_URI}"
  42 + uri = URI.parse(url)
  43 +
  44 + proxy_host = 'some.host'
  45 + proxy_port = 88
  46 + proxy_user = 'login'
  47 + proxy_pass = 'passwd'
  48 +
  49 + send_exception(:proxy_host => proxy_host,
  50 + :proxy_port => proxy_port,
  51 + :proxy_user => proxy_user,
  52 + :proxy_pass => proxy_pass)
  53 + assert_received(http, :post) do |expect|
  54 + expect.with(uri.path, anything, HoptoadNotifier::HEADERS)
  55 + end
  56 + assert_received(Net::HTTP, :Proxy) do |expect|
  57 + expect.with(proxy_host, proxy_port, proxy_user, proxy_pass)
  58 + end
  59 + end
  60 +
  61 + should "post to the right url for non-ssl" do
  62 + http = stub_http
  63 + url = "http://hoptoadapp.com:80#{HoptoadNotifier::Sender::NOTICES_URI}"
  64 + uri = URI.parse(url)
  65 + send_exception(:secure => false)
  66 + assert_received(http, :post) {|expect| expect.with(uri.path, anything, HoptoadNotifier::HEADERS) }
  67 + end
  68 +
  69 + should "post to the right path for ssl" do
  70 + http = stub_http
  71 + send_exception(:secure => true)
  72 + assert_received(http, :post) {|expect| expect.with(HoptoadNotifier::Sender::NOTICES_URI, anything, HoptoadNotifier::HEADERS) }
  73 + end
  74 +
  75 + should "default the open timeout to 2 seconds" do
  76 + http = stub_http
  77 + send_exception
  78 + assert_received(http, :open_timeout=) {|expect| expect.with(2) }
  79 + end
  80 +
  81 + should "default the read timeout to 5 seconds" do
  82 + http = stub_http
  83 + send_exception
  84 + assert_received(http, :read_timeout=) {|expect| expect.with(5) }
  85 + end
  86 +
  87 + should "allow override of the open timeout" do
  88 + http = stub_http
  89 + send_exception(:http_open_timeout => 4)
  90 + assert_received(http, :open_timeout=) {|expect| expect.with(4) }
  91 + end
  92 +
  93 + should "allow override of the read timeout" do
  94 + http = stub_http
  95 + send_exception(:http_read_timeout => 10)
  96 + assert_received(http, :read_timeout=) {|expect| expect.with(10) }
  97 + end
  98 +
  99 + should "connect to the right port for ssl" do
  100 + stub_http
  101 + send_exception(:secure => true)
  102 + assert_received(Net::HTTP, :new) {|expect| expect.with("hoptoadapp.com", 443) }
  103 + end
  104 +
  105 + should "connect to the right port for non-ssl" do
  106 + stub_http
  107 + send_exception(:secure => false)
  108 + assert_received(Net::HTTP, :new) {|expect| expect.with("hoptoadapp.com", 80) }
  109 + end
  110 +
  111 + should "use ssl if secure" do
  112 + stub_http
  113 + send_exception(:secure => true, :host => 'example.org')
  114 + assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 443) }
  115 + end
  116 +
  117 + should "not use ssl if not secure" do
  118 + stub_http
  119 + send_exception(:secure => false, :host => 'example.org')
  120 + assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 80) }
  121 + end
  122 +
  123 +end
... ...