/debug-bar

A plugin based debug bar implementation

Primary LanguageRuby

Overview

DebugBar offers an easy way to show developer/debugging information on a a web page in an unobtrustive way. It features keyboard shortcuts for showing/hiding the bar (Ctrl-~), and memory (through cookies) of which information to show.

DebugBar uses a modular architecture utilizing callback lambdas to produce the contents of the DebugBar.

DebugBar::Base is the base debug bar, suitable for use in any application, and comes without any pre-added callbacks.

DebugBar::Default is a default debug bar suitible for a typical Rails application, and includes several default callbacks meaningful in such an environment.

Installation

To use DebugBar, your application must include jQuery in rendered pages.

Typically, Rails applications create a debug_bar initializer that defines a DEBUG_BAR constant which refers to the configured DebugBar instance. Customization and setup are typically done in this file.

Examples

Basic Usage

Typically the debug bar is added to your layout template with the following code

DebugBar::Default.new.render(binding)

though it is typically better to pre-instantiate your debug bar instance as a constant in an initializer, and then reference it in your layout, like so:

# In your initializer
DEBUG_BAR = DebugBar::Default.new do |debug_bar|
  # Do additional setup, such as registering custom recipe books and callbacks here.
end

# In your layout view template
DEBUG_BAR.render(binding)

Additionally, it is common to include code that controls the optional rendering of the debug bar based on environement and/or parameters; for example

DEBUG_BAR.render(binding) if Rails.env=='development' || params.include?(:debugger)

could be used in Rails.

Custom Callbacks

While there are a basic set of callbacks available, the real power of DebugBar is the ability to add custom callbacks.

In the context of a Rails application, custom callbacks are typically added to the config/initializer where the debug_bar is instantiated.

Basic

Custom callbacks are typically Proc objects that take an evaluation binding context as an argument, and produce an array of the form of two to three elements:

title

The display title for this callback box.

body

The raw HTML string to render.

opts

A hash of options to pass to the renderer, usually used to control box layout options. This is optional.

Thus, if one wanted a debug box to display the time, one might do

debug_bar.add {|binding| ['Time', Time.now.to_s]}

A more complex example would to output the params hash. Note that since the output is raw HTML, we must replace all instances of ‘<’ with ‘&lt;’. (A proper implementation would escape all escapable entities.)

debug_bar.add do |binding|
  body = binding.eval('params').inspect.gsub('<','&lt;')
  ['Params', body]
end

Note that we using binding.eval to extract variable names from the binding by executing snippets of code. This raises two points:

  • Any code can be evaluated in the binding in this manor, thus choice of render binding has a major impact on the information available for display.

  • As a convenience, variables can be extracted from the binding with the [] method, thus

    body = binding[:params].inspect
    

    could be substituted for

    body = binding.eval('params').inspect
    

Rails Render

If rendering the DebugBar from within a Rails template (e.g. the application layout), you can use Rails render commands in the callback via a binding.eval to render any template and output the results to the debug bar. This is convenient way to render any input, though the use of custom recipe books should be considered if you do this often.

Options

Callbacks may provide the following options:

:id

The HTML id for the callback for use with custom javascript hooks, and remembered settings.

:hidden

Controls default state of disclosure arrow for the callback’s content. Note that if an :id is provided, the state can be remembered between requests.

UI Tools

Note that debug-bar callbacks can use the ‘toggle-switch’ and ‘toggle-content’ classes to drive toggleable hide/show behavior inside of the debug-bar. To do so, add the ‘toggle-switch’ class to the link that causes toggle, and the ‘toggle-content’ class to the sibling element that will toggle.

For example:

<div>
  <a href="" class="toggle-switch">Details</a>
  <div class="toggle-content" style="display:none">
    Lot's of content here.
  </div>
</div>

This would present a “Details” link that would reveal the content div.

Custom Recipes

While it is convenient to define one-off callbacks directly via add, it is often both cleaner and more useful to create re-usable callback recipes in RecipeBooks. Additionally, RecipeBooks provide some convenience methods not available in your own initializers.

Essentially, subclasses of RecipeBook::Base are factory classes that contain instance methods that generate Proc objects that are used as callbacks. What makes RecipeBook special over any random factory class is the convenience methods it gives and the tight integration with DebugBar::Base instances.

Setup

One can manually add a RecipeBook by class or instance using the add_recipe_book method. For example

debug_bar.add_recipe_book(DebugBar::RecipeBook::Default)

or

book = DebugBar::RecipeBook::Default.new
debug_bar.add_recipe_book(book)

Creating Your Own

To create your own recipe book, simply subclass another recipe book and add recipe generation inatance methods that follow a few simple rules:

  1. They must be the recipe name suffixed with ‘_recipe’.

  2. They must be able to support being called with no elements to support short-hand addition of a recipe. (This does no preclude supporting optional arguments and manual addition of the generated block.

Recipes in a RecipeBook::Base subclass get access to special functionality, such as being able to use templates at class-defined locations.

Contact

Jeff Reinecke <jreinecke@whitepages.com> Keith Stone <kstone@whitepages.com>

Feature Roadmap

  • No future features expected at this time.

Version History

1.0.0 - 2012-Jul-13

Initial Release.

License

Copyright (c) 2012, WhitePages, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the company nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WHITEPAGES, INC. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.