debug-bar 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rbenv-version +1 -0
- data/.rspec +1 -0
- data/Gemfile +16 -0
- data/README.rdoc +192 -0
- data/Rakefile +27 -0
- data/debug-bar.gemspec +24 -0
- data/lib/debug-bar/base.rb +208 -0
- data/lib/debug-bar/default.rb +26 -0
- data/lib/debug-bar/ext/binding.rb +17 -0
- data/lib/debug-bar/ext/object.rb +20 -0
- data/lib/debug-bar/ext/string.rb +18 -0
- data/lib/debug-bar/ext.rb +3 -0
- data/lib/debug-bar/recipe_book/base.rb +104 -0
- data/lib/debug-bar/recipe_book/default.rb +34 -0
- data/lib/debug-bar/recipe_book.rb +2 -0
- data/lib/debug-bar/version.rb +3 -0
- data/lib/debug-bar.rb +6 -0
- data/lib/templates/callback_box.html.erb +12 -0
- data/lib/templates/error.html.erb +6 -0
- data/lib/templates/layout.html.erb +142 -0
- data/spec/base_spec.rb +363 -0
- data/spec/binding_spec.rb +62 -0
- data/spec/recipe_book_spec.rb +161 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/templates/basic.html.erb +1 -0
- data/spec/support/templates/content.html.erb +1 -0
- metadata +116 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'awesome_print'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module DebugBar
|
6
|
+
module RecipeBook
|
7
|
+
# A default RecipeBook with recipes useful for Rails applications.
|
8
|
+
class Default < Base
|
9
|
+
|
10
|
+
# Displays params in a user readable fashion.
|
11
|
+
#
|
12
|
+
# If the :cutoff option is given, it auto-hides when the params are
|
13
|
+
# more characters in length than the cutoff, otherwise it defaults to
|
14
|
+
# a sane length.
|
15
|
+
def params_recipe(opts={})
|
16
|
+
return Proc.new do |b|
|
17
|
+
params_s = b[:params].awesome_print_html
|
18
|
+
['Params', params_s, {:id => 'params'}]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Displays the session in a pretty printed way.
|
23
|
+
def session_recipe
|
24
|
+
return Proc.new {|b| ['Session', b[:session].awesome_print_html, {:id => 'session'}]}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Displays the cookies.
|
28
|
+
def cookies_recipe
|
29
|
+
return Proc.new {|b| ['Cookies', b[:cookies].awesome_print_html, {:id => 'cookies'}]}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/debug-bar.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="callback-box dbar-togglable" style="border:1px solid gray; margin:4px; padding:4px;">
|
2
|
+
<% if opts[:id] %>
|
3
|
+
<a href="" id="<%= opts[:id] %>" class='dbar-toggle persistent'>
|
4
|
+
<% else %>
|
5
|
+
<a href="" class='dbar-toggle'>
|
6
|
+
<% end %>
|
7
|
+
[x] <span class="title" style="font-weight:bold; color: #000000;"><%= title %></span>
|
8
|
+
</a>
|
9
|
+
<div class="dbar-content <%= 'show' unless opts[:hidden] %>" <%= 'style="display:none"' if opts[:hidden] %> >
|
10
|
+
<%= content %>
|
11
|
+
</div>
|
12
|
+
</div>
|
@@ -0,0 +1,142 @@
|
|
1
|
+
<style>
|
2
|
+
.dbar-content pre {
|
3
|
+
background: #a9a9a9;
|
4
|
+
margin: 0;
|
5
|
+
padding: 0;
|
6
|
+
font-size: 10px;
|
7
|
+
font-family: "Lucida Console", Monaco, monospace;
|
8
|
+
}
|
9
|
+
|
10
|
+
.dbar-content pre pre {
|
11
|
+
background: #a9a9a9;
|
12
|
+
margin: 0;
|
13
|
+
padding: 0;
|
14
|
+
border: 0;
|
15
|
+
font-size: 10px;
|
16
|
+
font-family: "Lucida Console", Monaco, monospace;
|
17
|
+
display: inline;
|
18
|
+
}
|
19
|
+
|
20
|
+
</style>
|
21
|
+
|
22
|
+
<div id="debug-bar" style="text-align:left; border:1px solid yellow; background:#ffffaa; width:24px; position:fixed; top:0; left:0; z-index:999">
|
23
|
+
<a href="" id="debug-toggle">[x]</a>
|
24
|
+
<div id="debug-data" style="font-size:9pt; display:none; overflow:auto;">
|
25
|
+
<%= content %>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<script>
|
30
|
+
/*!
|
31
|
+
* jQuery Cookie Plugin
|
32
|
+
* https://github.com/carhartl/jquery-cookie
|
33
|
+
*
|
34
|
+
* Copyright 2011, Klaus Hartl
|
35
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
36
|
+
* http://www.opensource.org/licenses/mit-license.php
|
37
|
+
* http://www.opensource.org/licenses/GPL-2.0
|
38
|
+
*/
|
39
|
+
(function($) {
|
40
|
+
$.cookie = function(key, value, options) {
|
41
|
+
|
42
|
+
// key and at least value given, set cookie...
|
43
|
+
if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
|
44
|
+
options = $.extend({}, options);
|
45
|
+
|
46
|
+
if (value === null || value === undefined) {
|
47
|
+
options.expires = -1;
|
48
|
+
}
|
49
|
+
|
50
|
+
if (typeof options.expires === 'number') {
|
51
|
+
var days = options.expires, t = options.expires = new Date();
|
52
|
+
t.setDate(t.getDate() + days);
|
53
|
+
}
|
54
|
+
|
55
|
+
value = String(value);
|
56
|
+
|
57
|
+
return (document.cookie = [
|
58
|
+
encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
|
59
|
+
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
60
|
+
options.path ? '; path=' + options.path : '',
|
61
|
+
options.domain ? '; domain=' + options.domain : '',
|
62
|
+
options.secure ? '; secure' : ''
|
63
|
+
].join(''));
|
64
|
+
}
|
65
|
+
|
66
|
+
// key and possibly options given, get cookie...
|
67
|
+
options = value || {};
|
68
|
+
var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
|
69
|
+
|
70
|
+
var pairs = document.cookie.split('; ');
|
71
|
+
for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
|
72
|
+
if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
|
73
|
+
}
|
74
|
+
return null;
|
75
|
+
};
|
76
|
+
})(jQuery);
|
77
|
+
</script>
|
78
|
+
<script>
|
79
|
+
jQuery('document').ready(function(){
|
80
|
+
var toggleDebugBar = function(){
|
81
|
+
var data = jQuery('#debug-data').toggle();
|
82
|
+
jQuery('#debug-bar').css('width', data.is(':visible') ? 'auto' : '24px');
|
83
|
+
jQuery('#debug-bar').css('max-height', data.is(':visible') ? '100%' : '24px');
|
84
|
+
jQuery('#debug-bar').css('overflow-y', data.is(':visible') ? 'auto' : 'hidden');
|
85
|
+
};
|
86
|
+
|
87
|
+
jQuery('#debug-toggle').on('click', function(e){
|
88
|
+
toggleDebugBar();
|
89
|
+
return false;
|
90
|
+
});
|
91
|
+
|
92
|
+
jQuery('body').bind('keydown', function(e){
|
93
|
+
if(e.keyCode == 192 && e.ctrlKey == true)
|
94
|
+
toggleDebugBar();
|
95
|
+
});
|
96
|
+
|
97
|
+
// Debug-bar section specific toggle (may differ from generic toggle.
|
98
|
+
// This is meant to be consumable by callback makers.
|
99
|
+
jQuery('.dbar-toggle').bind('click', function(){
|
100
|
+
var toggle = jQuery(this);
|
101
|
+
var content = toggle.closest('.dbar-togglable').find('.dbar-content');
|
102
|
+
content.first().toggle();
|
103
|
+
return false;
|
104
|
+
});
|
105
|
+
|
106
|
+
// Generic togglable inside of debug bar callback content area.
|
107
|
+
jQuery('.dbar-content').find('.toggle-switch').click(function(){
|
108
|
+
var toggle_content = jQuery(this).siblings('.toggle-content');
|
109
|
+
toggle_content.toggle();
|
110
|
+
return false;
|
111
|
+
});
|
112
|
+
|
113
|
+
jQuery('.callback-box .dbar-toggle.persistent').bind('click', function() {
|
114
|
+
// caching
|
115
|
+
var toggle = jQuery(this);
|
116
|
+
var id = toggle.attr('id');
|
117
|
+
|
118
|
+
// Deal with an empty cookie and split the commas
|
119
|
+
var debug_bar_array = jQuery.cookie('debug_bar') ? jQuery.cookie('debug_bar').split(',') : [];
|
120
|
+
|
121
|
+
// Just a double check it has an id
|
122
|
+
if (id)
|
123
|
+
{
|
124
|
+
// Decide which way to toggle this key
|
125
|
+
var id_index = debug_bar_array.indexOf(id);
|
126
|
+
if (id_index > -1)
|
127
|
+
{
|
128
|
+
// Remove id from cookie
|
129
|
+
debug_bar_array.splice(id_index, 1);
|
130
|
+
}
|
131
|
+
else
|
132
|
+
{
|
133
|
+
// Add the id into the list to keep open
|
134
|
+
debug_bar_array.push(id);
|
135
|
+
}
|
136
|
+
|
137
|
+
// Rejoin the cookie keys and store
|
138
|
+
jQuery.cookie('debug_bar', debug_bar_array.join(','), { path: '/', expires: 7 });
|
139
|
+
}
|
140
|
+
});
|
141
|
+
});
|
142
|
+
</script>
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,363 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class TestDefaultRecipeBook < DebugBar::RecipeBook::Base
|
5
|
+
|
6
|
+
def params_recipe(opts={})
|
7
|
+
return Proc.new do |b|
|
8
|
+
params_s = b[:params].awesome_print_html
|
9
|
+
hidden = params_s.length > opts.fetch(:cutoff, 512)
|
10
|
+
puts [params_s.length, hidden, opts].inspect
|
11
|
+
['Params', params_s, {:hidden => hidden, :id => 'params'}]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def block_test_recipe(arg=nil)
|
16
|
+
return Proc.new do |b|
|
17
|
+
['Block Test', "|arg|#{arg}|arg| |block|#{yield(b) if block_given?}|block|", {}]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe DebugBar::Base do
|
24
|
+
|
25
|
+
describe 'callbacks' do
|
26
|
+
|
27
|
+
before(:each) do
|
28
|
+
@debug_bar = DebugBar::Base.new
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should register recipes in initializer after the block is called' do
|
32
|
+
debug_bar = DebugBar::Base.new(:params) do |bar|
|
33
|
+
bar.add_recipe_book(TestDefaultRecipeBook)
|
34
|
+
bar.callbacks.length.should == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
debug_bar.callbacks.length.should == 1
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
it 'should register blocks' do
|
42
|
+
@debug_bar.add {|b| ["Test Block", "Test Content", {}]}
|
43
|
+
|
44
|
+
@debug_bar.callbacks.length.should == 1
|
45
|
+
@debug_bar.callbacks.first.should be_kind_of(Proc)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should register recipes' do
|
49
|
+
@debug_bar.add_recipe_book(TestDefaultRecipeBook)
|
50
|
+
@debug_bar.add(:params)
|
51
|
+
|
52
|
+
@debug_bar.callbacks.length.should == 1
|
53
|
+
@debug_bar.callbacks.first.should be_kind_of(Proc)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should error on nil' do
|
57
|
+
lambda {@debug_bar.add(nil)}.should raise_error(ArgumentError)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'render' do
|
63
|
+
|
64
|
+
before(:each) do
|
65
|
+
@debug_bar = DebugBar::Base.new
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should render blocks' do
|
69
|
+
title = "Testing The Block"
|
70
|
+
content = "<pre>Alpha Beta</pre>"
|
71
|
+
@debug_bar.add {|b| [title, content, {}]}
|
72
|
+
|
73
|
+
html = @debug_bar.render(binding)
|
74
|
+
|
75
|
+
html.should be_kind_of(String)
|
76
|
+
html.should_not be_empty
|
77
|
+
|
78
|
+
html.index(title).should_not be_nil
|
79
|
+
html.index(content).should_not be_nil
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should render as html_safe string' do
|
83
|
+
@debug_bar.add {|b| ["foo", "bar", {}]}
|
84
|
+
html = @debug_bar.render(binding)
|
85
|
+
html.should be_kind_of(ActiveSupport::SafeBuffer)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should render with a given binding' do
|
89
|
+
@debug_bar.add {|b| ["Title", "||#{b.eval('foobar')}||", {}]}
|
90
|
+
|
91
|
+
foobar = "Spoilers!"
|
92
|
+
html = @debug_bar.render(binding)
|
93
|
+
|
94
|
+
html.should be_kind_of(String)
|
95
|
+
|
96
|
+
html.index(foobar).should_not be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should render with a custom decorated binding' do
|
100
|
+
@debug_bar.add {|b| ["Binding", "||get is #{b.respond_to?(:[])}||", {}]}
|
101
|
+
|
102
|
+
binding.should_not respond_to(:[])
|
103
|
+
html = @debug_bar.render(binding)
|
104
|
+
|
105
|
+
html.index("||get is true||").should_not be_nil
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should render recipes' do
|
109
|
+
@debug_bar.add_recipe_book(TestDefaultRecipeBook)
|
110
|
+
@debug_bar.add(:params)
|
111
|
+
params = {:given_name => 'Amelia', :family_name => 'Pond'}
|
112
|
+
|
113
|
+
html = @debug_bar.render(binding)
|
114
|
+
|
115
|
+
html.should be_kind_of(String)
|
116
|
+
html.should_not be_empty
|
117
|
+
|
118
|
+
html.index('Amelia').should_not be_nil
|
119
|
+
html.index(':given_name').should_not be_nil
|
120
|
+
html.index('dbar-content show').should_not be_nil # See if params was expanded.
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should render recipes with args' do
|
124
|
+
@debug_bar.add_recipe_book(TestDefaultRecipeBook)
|
125
|
+
@debug_bar.add(:params, :cutoff => 12)
|
126
|
+
|
127
|
+
params = {:given_name => 'Amelia', :family_name => 'Pond'}
|
128
|
+
|
129
|
+
html = @debug_bar.render(binding)
|
130
|
+
|
131
|
+
html.should be_kind_of(String)
|
132
|
+
html.should_not be_empty
|
133
|
+
|
134
|
+
html.index('Amelia').should_not be_nil
|
135
|
+
html.index(':given_name').should_not be_nil
|
136
|
+
html.index('dbar-content show').should be_nil # See if params was collapsed due to cutoff.
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should render recipes with block args' do
|
140
|
+
@debug_bar.add_recipe_book(TestDefaultRecipeBook)
|
141
|
+
@debug_bar.add(:block_test) {|b| b.class.name}
|
142
|
+
|
143
|
+
html = @debug_bar.render(binding)
|
144
|
+
|
145
|
+
html.should be_kind_of(String)
|
146
|
+
html.should_not be_empty
|
147
|
+
|
148
|
+
html.index('|block|Binding|block|').should_not be_nil
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should render the callback_box' do
|
152
|
+
@debug_bar.add {|b| ["foo", "bar", {}]}
|
153
|
+
html = @debug_bar.render(binding)
|
154
|
+
|
155
|
+
html.index('callback-box').should_not be_nil # Picked the CSS class as a good indicator of presence.
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should render the layout' do
|
159
|
+
@debug_bar.add {|b| ["foo", "bar", {}]}
|
160
|
+
html = @debug_bar.render(binding)
|
161
|
+
|
162
|
+
html.index('debug-bar').should_not be_nil # Picked the presence of CSS class as a good inidcator of presence.
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should render on crash in callback' do
|
166
|
+
@debug_bar.add {|b| raise RuntimeError, "Uh-oh, you didn't handle the exception!"}
|
167
|
+
html = ''
|
168
|
+
lambda {html = @debug_bar.render(binding)}.should_not raise_error
|
169
|
+
html.index('ERROR').should_not be_nil
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'options' do
|
175
|
+
|
176
|
+
before(:each) do
|
177
|
+
@debug_bar = DebugBar::Base.new
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should interpret missing opts from callback as {}' do
|
181
|
+
@debug_bar.add {|b| ['foo', 'bar']}
|
182
|
+
|
183
|
+
html = @debug_bar.render(binding)
|
184
|
+
|
185
|
+
html.should be_kind_of(String)
|
186
|
+
html.should_not be_empty
|
187
|
+
|
188
|
+
html.index('foo').should_not be_nil
|
189
|
+
html.index('bar').should_not be_nil
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should interpret nil opts from callback as {}' do
|
193
|
+
@debug_bar.add {|b| ['foo', 'bar', nil]}
|
194
|
+
|
195
|
+
html = @debug_bar.render(binding)
|
196
|
+
|
197
|
+
html.should be_kind_of(String)
|
198
|
+
html.should_not be_empty
|
199
|
+
|
200
|
+
html.index('foo').should_not be_nil
|
201
|
+
html.index('bar').should_not be_nil
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should default :hidden option to true if not explicitly given and session remembers it as open based on id' do
|
205
|
+
# Emulate saving of open callback box ids in cookies.
|
206
|
+
cookies = {:debug_bar => 'rory_williams,amelia_pond'}
|
207
|
+
# Put into binding.
|
208
|
+
b = binding
|
209
|
+
|
210
|
+
html_rory = DebugBar::Base.new.add {|b| ['foo', 'bar', :id => 'rory_williams']}.render(b)
|
211
|
+
html_rose = DebugBar::Base.new.add {|b| ['foo', 'bar', :id => 'rose_tyler']}.render(b)
|
212
|
+
|
213
|
+
# Extract the classes from the first div that has a dbar-content class in it.
|
214
|
+
extract_classes = lambda do |html|
|
215
|
+
m = /<div[^>]+class=['"]([^>'"]*dbar-content[^>'"]*)[^>]+>/.match(html)
|
216
|
+
return m.to_a[1].to_s.split(/\s+/)
|
217
|
+
end
|
218
|
+
|
219
|
+
html_rory.should include('show')
|
220
|
+
html_rose.should_not include('show')
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should recognize :hidden options' do
|
224
|
+
html_hidden = DebugBar::Base.new.add {|b| ['foo', 'bar', :hidden => true]}.render(binding)
|
225
|
+
html_nohide = DebugBar::Base.new.add {|b| ['foo', 'bar', :hidden => false]}.render(binding)
|
226
|
+
|
227
|
+
# Extract the classes from the first div that has a dbar-content class in it.
|
228
|
+
extract_classes = lambda do |html|
|
229
|
+
m = /<div[^>]+class=['"]([^>'"]*dbar-content[^>'"]*)[^>]+>/.match(html)
|
230
|
+
return m.to_a[1].to_s.split(/\s+/)
|
231
|
+
end
|
232
|
+
|
233
|
+
extract_classes.call(html_hidden).should_not include('show')
|
234
|
+
extract_classes.call(html_nohide).should include('show')
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
describe 'recipe books' do
|
240
|
+
|
241
|
+
class TestBook < DebugBar::RecipeBook::Base
|
242
|
+
def duplicated_recipe
|
243
|
+
Proc.new {|b| :test_book_duplicated_recipe}
|
244
|
+
end
|
245
|
+
|
246
|
+
def beta_recipe
|
247
|
+
Proc.new {|b| :test_book_beta_recipe}
|
248
|
+
end
|
249
|
+
|
250
|
+
def some_helper
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
class AnotherTestBook < DebugBar::RecipeBook::Base
|
255
|
+
def duplicated_recipe
|
256
|
+
Proc.new {|b| :another_test_book_duplicated_recipe}
|
257
|
+
end
|
258
|
+
|
259
|
+
def gamma_recipe
|
260
|
+
Proc.new {|b| :another_test_book_gamma_recipe}
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
before(:each) do
|
265
|
+
@book_class = TestBook # TODO: This is a poor choice, we should create one just for testing.
|
266
|
+
@book = @book_class.new
|
267
|
+
|
268
|
+
@base_debug_bar = DebugBar::Base.new
|
269
|
+
@debug_bar = DebugBar::Base.new {|bar| bar.add_recipe_book(TestBook); bar.add_recipe_book(AnotherTestBook)}
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should add recipe books by class' do
|
273
|
+
@base_debug_bar.add_recipe_book(@book_class)
|
274
|
+
|
275
|
+
@base_debug_bar.recipe_books.length.should == 1
|
276
|
+
@base_debug_bar.recipe_books.first.should be_kind_of(@book_class)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should add recipe books by instance' do
|
280
|
+
@base_debug_bar.add_recipe_book(@book)
|
281
|
+
|
282
|
+
@base_debug_bar.recipe_books.length.should == 1
|
283
|
+
@base_debug_bar.recipe_books.first.should be_kind_of(@book_class)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should return the list of known recipes' do
|
287
|
+
@debug_bar.recipes.sort.should == [:beta, :duplicated, :gamma].sort
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should return a recipe callback if one is found' do
|
291
|
+
callback = @debug_bar.recipe_callback(:beta)
|
292
|
+
callback.should be_kind_of(Proc)
|
293
|
+
callback.call.should == :test_book_beta_recipe
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'should raise an Argument Error if a recipe is not found' do
|
297
|
+
lambda {@debug_bar.recipe_callback(:zeta)}.should raise_error(ArgumentError)
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should use the last found instance of a recipe when it is duplicated' do
|
301
|
+
callback = @debug_bar.recipe_callback(:duplicated)
|
302
|
+
callback.should be_kind_of(Proc)
|
303
|
+
callback.call.should == :another_test_book_duplicated_recipe
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
describe 'subclass overrides' do
|
309
|
+
|
310
|
+
class SubclassTestBook < DebugBar::RecipeBook::Base
|
311
|
+
|
312
|
+
def beta_recipe
|
313
|
+
Proc.new {|b| :test_book_beta_recipe}
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|
317
|
+
|
318
|
+
class SubclassInstanceTestBook < DebugBar::RecipeBook::Base
|
319
|
+
|
320
|
+
def foo_recipe
|
321
|
+
Proc.new {|b| :instance_test_book_foo_recipe}
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
class SubclassTestBar < DebugBar::Base
|
327
|
+
|
328
|
+
private
|
329
|
+
|
330
|
+
def default_recipe_books
|
331
|
+
return [SubclassTestBook, SubclassInstanceTestBook.new]
|
332
|
+
end
|
333
|
+
|
334
|
+
def default_recipes
|
335
|
+
return [:beta]
|
336
|
+
end
|
337
|
+
|
338
|
+
def template_search_paths
|
339
|
+
return :standin_for_an_array_of_pathnames
|
340
|
+
end
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
before(:each) do
|
345
|
+
@debug_bar = SubclassTestBar.new
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'should add recipe books from the default recipe books method' do
|
349
|
+
@debug_bar.recipe_books.length.should == 2
|
350
|
+
@debug_bar.recipe_books.each {|book| book.should be_kind_of(DebugBar::RecipeBook::Base)}
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'should add recipes from the default recipe method' do
|
354
|
+
@debug_bar.recipes.sort.should == [:beta, :foo].sort
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'should allow overriding of the template path' do
|
358
|
+
@debug_bar.send(:template_search_paths).should == :standin_for_an_array_of_pathnames
|
359
|
+
end
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestContext
|
4
|
+
TARDIS = :tardis
|
5
|
+
@@gallifrey = :gallifrey
|
6
|
+
$the_doctor = :the_doctor
|
7
|
+
|
8
|
+
def get_binding
|
9
|
+
amelia_pond = :amelia_pond
|
10
|
+
@river_song = :river_song
|
11
|
+
|
12
|
+
return binding
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe DebugBar::Ext::Binding do
|
17
|
+
|
18
|
+
describe '[] method' do
|
19
|
+
|
20
|
+
before(:all) do
|
21
|
+
@binding = TestContext.new.get_binding
|
22
|
+
@binding.extend(DebugBar::Ext::Binding)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should exist on binding' do
|
26
|
+
@binding.should respond_to(:[])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should get local variables' do
|
30
|
+
@binding[:amelia_pond].should == :amelia_pond
|
31
|
+
@binding['amelia_pond'].should == :amelia_pond
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should get instance varaibles' do
|
35
|
+
@binding[:@river_song].should == :river_song
|
36
|
+
@binding['@river_song'].should == :river_song
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should get global variables' do
|
40
|
+
@binding[:$the_doctor].should == :the_doctor
|
41
|
+
@binding['$the_doctor'].should == :the_doctor
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should get constants' do
|
45
|
+
@binding[:TARDIS].should == :tardis
|
46
|
+
@binding['TARDIS'].should == :tardis
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should get class variables' do
|
50
|
+
@binding[:@@gallifrey].should == :gallifrey
|
51
|
+
@binding['@@gallifrey'].should == :gallifrey
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should not perform arbirary code' do
|
55
|
+
lambda {@binding['1+1']}.should raise_error(NameError)
|
56
|
+
lambda {@binding['amelia_pond.class']}.should raise_error(NameError)
|
57
|
+
lambda {@binding['def foo']}.should raise_error(NameError)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|