code_buddy 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,10 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ bundler
5
+ cache
4
6
  *.swp
7
+ *~
8
+ Gemfile.lock
9
+ example_trace
10
+ tmp
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in code_buddy.gemspec
4
4
  gemspec
5
+
6
+
7
+ group :test, :cucumber do
8
+ gem 'rails'
9
+ end
@@ -0,0 +1,10 @@
1
+ ## Code Buddy release history
2
+
3
+ ### 0.0.7 / 2011-01-04
4
+
5
+ [full changelog](https://github.com/patshaughnessy/code_buddy/compare/v0.0.6...v0.0.7)
6
+
7
+ * Bug fix: Handles stack traces from haml files
8
+ * 'e' opens an editor to current file (mvim and mate only based on EDITOR environment variable)
9
+ * 'h' show/hide code window
10
+ * Added some cucumber features so we know it works
data/Rakefile CHANGED
@@ -3,8 +3,13 @@ Bundler::GemHelper.install_tasks
3
3
 
4
4
  require 'rspec/core'
5
5
  require 'rspec/core/rake_task'
6
+ require 'cucumber/rake/task'
7
+
6
8
  RSpec::Core::RakeTask.new(:spec) do |spec|
7
9
  spec.pattern = FileList['spec/**/*_spec.rb']
8
10
  end
9
11
 
10
- task :default => :spec
12
+ task :default => [:spec, :cucumber]
13
+
14
+ Cucumber::Rake::Task.new(:cucumber)
15
+
@@ -27,5 +27,8 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency 'rake', '~> 0.8.7'
28
28
  s.add_development_dependency 'rspec', '~> 2.2.0'
29
29
  s.add_development_dependency 'mocha', '~> 0.9.10'
30
-
30
+ s.add_development_dependency 'cucumber', '~> 0.9.4'
31
+ s.add_development_dependency 'aruba', '~> 0.2.2'
32
+ # s.add_development_dependency 'capybara'
33
+ # s.add_development_dependency 'akephalos'
31
34
  end
@@ -0,0 +1,21 @@
1
+ Feature: Make sure CodeBuddy works with a Rails3 app
2
+
3
+ @announce
4
+ Scenario: See a stack trace with links
5
+ Given I have created a new Rails 2 app "new_rails2_app" with code_buddy
6
+ And I run "script/generate scaffold user"
7
+ And I overwrite "app/views/users/index.html.erb" with:
8
+ """
9
+ <%= raise 'oops' %>
10
+ """
11
+ And I run "rake db:migrate"
12
+ And I run "cp ../../../features/templates/rails_exception.feature.template features/rails_exception.feature"
13
+ And I am pending
14
+ And I run "rake cucumber"
15
+ Then it should pass with:
16
+ """
17
+ 1 scenario (1 passed)
18
+ 4 steps (4 passed)
19
+ """
20
+
21
+
@@ -0,0 +1,21 @@
1
+ Feature: Make sure CodeBuddy works with a Rails3 app
2
+
3
+ @announce
4
+ Scenario: See a stack trace with links
5
+ Given I have created a new Rails 3 app "new_rails3_app" with code_buddy
6
+ And I run "rails generate scaffold users"
7
+ And I overwrite "app/views/users/index.html.erb" with:
8
+ """
9
+ <%= raise 'oops' %>
10
+ """
11
+ And I run "rake db:migrate"
12
+ And I enable show_exceptions in "config/environments/test.rb"
13
+ And I run "cp ../../../features/templates/rails_exception.feature.template features/rails_exception.feature"
14
+ And I run "bundle exec rake cucumber -v"
15
+ Then it should pass with:
16
+ """
17
+ 1 scenario (1 passed)
18
+ 4 steps (4 passed)
19
+ """
20
+
21
+
@@ -0,0 +1,15 @@
1
+ Feature: Make sure CodeBuddy works when started as a sinatra app
2
+
3
+ @announce
4
+ Scenario: See a stack trace with links
5
+ Given I have created a test harness "sinatra_testing" for sinatra
6
+ And I run "cp ../../../features/templates/sinatra_homepage.feature.template features/sinatra_homepage.feature"
7
+ And I run "cp ../../../features/templates/sinatra_paths.rb.template features/support/paths.rb"
8
+ And I run "cucumber ."
9
+ Then it should pass with:
10
+ """
11
+ 1 scenario (1 passed)
12
+ 2 steps (2 passed)
13
+ """
14
+
15
+
@@ -0,0 +1,68 @@
1
+ Given /^I have created a new Rails 3 app "([^"]*)" with code_buddy$/ do |app_name|
2
+ steps <<-STEPS
3
+ Given I successfully run "rails new #{app_name}"
4
+ And I cd to "#{app_name}"
5
+ And I append to "Gemfile" with:
6
+ """
7
+ gem 'rspec'
8
+ # gem 'akephalos', :git => 'https://github.com/thoughtbot/akephalos.git'
9
+ gem "cucumber-rails"
10
+ gem "capybara", '~> 0.3.8'
11
+ gem 'code_buddy', :path=>File.expand_path("../../../..", __FILE__)
12
+ """
13
+ And I run "bundle install"
14
+ And I run "rails generate cucumber:install"
15
+ And I run "rake db:migrate"
16
+ STEPS
17
+ end
18
+
19
+ Given /^I have created a new Rails 2 app "([^"]*)" with code_buddy$/ do |app_name|
20
+ steps <<-STEPS
21
+ Given I run "gem install rails --version '=2.3.10'"
22
+ And I successfully run "rails _2.3.10_ #{app_name}"
23
+ And I cd to "#{app_name}"
24
+ And I replace "# Specify gems that this application depends on and have them installed with rake gems:install" in "config/environment.rb" with:
25
+ """
26
+ # Specify gems that this application depends on and have them installed with rake gems:install
27
+ config.gem 'code_buddy'
28
+ config.middleware.use "CodeBuddy::ShowApp"
29
+
30
+ """
31
+ And I run "mkdir vendor/gems"
32
+ And I run "ln -s #{File.expand_path("../../..", __FILE__)} vendor/gems/code_buddy-#{CodeBuddy::VERSION}"
33
+ And I run "script/generate cucumber"
34
+ And I run "rake db:migrate"
35
+ STEPS
36
+ end
37
+
38
+
39
+ Given /^I have created a test harness "([^"]*)" for sinatra$/ do |app_name|
40
+ steps <<-STEPS
41
+ Given I run "gem install cucumber-sinatra"
42
+ And I successfully run "mkdir #{app_name}"
43
+ And I cd to "#{app_name}"
44
+ And I run "cucumber-sinatra init CodeBuddy::App ../../../spec/spec_helper.rb"
45
+ STEPS
46
+ # And I run "cp #{File.expand_path("../templates/sinatra_env.rb.template", __FILE__)} features/support/env.rb"
47
+ end
48
+
49
+ Given /^I enable show_exceptions in "([^"]*)"$/ do |file_name|
50
+ # Given %Q[I replace "config.action_dispatch.show_exceptions = false" in "#{file_name}"], pystring #Cucumber::Ast::PyString.parse('config.action_dispatch.show_exceptions = true')
51
+ cmd = "sed s/'config.action_dispatch.show_exceptions = false'/'config.action_dispatch.show_exceptions = true'/ #{file_name}"
52
+ run_simple(cmd)
53
+ create_file(file_name, stdout_from(cmd), true)
54
+ end
55
+
56
+ Given /^I replace "([^"]*)" in "([^"]*)" with:$/ do |marker, file_name, new_text|
57
+ file = File.readlines(File.join(current_dir, file_name))
58
+ new_content = file.map do |line|
59
+ if line =~ Regexp.new(marker)
60
+ new_text
61
+ else
62
+ line
63
+ end
64
+ end
65
+ create_file(file_name, new_content, true)
66
+ end
67
+
68
+
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec/expectations'
4
+ require 'aruba/cucumber'
5
+
6
+ Before do
7
+ unset_bundler_env_vars
8
+ end
9
+
@@ -0,0 +1,8 @@
1
+ Feature: Ensure CodeBuddy creates links in a Rails app
2
+
3
+ @allow-rescue
4
+ Scenario: Clicking on a line of a stack trace on the exception page
5
+ When I go to the users page
6
+ Then I should see "app/views/users/index.html.erb:1"
7
+ And I follow "app/views/users/index.html.erb:1"
8
+ Then I should see "CodeBuddySee your Ruby stack come alive"
@@ -0,0 +1,22 @@
1
+ # Some minor edits after being
2
+ # Generated by cucumber-sinatra. (Wed Dec 22 13:32:12 -0500 2010)
3
+
4
+ ENV['RACK_ENV'] = 'test'
5
+
6
+ require File.join(File.dirname(__FILE__), '..', '..', '../../spec/spec_helper.rb')
7
+
8
+ require 'capybara'
9
+ require 'capybara/cucumber'
10
+ require 'rspec'
11
+
12
+ Capybara.app = CodeBuddy::App
13
+
14
+ class CodeBuddyWorld
15
+ include Capybara
16
+ include RSpec::Expectations
17
+ include RSpec::Matchers
18
+ end
19
+
20
+ World do
21
+ CodeBuddyWorld.new
22
+ end
@@ -0,0 +1,6 @@
1
+ Feature: Ensure CodeBuddy creates links as a stand alone Sinatra app
2
+
3
+ Scenario: Clicking on a line of a stack trace on the exception page
4
+ When I go to the new stack form page
5
+ # And show me the page
6
+ Then I should see "CodeBuddySee your Ruby stack come alive"
@@ -0,0 +1,31 @@
1
+ # Taken from the cucumber-rails project.
2
+
3
+ module NavigationHelpers
4
+ # Maps a name to a path. Used by the
5
+ #
6
+ # When /^I go to (.+)$/ do |page_name|
7
+ #
8
+ # step definition in web_steps.rb
9
+ #
10
+ def path_to(page_name)
11
+ case page_name
12
+
13
+ when /the home page/
14
+ '/'
15
+ when /the new stack form page/
16
+ '/new'
17
+
18
+ # Add more mappings here.
19
+ # Here is an example that pulls values out of the Regexp:
20
+ #
21
+ # when /^(.*)'s profile page$/i
22
+ # user_profile_path(User.find_by_login($1))
23
+
24
+ else
25
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
26
+ "Now, go and add a mapping in #{__FILE__}"
27
+ end
28
+ end
29
+ end
30
+
31
+ World(NavigationHelpers)
@@ -9,8 +9,7 @@ require 'code_buddy/stack_frame'
9
9
  require 'code_buddy/middleware'
10
10
 
11
11
  begin
12
- if Rails.env.development?
13
- CodeBuddy::App.rails = true
12
+ if Rails.env.development? || Rails.env.test?
14
13
  case Rails::VERSION::MAJOR
15
14
  when 2:
16
15
  require 'code_buddy/rails2/monkey_patch_action_controller'
@@ -21,3 +20,5 @@ begin
21
20
  rescue NameError
22
21
  nil
23
22
  end
23
+
24
+ # CodeBuddy::App.run!
@@ -5,7 +5,7 @@ module CodeBuddy
5
5
 
6
6
  class << self
7
7
  attr_reader :stack
8
- attr_accessor :rails
8
+ attr_accessor :path_prefix
9
9
 
10
10
  def exception=(exception)
11
11
  @stack = Stack.new(exception)
@@ -17,7 +17,7 @@ module CodeBuddy
17
17
  end
18
18
 
19
19
  get '/' do
20
- redirect "#{rails_prefix}/stack"
20
+ redirect "#{path_prefix}/stack"
21
21
  end
22
22
 
23
23
  get '/new' do
@@ -26,7 +26,7 @@ module CodeBuddy
26
26
 
27
27
  post '/new' do
28
28
  self.class.stack_string = params[:stack]
29
- redirect "#{rails_prefix}/stack"
29
+ redirect "#{path_prefix}/stack"
30
30
  end
31
31
 
32
32
  get '/stack' do
@@ -38,18 +38,22 @@ module CodeBuddy
38
38
  display_stack(params[:selected].to_i)
39
39
  end
40
40
 
41
+ get '/edit/:selected' do
42
+ self.class.stack.edit(params[:selected].to_i)
43
+ end
44
+
41
45
  def display_stack(selected_param)
42
46
  @stack = self.class.stack
43
47
  if @stack
44
48
  @stack.selected = selected_param
45
49
  erb :index
46
50
  else
47
- redirect "#{rails_prefix}/new"
51
+ redirect "#{path_prefix}/new"
48
52
  end
49
53
  end
50
54
 
51
- def rails_prefix
52
- self.class.rails ? '/code_buddy' : ''
55
+ def path_prefix
56
+ self.class.path_prefix
53
57
  end
54
58
 
55
59
  end
@@ -5,7 +5,7 @@ module CodeBuddy
5
5
  end
6
6
 
7
7
  def call(env)
8
- if env['PATH_INFO'] =~ /^\/code_buddy(.*)/ && Rails.env.development?
8
+ if env['PATH_INFO'] =~ /^\/code_buddy(.*)/ #&& Rails.env.development?
9
9
  env['PATH_INFO'] = $1
10
10
  App.new.call(env)
11
11
  else
@@ -1,16 +1,31 @@
1
- var Address = Backbone.Model.extend({
1
+ var CodeBuddy = {
2
+ stack : null,
3
+ stackView : null,
4
+ backbone : {}
5
+ }
6
+
7
+ CodeBuddy.backbone.Address = Backbone.Model.extend({
2
8
  selected: function() {
3
- return stack.selectedAddress() == this
4
- },
9
+ return CodeBuddy.stack.selectedAddress() == this
10
+ },
5
11
  });
6
12
 
7
- var Addresses = Backbone.Collection.extend({model:Address})
13
+ CodeBuddy.backbone.Addresses = Backbone.Collection.extend({
14
+ model:CodeBuddy.backbone.Address,
15
+
16
+ bookmarked: function() {
17
+ return this.select(function(address){
18
+ return address.get('bookmarked');
19
+ })
20
+ }
21
+ })
8
22
 
9
- var Stack = Backbone.Model.extend({
23
+ CodeBuddy.backbone.Stack = Backbone.Model.extend({
10
24
  initialize: function() {
25
+ _.bindAll(this, 'toggleBookmark', 'selectNextBookmark')
11
26
  this.bind('change:selected', this.selectionChanged);
12
27
  this.set({
13
- addresses: new Addresses(this.get('stack_frames'))
28
+ addresses: new CodeBuddy.backbone.Addresses(this.get('stack_frames'))
14
29
  })
15
30
  },
16
31
 
@@ -19,6 +34,14 @@ var Stack = Backbone.Model.extend({
19
34
  this.set({ selected: newSelected })
20
35
  }
21
36
  },
37
+
38
+ selectPrevious: function() {
39
+ this.setSelection(this.get('selected') - 1)
40
+ },
41
+
42
+ selectNext: function() {
43
+ this.setSelection(this.get('selected') + 1)
44
+ },
22
45
 
23
46
  addresses: function() {
24
47
  return this.get('addresses')
@@ -30,100 +53,138 @@ var Stack = Backbone.Model.extend({
30
53
  },
31
54
 
32
55
  selectionChanged: function(x) {
33
- this.updateSelectedAddress(x)
34
- this.view.render()
35
- },
36
-
37
- updateSelectedAddress: function(x) {
38
56
  this.addresses().at(x.previousAttributes().selected).view.render()
39
57
  this.addresses().at(x.changedAttributes().selected).view.render()
40
- }
58
+ this.view.render()
59
+ },
41
60
 
61
+ toggleBookmark: function() {
62
+ this.selectedAddress().set({bookmarked:!this.get('bookmarked')})
63
+ this.selectedAddress().view.render();
64
+ },
42
65
 
66
+ selectNextBookmark: function() {
67
+ var bookmarked = this.addresses().bookmarked();
68
+ var length = bookmarked.length;
69
+ var toSelect;
70
+ if(length > 0) {
71
+ var current = _.indexOf(bookmarked, this.selectedAddress())
72
+ if(current > -1 && current < length - 1) {
73
+ toSelect = bookmarked[current + 1]
74
+ } else {
75
+ toSelect = bookmarked[0]
76
+ }
77
+ return this.setSelection(toSelect.cid.substr(1)-1)
78
+ }
79
+ }
43
80
  });
44
81
 
45
82
  // ADDRESS VIEW - SELECTED ADDRESS IN BOLD
46
- var AddressView = Backbone.View.extend({
83
+ CodeBuddy.backbone.AddressView = Backbone.View.extend({
47
84
  tagName: "li",
48
85
 
49
86
  template: _.template("<span class='container'><%= path %>:<%= line%><span class='overlay'></span></span>"),
50
87
 
51
88
  initialize: function() {
52
- _.bindAll(this, 'render', 'close');
53
- this.model.bind('change', this.render);
54
89
  this.model.view = this;
55
90
  },
56
91
 
57
92
  events: {
58
- click: "open"
93
+ click: "open",
94
+ dblclick: "toggleBookmark"
59
95
  },
96
+
60
97
  open: function() {
61
- stack.set({selected: this.model.cid.substr(1)-1});
98
+ CodeBuddy.stack.set({selected: this.model.cid.substr(1)-1});
99
+ },
100
+
101
+ toggleBookmark: function() {
102
+ this.open();
103
+ CodeBuddy.stack.toggleBookmark();
62
104
  },
63
105
 
64
106
  render: function() {
107
+ $(this.el).removeClass('selected bookmarked')
108
+
65
109
  var html = this.template(this.model.toJSON())
66
110
 
67
111
  $(this.el).html(html);
68
112
  if (this.model.selected()) {
69
113
  $(this.el).addClass('selected')
70
- } else {
71
- $(this.el).removeClass('selected')
114
+ }
115
+ if (this.model.get('bookmarked')) {
116
+ $(this.el).addClass('bookmarked')
72
117
  }
73
118
  return this;
74
119
  }
75
120
  })
76
121
 
77
122
  // STACK VIEW - LOGIC FOR ASSIGNING EACH ADDRESS VIEW TO EACH LI TAG
78
- var StackView = Backbone.View.extend({
123
+ CodeBuddy.backbone.StackView = Backbone.View.extend({
79
124
 
80
125
  el: $("#stack"),
81
126
 
82
- events: {
83
- "keypress #stack" : "changeSelectionOnArrow"
84
- },
85
-
86
127
  initialize: function() {
87
- _.bindAll(this, 'render', 'close');
88
- this.model.bind('change', this.render);
128
+ _.bindAll(this, 'selectNext', 'selectPrevious')
89
129
  this.model.view = this;
90
-
91
130
  this.model.get('addresses').each(this.addOneAddress);
92
131
  },
93
-
94
- changeSelectionOnArrow: function(event) {
95
- var origSelection = this.model.get('selected')
96
- var newSelection = origSelection
97
- if (event.keyCode == 38) {
98
- newSelection = origSelection - 1
99
- } else if (event.keyCode == 40) {
100
- newSelection = origSelection + 1
101
- }
102
- if (newSelection != origSelection) {
103
- this.model.setSelection(newSelection)
104
-
105
- var offset = $(stack.selectedAddress().view.el).offset()
106
- var windowHeight = $(window).height()
107
- if (offset.top > windowHeight + $(window).scrollTop() - 10) {
108
- // scroll down
109
- $('html,body').animate({scrollTop: offset.top - 200}, 500);
110
- } else if (offset.top < $(window).scrollTop() + 100) {
111
- // scroll up
112
- $('html,body').animate({scrollTop: offset.top - 500}, 500);
113
- }
114
- return false
115
- } else {
116
- return true
132
+
133
+ selectPrevious: function() {
134
+ this.model.selectPrevious();
135
+ this.ensureVisibility();
136
+ return false;
137
+ },
138
+
139
+ selectNext: function() {
140
+ this.model.selectNext();
141
+ this.ensureVisibility();
142
+ return false;
143
+ },
144
+
145
+ ensureVisibility: function() {
146
+ var offset = $(CodeBuddy.stack.selectedAddress().view.el).offset()
147
+ var windowHeight = $(window).height()
148
+ if (offset.top > windowHeight + $(window).scrollTop() - 10) {
149
+ // scroll down
150
+ $('html,body').animate({scrollTop: offset.top - 200}, 500);
151
+ } else if (offset.top < $(window).scrollTop() + 100) {
152
+ // scroll up
153
+ $('html,body').animate({scrollTop: offset.top - 500}, 500);
117
154
  }
155
+ return false
118
156
  },
119
157
 
120
158
  addOneAddress: function(address, index) {
121
- var view = new AddressView({model: address});
159
+ var view = new CodeBuddy.backbone.AddressView({model: address});
122
160
  this.$("#stack").append(view.render().el);
123
161
  },
124
162
 
125
163
  render: function() {
126
164
  $('#code').html(this.model.selectedAddress().get('code'))
165
+ },
166
+
167
+ toggleCodeWindow: function() {
168
+ $('#code').toggle()
169
+ },
170
+
171
+ editCode: function() {
172
+ $.get('../edit/' + CodeBuddy.stack.get('selected'))
127
173
  }
174
+ })
128
175
 
129
- })
176
+ CodeBuddy.setKeyBindings = function(){
177
+ $(document).bind('keydown', 'up', CodeBuddy.stackView.selectPrevious)
178
+ $(document).bind('keydown', 'down', CodeBuddy.stackView.selectNext)
179
+ $(document).bind('keydown', 'a', CodeBuddy.stack.toggleBookmark)
180
+ $(document).bind('keydown', 's', CodeBuddy.stack.selectNextBookmark)
181
+ $(document).bind('keydown', 'h', CodeBuddy.stackView.toggleCodeWindow)
182
+ $(document).bind('keydown', 'e', CodeBuddy.stackView.editCode)
183
+ }
184
+
185
+ CodeBuddy.setup = function(stackJson) {
186
+ this.stack = new this.backbone.Stack(stackJson);
187
+ this.stackView = new this.backbone.StackView({model: this.stack});
188
+ this.stackView.render();
189
+ this.setKeyBindings();
190
+ }
@@ -0,0 +1,99 @@
1
+ /*
2
+ * jQuery Hotkeys Plugin
3
+ * Copyright 2010, John Resig
4
+ * Dual licensed under the MIT or GPL Version 2 licenses.
5
+ *
6
+ * Based upon the plugin by Tzury Bar Yochay:
7
+ * http://github.com/tzuryby/hotkeys
8
+ *
9
+ * Original idea by:
10
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
11
+ */
12
+
13
+ (function(jQuery){
14
+
15
+ jQuery.hotkeys = {
16
+ version: "0.8",
17
+
18
+ specialKeys: {
19
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
20
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
21
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
22
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
23
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
24
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
25
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
26
+ },
27
+
28
+ shiftNums: {
29
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
30
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
31
+ ".": ">", "/": "?", "\\": "|"
32
+ }
33
+ };
34
+
35
+ function keyHandler( handleObj ) {
36
+ // Only care when a possible input has been specified
37
+ if ( typeof handleObj.data !== "string" ) {
38
+ return;
39
+ }
40
+
41
+ var origHandler = handleObj.handler,
42
+ keys = handleObj.data.toLowerCase().split(" ");
43
+
44
+ handleObj.handler = function( event ) {
45
+ // Don't fire in text-accepting inputs that we didn't directly bind to
46
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
47
+ event.target.type === "text") ) {
48
+ return;
49
+ }
50
+
51
+ // Keypress represents characters, not special keys
52
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
53
+ character = String.fromCharCode( event.which ).toLowerCase(),
54
+ key, modif = "", possible = {};
55
+
56
+ // check combinations (alt|ctrl|shift+anything)
57
+ if ( event.altKey && special !== "alt" ) {
58
+ modif += "alt+";
59
+ }
60
+
61
+ if ( event.ctrlKey && special !== "ctrl" ) {
62
+ modif += "ctrl+";
63
+ }
64
+
65
+ // TODO: Need to make sure this works consistently across platforms
66
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
67
+ modif += "meta+";
68
+ }
69
+
70
+ if ( event.shiftKey && special !== "shift" ) {
71
+ modif += "shift+";
72
+ }
73
+
74
+ if ( special ) {
75
+ possible[ modif + special ] = true;
76
+
77
+ } else {
78
+ possible[ modif + character ] = true;
79
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
80
+
81
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
82
+ if ( modif === "shift+" ) {
83
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
84
+ }
85
+ }
86
+
87
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
88
+ if ( possible[ keys[i] ] ) {
89
+ return origHandler.apply( this, arguments );
90
+ }
91
+ }
92
+ };
93
+ }
94
+
95
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
96
+ jQuery.event.special[ this ] = { add: keyHandler };
97
+ });
98
+
99
+ })( jQuery );
@@ -108,4 +108,8 @@ li {
108
108
  li:hover {
109
109
  background:#444;
110
110
  cursor:pointer;
111
+ }
112
+
113
+ .bookmarked {
114
+ background:#666;
111
115
  }
@@ -17,3 +17,5 @@ module ActionController
17
17
  end
18
18
  end
19
19
  end
20
+
21
+ CodeBuddy::App.path_prefix = '/code_buddy'
@@ -6,6 +6,7 @@ module CodeBuddy
6
6
  app.middleware.insert_before CodeBuddy::ShowExceptions, CodeBuddy::ShowApp
7
7
  end
8
8
  end
9
+ CodeBuddy::App.path_prefix = '/code_buddy'
9
10
  end
10
11
 
11
12
  class ShowExceptions < ActionDispatch::ShowExceptions
@@ -20,3 +21,5 @@ module CodeBuddy
20
21
  end
21
22
  end
22
23
  end
24
+
25
+
@@ -5,15 +5,19 @@ module CodeBuddy
5
5
 
6
6
  def initialize(exception_or_string)
7
7
  if exception_or_string.is_a?(Exception)
8
- @selected = selected
9
- @stack_frames = exception_or_string.backtrace.collect do |string|
10
- StackFrame.new(string)
11
- end
8
+ backtrace = exception_or_string.backtrace
9
+ backtrace = backtrace.first.split("\n") if backtrace.size == 1 #haml errors come through this way
12
10
  else
13
- @stack_frames = exception_or_string.collect do |string|
14
- StackFrame.new(string)
15
- end
11
+ backtrace = exception_or_string
16
12
  end
13
+
14
+ @stack_frames = backtrace.collect do |string|
15
+ StackFrame.new(string)
16
+ end
17
+ end
18
+
19
+ def edit(index)
20
+ @stack_frames[index].open_in_editor
17
21
  end
18
22
  end
19
23
  end
@@ -39,5 +39,16 @@ module CodeBuddy
39
39
  "<span class=\"coderay\">Unable to read file:\n&nbsp;\"#{@path}\"</span>"
40
40
  end
41
41
  end
42
+
43
+ def open_in_editor
44
+ case ENV['EDITOR']
45
+ when 'mate'
46
+ `mate #{path} -l #{line}`
47
+ when 'mvim'
48
+ `mvim +#{line} #{path}`
49
+ else
50
+ puts "Sorry unable to open the file for editing. Please set your environment variable to either mate or mvim 'export EDITOR=mate' and restart the server"
51
+ end
52
+ end
42
53
  end
43
54
  end
@@ -1,3 +1,3 @@
1
1
  module CodeBuddy
2
- VERSION = "0.0.6"
2
+ VERSION = '0.0.7'
3
3
  end
@@ -3,6 +3,7 @@
3
3
  <link href="<%= @static_file_prefix %>stylesheets/code_buddy.css" media="screen" rel="stylesheet" type="text/css" />
4
4
  <link href="<%= @static_file_prefix %>stylesheets/coderay.css" media="screen" rel="stylesheet" type="text/css" />
5
5
  <script src="<%= @static_file_prefix %>javascripts/jquery.js" type="text/javascript"></script>
6
+ <script src="<%= @static_file_prefix %>javascripts/jquery.hotkeys.js" type="text/javascript"></script>
6
7
  <script src="<%= @static_file_prefix %>javascripts/underscore.js" type="text/javascript"></script>
7
8
  <script src="<%= @static_file_prefix %>javascripts/backbone.js" type="text/javascript"></script>
8
9
  </head>
@@ -14,12 +14,7 @@
14
14
  <div id='code'></div>
15
15
  <script src="<%= @static_file_prefix %>javascripts/code_buddy.js" type="text/javascript"></script>
16
16
  <script>
17
- var stack = new Stack(<%= @stack.to_json %>);
18
- var stackView = new StackView({model: stack});
19
- stackView.render();
20
- $(document).keydown(function(event) {
21
- return stack.view.changeSelectionOnArrow(event)
22
- })
17
+ CodeBuddy.setup(<%= @stack.to_json %>)
23
18
  </script>
24
19
  </body>
25
20
  </html>
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_buddy
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 17
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 0
8
- - 6
9
- version: 0.0.6
9
+ - 7
10
+ version: 0.0.7
10
11
  platform: ruby
11
12
  authors:
12
13
  - Pat Shaughnessy, Alex Rothenberg, Daniel Higginbotham
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-12-13 00:00:00 -05:00
18
+ date: 2011-01-04 00:00:00 -05:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: rack
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -33,9 +36,11 @@ dependencies:
33
36
  name: sinatra
34
37
  prerelease: false
35
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
36
40
  requirements:
37
41
  - - ~>
38
42
  - !ruby/object:Gem::Version
43
+ hash: 19
39
44
  segments:
40
45
  - 1
41
46
  - 1
@@ -47,9 +52,11 @@ dependencies:
47
52
  name: json_pure
48
53
  prerelease: false
49
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
50
56
  requirements:
51
57
  - - ~>
52
58
  - !ruby/object:Gem::Version
59
+ hash: 11
53
60
  segments:
54
61
  - 1
55
62
  - 4
@@ -61,9 +68,11 @@ dependencies:
61
68
  name: coderay
62
69
  prerelease: false
63
70
  requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
64
72
  requirements:
65
73
  - - ~>
66
74
  - !ruby/object:Gem::Version
75
+ hash: 55
67
76
  segments:
68
77
  - 0
69
78
  - 9
@@ -75,9 +84,11 @@ dependencies:
75
84
  name: rake
76
85
  prerelease: false
77
86
  requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
78
88
  requirements:
79
89
  - - ~>
80
90
  - !ruby/object:Gem::Version
91
+ hash: 49
81
92
  segments:
82
93
  - 0
83
94
  - 8
@@ -89,9 +100,11 @@ dependencies:
89
100
  name: rspec
90
101
  prerelease: false
91
102
  requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
92
104
  requirements:
93
105
  - - ~>
94
106
  - !ruby/object:Gem::Version
107
+ hash: 7
95
108
  segments:
96
109
  - 2
97
110
  - 2
@@ -103,9 +116,11 @@ dependencies:
103
116
  name: mocha
104
117
  prerelease: false
105
118
  requirement: &id007 !ruby/object:Gem::Requirement
119
+ none: false
106
120
  requirements:
107
121
  - - ~>
108
122
  - !ruby/object:Gem::Version
123
+ hash: 47
109
124
  segments:
110
125
  - 0
111
126
  - 9
@@ -113,6 +128,38 @@ dependencies:
113
128
  version: 0.9.10
114
129
  type: :development
115
130
  version_requirements: *id007
131
+ - !ruby/object:Gem::Dependency
132
+ name: cucumber
133
+ prerelease: false
134
+ requirement: &id008 !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ hash: 51
140
+ segments:
141
+ - 0
142
+ - 9
143
+ - 4
144
+ version: 0.9.4
145
+ type: :development
146
+ version_requirements: *id008
147
+ - !ruby/object:Gem::Dependency
148
+ name: aruba
149
+ prerelease: false
150
+ requirement: &id009 !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ~>
154
+ - !ruby/object:Gem::Version
155
+ hash: 19
156
+ segments:
157
+ - 0
158
+ - 2
159
+ - 2
160
+ version: 0.2.2
161
+ type: :development
162
+ version_requirements: *id009
116
163
  description: See the Ruby code running in your app.
117
164
  email:
118
165
  - pat@patshaughnessy.net, alex@alexrothenberg.com, daniel@flyingmachinestudios.com
@@ -126,18 +173,28 @@ files:
126
173
  - .gitignore
127
174
  - .rvmrc
128
175
  - Gemfile
129
- - Gemfile.lock
176
+ - History.md
130
177
  - LICENSE
131
178
  - README.rdoc
132
179
  - Rakefile
133
180
  - bin/code_buddy
134
181
  - code_buddy.gemspec
182
+ - features/rails2_app.feature
183
+ - features/rails3_app.feature
184
+ - features/sinatra.feature
185
+ - features/step_definitions/rails_setup_steps.rb
186
+ - features/support/env.rb
187
+ - features/templates/rails_exception.feature.template
188
+ - features/templates/sinatra_env.rb.template
189
+ - features/templates/sinatra_homepage.feature.template
190
+ - features/templates/sinatra_paths.rb.template
135
191
  - lib/code_buddy.rb
136
192
  - lib/code_buddy/app.rb
137
193
  - lib/code_buddy/middleware.rb
138
194
  - lib/code_buddy/public/images/buddy.jpeg
139
195
  - lib/code_buddy/public/javascripts/backbone.js
140
196
  - lib/code_buddy/public/javascripts/code_buddy.js
197
+ - lib/code_buddy/public/javascripts/jquery.hotkeys.js
141
198
  - lib/code_buddy/public/javascripts/jquery.js
142
199
  - lib/code_buddy/public/javascripts/underscore.js
143
200
  - lib/code_buddy/public/stylesheets/code_buddy.css
@@ -182,27 +239,40 @@ rdoc_options: []
182
239
  require_paths:
183
240
  - lib
184
241
  required_ruby_version: !ruby/object:Gem::Requirement
242
+ none: false
185
243
  requirements:
186
244
  - - ">="
187
245
  - !ruby/object:Gem::Version
246
+ hash: 3
188
247
  segments:
189
248
  - 0
190
249
  version: "0"
191
250
  required_rubygems_version: !ruby/object:Gem::Requirement
251
+ none: false
192
252
  requirements:
193
253
  - - ">="
194
254
  - !ruby/object:Gem::Version
255
+ hash: 3
195
256
  segments:
196
257
  - 0
197
258
  version: "0"
198
259
  requirements: []
199
260
 
200
261
  rubyforge_project: code_buddy
201
- rubygems_version: 1.3.6
262
+ rubygems_version: 1.3.7
202
263
  signing_key:
203
264
  specification_version: 3
204
265
  summary: See the Ruby code running in your app.
205
266
  test_files:
267
+ - features/rails2_app.feature
268
+ - features/rails3_app.feature
269
+ - features/sinatra.feature
270
+ - features/step_definitions/rails_setup_steps.rb
271
+ - features/support/env.rb
272
+ - features/templates/rails_exception.feature.template
273
+ - features/templates/sinatra_env.rb.template
274
+ - features/templates/sinatra_homepage.feature.template
275
+ - features/templates/sinatra_paths.rb.template
206
276
  - spec/app_spec.rb
207
277
  - spec/middleware_spec.rb
208
278
  - spec/spec_helper.rb
@@ -1,44 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- code_buddy (0.0.6)
5
- coderay (~> 0.9.6)
6
- json_pure (~> 1.4.6)
7
- rack
8
- sinatra (~> 1.1.0)
9
-
10
- GEM
11
- remote: http://rubygems.org/
12
- specs:
13
- coderay (0.9.6)
14
- diff-lcs (1.1.2)
15
- json_pure (1.4.6)
16
- mocha (0.9.10)
17
- rake
18
- rack (1.2.1)
19
- rake (0.8.7)
20
- rspec (2.2.0)
21
- rspec-core (~> 2.2)
22
- rspec-expectations (~> 2.2)
23
- rspec-mocks (~> 2.2)
24
- rspec-core (2.2.1)
25
- rspec-expectations (2.2.0)
26
- diff-lcs (~> 1.1.2)
27
- rspec-mocks (2.2.0)
28
- sinatra (1.1.0)
29
- rack (~> 1.1)
30
- tilt (~> 1.1)
31
- tilt (1.1)
32
-
33
- PLATFORMS
34
- ruby
35
-
36
- DEPENDENCIES
37
- code_buddy!
38
- coderay (~> 0.9.6)
39
- json_pure (~> 1.4.6)
40
- mocha (~> 0.9.10)
41
- rack
42
- rake (~> 0.8.7)
43
- rspec (~> 2.2.0)
44
- sinatra (~> 1.1.0)