-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcode_buddy.html
148 lines (148 loc) · 15 KB
/
code_buddy.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>CodeBuddy: See your Ruby stack come alive! - Pat Shaughnessy</title><meta name="description" content=""><meta name="author" content=""><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/assets/css/normalize.css"><link rel="stylesheet" href="/assets/css/skeleton.css"><link rel="alternate" type="application/atom+xml" title="Pat Shaughnessy - Feed" href="http://feeds2.feedburner.com/patshaughnessy"><link rel="icon" type="image/png" href="images/favicon.png"></head><body><div id="banner"><a href="/"><span id="title">Pat Shaughnessy</span><span id="tagline"> blogger, rubyist, aspiring author</span></a></div><div style="margin-top: 35px"><div class="ten columns"><div class="container"><div class="row"><article class="post"><header><h1>CodeBuddy: See your Ruby stack come alive!</h1><div class="metadata">December 13th 2010 — <a href="#disqus_thread" data-disqus-identifier="https://patshaughnessy.net/code_buddy"> Comments and Reactions</a></div></header><section class="content"><p><a href="http://www.alexrothenberg.com/">Alex Rothenberg</a>, <a href="http://www.flyingmachinestudios.com/">Daniel Higginbotham</a> and I just published a new gem called <a href="http://github.com/patshaughnessy/code_buddy">CodeBuddy</a> that displays a Ruby stack trace inside your browser like this:
<p><img src="https://patshaughnessy.net/assets/2010/12/13/code_buddy.png"></p>
<p>The idea is that you can see both the stack trace and code snippets from the corresponding files at the same time, to make it easier to understand what was going on. You can move up and down the stack just by pressing the up/down arrow keys, or by clicking on a line in the stack trace:</p>
<p><img src="https://patshaughnessy.net/assets/2010/12/13/code_buddy_moved.png"></p>
<p>As you move, the code snippet in the center of the screen will update, showing you the path the Ruby interpreter took through your application’s code.</p>
<h2>Use it in your Rails app</h2>
<p>If you’re working on a Rails application, then just add the “code_buddy” gem to your Gemfile like this - to avoid security issues CodeBuddy will only function in the development environment:</p>
<p><div class="CodeRay">
<div class="code"><pre>group <span class="sy">:development</span> <span class="r">do</span>
gem <span class="s"><span class="dl">"</span><span class="k">code_buddy</span><span class="dl">"</span></span>
<span class="r">end</span></pre></div>
</div></p>
<p>And then install it using Bundler:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ bundle install</pre></div>
</div></p>
<p>Now whenever an exception occurs in your Rails app, the Rails exception page will appear as usual, but each file in the stack trace will now appear as a link:</p>
<p><img src="https://patshaughnessy.net/assets/2010/12/13/exception.png"></p>
<p>When you click any of these links CodeBuddy will appear, displaying code from the selected file.</p>
<p>If you’re using Rails 2.3.x, you can use CodeBuddy by adding these two lines to your config/environments/development.rb file:</p>
<p><div class="CodeRay">
<div class="code"><pre>config.gem <span class="s"><span class="dl">'</span><span class="k">code_buddy</span><span class="dl">'</span></span>
config.middleware.use <span class="s"><span class="dl">"</span><span class="k">CodeBuddy::ShowApp</span><span class="dl">"</span></span></pre></div>
</div></p>
<h2>Run it as a Sinatra app</h2>
<p>If you’re working on a Ruby project that is not a Rails application, or if you want to look at a stack trace generated by “puts caller” or in some other way you can run CodeBuddy as a standalone Sinatra app, like this:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ gem install code_buddy
$ code_buddy
== Sinatra/1.1.0 has taken the stage on 4567 for development with backup from...</pre></div>
</div></p>
<p>Now if you open <a href="http://localhost:4567">http://localhost:4567</a> you’ll get a form like this:</p>
<p><img src="https://patshaughnessy.net/assets/2010/12/13/code_buddy_form.png"></p>
<p>Here you can copy/paste a Ruby stack from your console or elsewhere and click “submit” to see it inside CodeBuddy. As long as the file paths in the stack can be found on your machine they will appear properly in CodeBuddy. You can even paste a stack containing relative paths, as long as you run the code_buddy command from the directory the paths are relative to.</p>
<p>This form is also available when CodeBuddy is running inside your Rails app if you click the “Paste Stack” link near the top right corner. By the way, the reason we disabled CodeBuddy outside of the development environment is that this form would be a huge, gaping security hole if CodeBuddy were active in the production or other server environment. This is because you can type any file path and line number you’d like into the form, and CodeBuddy will display the contents of the specified files. This is definitely not something you want to make available to anonymous users on the Internet in production! In the future we may provide options for running CodeBuddy in non-development environments, such as on an integration or staging server, if you’re sure it won’t present a security risk.</p>
<h2>Detailed example</h2>
<p>Let’s create a new Rails 3 app together, and try out CodeBuddy. I’ll create a new application from scratch called “code_buddy_example:”</p>
<p><div class="CodeRay">
<div class="code"><pre>$ rails new code_buddy_example
<span class="s">create</span>
<span class="s">create</span> README
<span class="s">create</span> Rakefile
<span class="s">create</span> config.ru
<span class="s">create</span> .gitignore
<span class="s">create</span> Gemfile
<span class="s">create</span> app
<span class="s">create</span> app/controllers/application_controller.rb
<span class="s">create</span> app/helpers/application_helper.rb
<p>... etc ...</p>
<p>$ cd code_buddy_example/</pre></div> </p>
</div></p>
<p>And let’s go ahead and add CodeBuddy to the development environment right away in the Gemfile:</p>
<p><div class="CodeRay">
<div class="code"><pre>source <span class="s"><span class="dl">'</span><span class="k">http://rubygems.org</span><span class="dl">'</span></span>
<p>gem <span class="s"><span class="dl">'</span><span class="k">rails</span><span class="dl">'</span></span>, <span class="s"><span class="dl">'</span><span class="k">3.0.3</span><span class="dl">'</span></span>
group <span class="sy">:development</span> <span class="r">do</span>
gem <span class="s"><span class="dl">'</span><span class="k">code_buddy</span><span class="dl">'</span></span>
<span class="r">end</span> </p>
<p>etc...</pre></div> </p>
</div></p>
<p>And now I’ll install it using bundler:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ bundle install
Fetching source index for http://rubygems.org/
Using rake (0.8.7)
Using abstract (1.0.0)
Using activesupport (3.0.3)
Using builder (2.1.2)
<p>... etc ...</p>
<p><span class='container'>Using coderay (0.9.6)<span class='overlay'></span></span>
<span class='container'>Using json_pure (1.4.6)<span class='overlay'></span></span>
<span class='container'>Using tilt (1.1)<span class='overlay'></span></span>
<span class='container'>Using sinatra (1.1.0)<span class='overlay'></span></span>
<span class='container'>Installing code_buddy (0.0.6)<span class='overlay'></span></span>
Using thor (0.14.6)
Using railties (3.0.3) </p>
<p>... etc ...</p>
<p><span class="s">Your bundle is complete! Use <code>bundle show [gemname]</code> to see where a bundled gem...</p>
<p>Your bundle was installed to <code>/Users/pat/.rvm/gems/ruby-1.8.7-p302</code></span></pre></div> </p>
</div></p>
<p>You can see the CodeBuddy gem was installed, along with a few others CodeBuddy depends on like Sinatra and Coderay. We use Coderay to provide the Ruby syntax color highlighting.</p>
<p>Now before I go any farther, let’s take a look at the Rack middleware stack:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ rake middleware
(in /Users/pat/rails-apps/code_buddy_example)
use ActionDispatch::Static
use Rack::Lock
use ActiveSupport::Cache::Strategy::LocalCache
use Rack::Runtime
use Rails::Rack::Logger
<span class='container'>use CodeBuddy::ShowApp<span class='overlay'></span></span>
<span class='container'>use CodeBuddy::ShowExceptions<span class='overlay'></span></span>
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
run CodeBuddyExample::Application.routes</pre></div>
</div></p>
<p>You’ll notice CodeBuddy appears twice. First a Rack middleware component called “CodeBuddy::ShowApp” was added by the gem. This displays the CodeBuddy page whenever the user accesses a URL matching “/code_buddy”. Behind the scenes, CodeBuddy::ShowApp actually runs the Sinatra app I mentioned above, right inside your Rails application. Kind of cool!</p>
<p>Second, you can see another Rack middleware component called “CodeBuddy::ShowExceptions.” CodeBuddy replaces the standard Rails ActionDispatch::ShowExceptions middleware component with a modified version, using “middleware.swap.” ActionDispatch::ShowExceptions is what displays the Rails exception pages, and the CodeBuddy version is identical, except that each line in the stack trace is displayed as a link to a “/code_buddy/... ” URL.</p>
<p>Now let’s finish our silly sample app by generating a controller to display a default home page:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ rails g controller welcome
<span class="s">create</span> app/controllers/welcome_controller.rb
invoke erb
<span class="s">create</span> app/views/welcome
invoke test_unit
<span class="s">create</span> test/functional/welcome_controller_test.rb
invoke helper
<span class="s">create</span> app/helpers/welcome_helper.rb
invoke test_unit
<span class="s">create</span> test/unit/helpers/welcome_helper_test.rb
etc...</pre></div>
</div></p>
<p>I’ll edit app/controllers/welcome_controller.rb and add some code to immediately throw an exception:</p>
<p><div class="CodeRay">
<div class="code"><pre><span class="r">class</span> <span class="cl">WelcomeController</span> < <span class="co">ApplicationController</span>
<span class="r">def</span> <span class="fu">index</span>
raise <span class="s"><span class="dl">'</span><span class="k">exception</span><span class="dl">'</span></span>
<span class="r">end</span>
<span class="r">end</span></pre></div>
</div></p>
<p>Now I’ll set this as my home page in config/routes.rb:</p>
<p><div class="CodeRay">
<div class="code"><pre>root <span class="sy">:to</span> => <span class="s"><span class="dl">"</span><span class="k">welcome#index</span><span class="dl">"</span></span></pre></div>
</div></p>
<p>And finally I’ll delete my static home page:</p>
<p><div class="CodeRay">
<div class="code"><pre>$ rm public/index.html</pre></div>
</div></p>
<p>Now if I run my server and access http://localhost:3000 I’ll immediately run into the exception... and clicking any of the links in the stack trace will take me to CodeBuddy!</p>
<p>It’s actually quite interesting to follow the stack down from the welcome controller’s action all the way through the rack middleware stack... all the way to the script/server command. Using Webrick from my laptop’s command line I get 82 different levels in my stack trace! Amazing - who knew so much code was executed before the Ruby interpreter ever reached my application!</p>
<h2>Feedback welcome</h2>
<p>Alex, Daniel and I would love to hear if the gem works for you, and if you have any suggestions - what else could we show in CodeBuddy? How else could it be used? What features is it missing?</p>
</section><section class="comments"><div id="disqus_thread"><script type="text/javascript">var disqus_identifier = 'https://patshaughnessy.net/code_buddy'; var disqus_shortname = 'patshaughnessy'; var disqus_title = 'CodeBuddy: See your Ruby stack come alive!';</script></div><script type="text/javascript" src="https://disqus.com/forums/patshaughnessy/embed.js"></script><noscript><a href="https://patshaughnessy.disqus.com/?url=ref">View the discussion thread.</a></noscript></section></article></div></div></div><div class="two columns"><div id="sidebar"><img src="/assets/images/pat.jpg"></img><div class="header">Subscribe</div><div class="links"><ul><li><a id="feed" href="http://feeds.feedburner.com/patshaughnessy"><img src="/assets/images/feed-icon16x16B.png"></img></a><a href="http://twitter.com/pat_shaughnessy"><img width="20" height="20" src="/assets/images/twitter.svg"></img></a></li></ul></div><div class="header">Buy My Book</div><div class="links"><ul><li><a href="/ruby-under-a-microscope"><img src="/assets/images/book-cover.png"></img></a></li><li id="eBook"><a href="/ruby-under-a-microscope">Ruby Under a Microscope</a></li></ul></div><div class="header">More on Ruby</div><div class="links"><ul><li><a href="/2016/10/7/need-a-second-opinion-on-your-ruby-code-ask-crystal">Need a Second Opinion on Your Ruby Code? Ask Crystal</a></li><li><a href="/2016/4/2/two-dumb-ruby-mistakes">Two Dumb Ruby Mistakes</a></li><li><a href="/2015/6/18/dont-let-your-data-out-of-the-database">Don’t Let Your Data Out of the Database</a></li><li><a href="/2015/2/16/mark-methods-private-when-you-dont-test-them">Mark Methods Private When You Don’t Test Them</a></li></ul></div><div class="header">Popular</div><div class="links"><ul><li><a href="/2016/11/26/learning-to-read-x86-assembly-language">Learning to Read x86 Assembly Language</a></li><li><a href="/2012/1/4/never-create-ruby-strings-longer-than-23-characters">Never create Ruby strings longer than 23 characters</a></li><li><a href="/2012/3/23/why-you-should-be-excited-about-garbage-collection-in-ruby-2-0">Why You Should Be Excited About Garbage Collection in Ruby 2.0</a></li><li><a href="/2013/4/3/ruby-2-0-works-hard-so-you-can-be-lazy">Ruby 2.0 Works Hard So You Can Be Lazy</a></li></ul></div><div class="header"><a href="/">More...</a></div></div></div><script type="text/javascript">(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());</script></div><div id="footer" class="ten columns"><p>Content and UI design © 2008-2022 Pat Shaughnessy</p></div></body></html>