web-console 2.0.0.beta2 → 2.0.0.beta3

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.markdown +304 -19
  4. data/app/assets/javascripts/web_console/application.js +1 -0
  5. data/app/assets/javascripts/web_console/console_sessions.js +172 -0
  6. data/app/assets/stylesheets/web_console/application.css +13 -0
  7. data/app/assets/stylesheets/web_console/console_sessions.css.erb +6 -0
  8. data/app/controllers/web_console/application_controller.rb +13 -0
  9. data/app/controllers/web_console/console_sessions_controller.rb +43 -0
  10. data/app/helpers/web_console/application_helper.rb +4 -0
  11. data/app/helpers/web_console/console_session_helper.rb +4 -0
  12. data/app/models/web_console/console_session.rb +96 -0
  13. data/app/views/layouts/web_console/application.html.erb +14 -0
  14. data/app/views/web_console/console_sessions/index.html.erb +15 -0
  15. data/config/routes.rb +11 -0
  16. data/lib/action_dispatch/debug_exceptions.rb +69 -69
  17. data/lib/action_dispatch/exception_wrapper.rb +2 -1
  18. data/lib/assets/javascripts/web-console.js +1 -0
  19. data/lib/assets/javascripts/web_console.js +41 -0
  20. data/lib/web_console.rb +14 -15
  21. data/lib/web_console/colors.rb +87 -0
  22. data/lib/web_console/colors/light.rb +24 -0
  23. data/lib/web_console/colors/monokai.rb +24 -0
  24. data/lib/web_console/colors/solarized.rb +47 -0
  25. data/lib/web_console/colors/tango.rb +24 -0
  26. data/lib/web_console/colors/xterm.rb +24 -0
  27. data/lib/web_console/engine.rb +95 -0
  28. data/lib/web_console/exception_extension.rb +10 -11
  29. data/lib/web_console/repl_session.rb +5 -3
  30. data/lib/web_console/slave.rb +139 -0
  31. data/lib/web_console/version.rb +1 -1
  32. data/lib/web_console/view_helpers.rb +3 -7
  33. data/test/controllers/web_console/console_sessions_controller_test.rb +95 -0
  34. data/test/dummy/app/controllers/exception_test_controller.rb +4 -0
  35. data/test/dummy/app/views/exception_test/xhr.html.erb +1 -0
  36. data/test/dummy/config/application.rb +37 -1
  37. data/test/dummy/config/environments/test.rb +2 -0
  38. data/test/dummy/config/routes.rb +1 -0
  39. data/test/dummy/db/development.sqlite3 +0 -0
  40. data/test/dummy/log/development.log +61814 -0
  41. data/test/dummy/log/test.log +8621 -3
  42. data/test/dummy/tmp/cache/assets/development/sprockets/038461854af2e8bccdb29768efd4768f +0 -0
  43. data/test/dummy/tmp/cache/assets/development/sprockets/0ec396634a5f6808b026257fd107c355 +0 -0
  44. data/test/dummy/tmp/cache/assets/development/sprockets/127a54171eea8d294e4673599861787d +0 -0
  45. data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  46. data/test/dummy/tmp/cache/assets/development/sprockets/17c571144b4e44da39bddb2d2c412414 +0 -0
  47. data/test/dummy/tmp/cache/assets/development/sprockets/1cb77d8cf661ccbc9de08f347c89b9f1 +0 -0
  48. data/test/dummy/tmp/cache/assets/development/sprockets/204edd12a29660722d4e0d8de9bd6652 +0 -0
  49. data/test/dummy/tmp/cache/assets/development/sprockets/2b96b037f3dfeccfe27113eb95b06ea1 +0 -0
  50. data/test/dummy/tmp/cache/assets/development/sprockets/2c853768baf811357d81d41bdfd05dcf +0 -0
  51. data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  52. data/test/dummy/tmp/cache/assets/development/sprockets/314d48e543146f617c4d3439a4d8d40d +0 -0
  53. data/test/dummy/tmp/cache/assets/development/sprockets/34f21019a876722b8c24a6da4f0ef50b +0 -0
  54. data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  55. data/test/dummy/tmp/cache/assets/development/sprockets/36341e42f23669574fa1027d0958ff3e +0 -0
  56. data/test/dummy/tmp/cache/assets/development/sprockets/44117154e909436e7eeaf10cdb18d2b4 +0 -0
  57. data/test/dummy/tmp/cache/assets/development/sprockets/496864a905d53afd8e176f29500f96a8 +0 -0
  58. data/test/dummy/tmp/cache/assets/development/sprockets/55b7b76605fdffe31d737d4ac1f1ef7b +0 -0
  59. data/test/dummy/tmp/cache/assets/development/sprockets/5ac98782fe3dfd0a766f75ce1801f0a0 +0 -0
  60. data/test/dummy/tmp/cache/assets/development/sprockets/6088d6f344b38303cc8028057d69e0f9 +0 -0
  61. data/test/dummy/tmp/cache/assets/development/sprockets/676dcf9b2d01b9dc7bd3183d8da88463 +0 -0
  62. data/test/dummy/tmp/cache/assets/development/sprockets/680381170dc160e358fc28076ea6886c +0 -0
  63. data/test/dummy/tmp/cache/assets/development/sprockets/6ad7acc9a22fe2a67ec24a1fc866c20e +0 -0
  64. data/test/dummy/tmp/cache/assets/development/sprockets/6bdb0d0c602e0e1bc304dc697e2cc6de +0 -0
  65. data/test/dummy/tmp/cache/assets/development/sprockets/6dc8d7aa69668fce85683aaad6615432 +0 -0
  66. data/test/dummy/tmp/cache/assets/development/sprockets/6e4d5b32cc444226f6597198994ccd5e +0 -0
  67. data/test/dummy/tmp/cache/assets/development/sprockets/74db0ca5cb8c8c347c9131a3ff516748 +0 -0
  68. data/test/dummy/tmp/cache/assets/development/sprockets/7999e525c88173c1beb785f002effc1d +0 -0
  69. data/test/dummy/tmp/cache/assets/development/sprockets/7a50a9e605754e99783de95715b976b0 +0 -0
  70. data/test/dummy/tmp/cache/assets/development/sprockets/806b0e33a2fe8e1245534345fa27c30a +0 -0
  71. data/test/dummy/tmp/cache/assets/development/sprockets/8aa4c7aabff23c8089d41e9e54193483 +0 -0
  72. data/test/dummy/tmp/cache/assets/development/sprockets/90396626cba6cbec37e32038e6c54e76 +0 -0
  73. data/test/dummy/tmp/cache/assets/development/sprockets/976b28910aa72c90a3b30c6e940f51df +0 -0
  74. data/test/dummy/tmp/cache/assets/development/sprockets/99e1bd7cbc437505bc8f07bc528c721c +0 -0
  75. data/test/dummy/tmp/cache/assets/development/sprockets/aaccf2c9ae2add0863c9a49e0042a097 +0 -0
  76. data/test/dummy/tmp/cache/assets/development/sprockets/ae4677d24a79d9411f2fced5011d5807 +0 -0
  77. data/test/dummy/tmp/cache/assets/development/sprockets/b2401118729720034b6f3eda0b4c5025 +0 -0
  78. data/test/dummy/tmp/cache/assets/development/sprockets/c649837df826fc310cb80f1adafd6b8d +0 -0
  79. data/test/dummy/tmp/cache/assets/development/sprockets/cac185d59612fae451a12df3fc21bb51 +0 -0
  80. data/test/dummy/tmp/cache/assets/development/sprockets/cb0065359d3b5b296f71d673f4b276e9 +0 -0
  81. data/test/dummy/tmp/cache/assets/development/sprockets/cee8c6b09c33d2b276753e959712724e +0 -0
  82. data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  83. data/test/dummy/tmp/cache/assets/development/sprockets/d1f6e06bc2f112c4ec3a4c3f68351878 +0 -0
  84. data/test/dummy/tmp/cache/assets/development/sprockets/d20d83fd7ffa378b1b2b901786d640f3 +0 -0
  85. data/test/dummy/tmp/cache/assets/development/sprockets/d38c7c3aa1e72b55769ccb3607641ef4 +0 -0
  86. data/test/dummy/tmp/cache/assets/development/sprockets/d6b85d8b0b5c569388b89e56e9f6fed7 +0 -0
  87. data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  88. data/test/dummy/tmp/cache/assets/development/sprockets/d982412def520c434e2240eae6d29cf2 +0 -0
  89. data/test/dummy/tmp/cache/assets/development/sprockets/df048a8b0897b9c04acdf59c8f95b18f +0 -0
  90. data/test/dummy/tmp/cache/assets/development/sprockets/df600f50f002512c95d93bcfbab891ed +0 -0
  91. data/test/dummy/tmp/cache/assets/development/sprockets/e6d6b8bde546349764be7b44ffcf5807 +0 -0
  92. data/test/dummy/tmp/cache/assets/development/sprockets/eb25265794d2f7afd1684779d84efdac +0 -0
  93. data/test/dummy/tmp/cache/assets/development/sprockets/ee8826b12b7d9bfd717df950b58f82ab +0 -0
  94. data/test/dummy/tmp/cache/assets/development/sprockets/ef9824789c6ed3483590e0564a12e1d1 +0 -0
  95. data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  96. data/test/dummy/tmp/cache/assets/development/sprockets/fc7201c6cbef32453aa4175c520c8eae +0 -0
  97. data/test/dummy/tmp/cache/assets/test/sprockets/17c571144b4e44da39bddb2d2c412414 +0 -0
  98. data/test/dummy/tmp/cache/assets/test/sprockets/36341e42f23669574fa1027d0958ff3e +0 -0
  99. data/test/dummy/tmp/cache/assets/test/sprockets/55b7b76605fdffe31d737d4ac1f1ef7b +0 -0
  100. data/test/dummy/tmp/cache/assets/test/sprockets/5ac98782fe3dfd0a766f75ce1801f0a0 +0 -0
  101. data/test/dummy/tmp/cache/assets/test/sprockets/680381170dc160e358fc28076ea6886c +0 -0
  102. data/test/dummy/tmp/cache/assets/test/sprockets/6ad7acc9a22fe2a67ec24a1fc866c20e +0 -0
  103. data/test/dummy/tmp/cache/assets/test/sprockets/6e4d5b32cc444226f6597198994ccd5e +0 -0
  104. data/test/dummy/tmp/cache/assets/test/sprockets/7a50a9e605754e99783de95715b976b0 +0 -0
  105. data/test/dummy/tmp/cache/assets/test/sprockets/8aa4c7aabff23c8089d41e9e54193483 +0 -0
  106. data/test/dummy/tmp/cache/assets/test/sprockets/b2401118729720034b6f3eda0b4c5025 +0 -0
  107. data/test/dummy/tmp/cache/assets/test/sprockets/cb0065359d3b5b296f71d673f4b276e9 +0 -0
  108. data/test/dummy/tmp/cache/assets/test/sprockets/d1f6e06bc2f112c4ec3a4c3f68351878 +0 -0
  109. data/test/dummy/tmp/cache/assets/test/sprockets/d6b85d8b0b5c569388b89e56e9f6fed7 +0 -0
  110. data/test/dummy/tmp/cache/assets/test/sprockets/d982412def520c434e2240eae6d29cf2 +0 -0
  111. data/test/dummy/tmp/cache/assets/test/sprockets/df048a8b0897b9c04acdf59c8f95b18f +0 -0
  112. data/test/dummy/tmp/cache/assets/test/sprockets/e6d6b8bde546349764be7b44ffcf5807 +0 -0
  113. data/test/models/console_session_test.rb +58 -0
  114. data/test/web_console/colors_test.rb +58 -0
  115. data/test/web_console/engine_test.rb +136 -0
  116. data/test/web_console/slave_test.rb +71 -0
  117. data/vendor/assets/javascripts/term.js +5726 -0
  118. metadata +188 -7
  119. data/lib/web_console/railtie.rb +0 -15
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,6 @@
1
+ <% WebConsole.config.style.instance_eval do %>
2
+ body { color: <%= colors.foreground %>; background: <%= colors.background %>; margin: 0; padding: 0; }
3
+
4
+ .terminal { float: left; overflow: hidden; font: <%= font %>; }
5
+ .terminal-cursor { color: <%= colors.background %>; background: <%= colors.foreground %>; }
6
+ <% end %>
@@ -0,0 +1,13 @@
1
+ module WebConsole
2
+ class ApplicationController < ActionController::Base
3
+ before_action :prevent_unauthorized_requests!
4
+
5
+ private
6
+
7
+ def prevent_unauthorized_requests!
8
+ unless request.remote_ip.in?(WebConsole.config.whitelisted_ips)
9
+ render nothing: true, status: :unauthorized
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ require_dependency 'web_console/application_controller'
2
+
3
+ module WebConsole
4
+ class ConsoleSessionsController < ApplicationController
5
+ rescue_from ConsoleSession::Unavailable do |exception|
6
+ render json: exception, status: :gone
7
+ end
8
+
9
+ rescue_from ConsoleSession::Invalid do |exception|
10
+ render json: exception, status: :unprocessable_entity
11
+ end
12
+
13
+ def index
14
+ @console_session = ConsoleSession.create
15
+ end
16
+
17
+ def input
18
+ @console_session = ConsoleSession.find(params[:id])
19
+ @console_session.send_input(console_session_params[:input])
20
+
21
+ render nothing: true
22
+ end
23
+
24
+ def configuration
25
+ @console_session = ConsoleSession.find(params[:id])
26
+ @console_session.configure(console_session_params)
27
+
28
+ render nothing: true
29
+ end
30
+
31
+ def pending_output
32
+ @console_session = ConsoleSession.find(params[:id])
33
+
34
+ render json: { output: @console_session.pending_output }
35
+ end
36
+
37
+ private
38
+
39
+ def console_session_params
40
+ params.permit(:id, :input, :width, :height)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ module WebConsole
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module WebConsole
2
+ module ConsoleSessionHelper
3
+ end
4
+ end
@@ -0,0 +1,96 @@
1
+ module WebConsole
2
+ # Manage and persist (in memory) WebConsole::Slave instances.
3
+ class ConsoleSession
4
+ include ActiveModel::Model
5
+
6
+ # In-memory storage for the console sessions. Session preservation is
7
+ # troubled on servers with multiple workers and threads.
8
+ INMEMORY_STORAGE = {}
9
+
10
+ # Base error class for ConsoleSession specific exceptions.
11
+ #
12
+ # Provides #to_json implementation, so all subclasses are JSON
13
+ # serializable.
14
+ class Error < StandardError
15
+ def to_json(*)
16
+ { error: to_s }.to_json
17
+ end
18
+ end
19
+
20
+ # Raised when trying to find a session that is no longer in the in-memory
21
+ # session storage or when the slave process exited.
22
+ Unavailable = Class.new(Error)
23
+
24
+ # Raised when an operation transition to an invalid state.
25
+ Invalid = Class.new(Error)
26
+
27
+ class << self
28
+ # Finds a session by its pid.
29
+ #
30
+ # Raises WebConsole::ConsoleSession::Expired if there is no such session.
31
+ def find(pid)
32
+ INMEMORY_STORAGE[pid.to_i] or raise Unavailable, 'Session unavailable'
33
+ end
34
+
35
+ # Creates an already persisted consolse session.
36
+ #
37
+ # Use this method if you need to persist a session, without providing it
38
+ # any input.
39
+ def create
40
+ new.persist
41
+ end
42
+ end
43
+
44
+ def initialize
45
+ @slave = WebConsole::Slave.new
46
+ end
47
+
48
+ # Explicitly persist the model in the in-memory storage.
49
+ def persist
50
+ INMEMORY_STORAGE[pid] = self
51
+ end
52
+
53
+ # Returns true if the current session is persisted in the in-memory storage.
54
+ def persisted?
55
+ self == INMEMORY_STORAGE[pid]
56
+ end
57
+
58
+ # Returns an Enumerable of all key attributes if any is set, regardless if
59
+ # the object is persisted or not.
60
+ def to_key
61
+ [pid] if persisted?
62
+ end
63
+
64
+ private
65
+
66
+ def delegate_and_call_slave_method(name, *args, &block)
67
+ # Cache the delegated method, so we don't have to hit #method_missing
68
+ # on every call.
69
+ define_singleton_method(name) do |*inner_args, &inner_block|
70
+ begin
71
+ @slave.public_send(name, *inner_args, &inner_block)
72
+ rescue ArgumentError => exc
73
+ raise Invalid, exc
74
+ rescue Slave::Closed => exc
75
+ raise Unavailable, exc
76
+ end
77
+ end
78
+
79
+ # Now call the method, since that's our most common use case. Delegate
80
+ # the method and than call it.
81
+ public_send(name, *args, &block)
82
+ end
83
+
84
+ def method_missing(name, *args, &block)
85
+ if @slave.respond_to?(name)
86
+ delegate_and_call_slave_method(name, *args, &block)
87
+ else
88
+ super
89
+ end
90
+ end
91
+
92
+ def respond_to_missing?(name, include_all = false)
93
+ @slave.respond_to?(name) or super
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>WebConsole</title>
5
+ <%= stylesheet_link_tag "web_console/application", media: "all" %>
6
+ <%= javascript_include_tag "web_console/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,15 @@
1
+ <script>
2
+ var config = {
3
+ terminal: {
4
+ colors: <%= raw WebConsole.config.style.colors.to_json %>
5
+ },
6
+
7
+ transport: {
8
+ url: {
9
+ input: "<%= web_console.input_console_session_path(@console_session) %>",
10
+ pendingOutput: "<%= web_console.pending_output_console_session_path(@console_session) %>",
11
+ configuration: "<%= web_console.configuration_console_session_path(@console_session) %>"
12
+ }
13
+ }
14
+ };
15
+ </script>
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ WebConsole::Engine.routes.draw do
2
+ root to: 'console_sessions#index'
3
+
4
+ resources :console_sessions do
5
+ member do
6
+ put :input
7
+ get :pending_output
8
+ put :configuration
9
+ end
10
+ end
11
+ end
@@ -30,86 +30,86 @@ module ActionDispatch
30
30
 
31
31
  private
32
32
 
33
- def update_repl_session(id, input)
34
- console_session = WebConsole::REPLSession.find(id)
35
- response = console_session.save({ input: input })
36
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [response.to_json]]
37
- end
38
-
39
- def change_stack_trace(id, frame_id)
40
- console_session = WebConsole::REPLSession.find(id)
41
- binding = console_session.binding_stack[frame_id.to_i]
42
- console_session.binding = binding
43
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump("success")]]
44
- end
33
+ def update_repl_session(id, input)
34
+ console_session = WebConsole::REPLSession.find(id)
35
+ response = console_session.save(input: input)
36
+ [ 200, { "Content-Type" => "text/plain; charset=utf-8" }, [ response.to_json ] ]
37
+ end
45
38
 
46
- def render_exception(env, exception)
47
- if exception.respond_to?(:original_exception) && exception.original_exception
48
- exception = exception.original_exception
39
+ def change_stack_trace(id, frame_id)
40
+ console_session = WebConsole::REPLSession.find(id)
41
+ binding = console_session.binding_stack[frame_id.to_i]
42
+ console_session.binding = binding
43
+ [ 200, { "Content-Type" => "text/plain; charset=utf-8" }, [ JSON.dump("success") ] ]
49
44
  end
50
45
 
51
- wrapper = ExceptionWrapper.new(env, exception)
52
- traces = traces_from_wrapper(wrapper)
53
- extract_sources = wrapper.extract_sources
54
- console_session = WebConsole::REPLSession.create(
55
- binding: binding_from_exception(exception),
56
- binding_stack: exception.__web_console_bindings_stack
57
- )
58
- log_error(env, wrapper)
59
-
60
- if env['action_dispatch.show_detailed_exceptions']
61
- request = Request.new(env)
62
- template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
63
- request: request,
64
- exception: wrapper.exception,
65
- application_trace: traces[:application_trace],
66
- framework_trace: traces[:framework_trace],
67
- full_trace: traces[:full_trace],
68
- routes_inspector: routes_inspector(exception),
69
- extract_sources: extract_sources,
70
- console_session: console_session
71
- )
72
- file = "rescues/#{wrapper.rescue_template}"
46
+ def render_exception(env, exception)
47
+ if exception.respond_to?(:original_exception) && exception.original_exception
48
+ exception = exception.original_exception
49
+ end
73
50
 
74
- if request.xhr?
75
- body = template.render(template: file, layout: false, formats: [:text])
76
- format = "text/plain"
51
+ wrapper = ExceptionWrapper.new(env, exception)
52
+ traces = traces_from_wrapper(wrapper)
53
+ extract_sources = wrapper.extract_sources
54
+ console_session = WebConsole::REPLSession.create(
55
+ binding: binding_from_exception(exception),
56
+ binding_stack: exception.__web_console_bindings_stack
57
+ )
58
+ log_error(env, wrapper)
59
+
60
+ if env['action_dispatch.show_detailed_exceptions']
61
+ request = Request.new(env)
62
+ template = ActionView::Base.new([ RESCUES_TEMPLATE_PATH ],
63
+ request: request,
64
+ exception: wrapper.exception,
65
+ application_trace: traces[:application_trace],
66
+ framework_trace: traces[:framework_trace],
67
+ full_trace: traces[:full_trace],
68
+ routes_inspector: routes_inspector(exception),
69
+ extract_sources: extract_sources,
70
+ console_session: console_session
71
+ )
72
+ file = "rescues/#{wrapper.rescue_template}"
73
+
74
+ if request.xhr?
75
+ body = template.render(template: file, layout: false, formats: [ :text ])
76
+ format = "text/plain"
77
+ else
78
+ body = template.render(template: file, layout: 'rescues/layout')
79
+ format = "text/html"
80
+ end
81
+
82
+ [ wrapper.status_code, { 'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s }, [ body ] ]
77
83
  else
78
- body = template.render(template: file, layout: 'rescues/layout')
79
- format = "text/html"
84
+ raise exception
80
85
  end
81
-
82
- [wrapper.status_code, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
83
- else
84
- raise exception
85
86
  end
86
- end
87
87
 
88
- # Augment the exception traces by providing ids for all unique stack frame
89
- def traces_from_wrapper(wrapper)
90
- id_counter = 0
88
+ # Augment the exception traces by providing ids for all unique stack frames.
89
+ def traces_from_wrapper(wrapper)
90
+ id_counter = 0
91
91
 
92
- application_trace = wrapper.application_trace.map do |trace|
93
- prev = id_counter
94
- id_counter += 1
95
- { id: prev, trace: trace }
96
- end
92
+ application_trace = wrapper.application_trace.map do |trace|
93
+ prev = id_counter
94
+ id_counter += 1
95
+ { id: prev, trace: trace }
96
+ end
97
97
 
98
- framework_trace = wrapper.framework_trace.map do |trace|
99
- prev = id_counter
100
- id_counter += 1
101
- { id: prev, trace: trace }
102
- end
98
+ framework_trace = wrapper.framework_trace.map do |trace|
99
+ prev = id_counter
100
+ id_counter += 1
101
+ { id: prev, trace: trace }
102
+ end
103
103
 
104
- {
105
- application_trace: application_trace,
106
- framework_trace: framework_trace,
107
- full_trace: application_trace + framework_trace
108
- }
109
- end
104
+ {
105
+ application_trace: application_trace,
106
+ framework_trace: framework_trace,
107
+ full_trace: application_trace + framework_trace
108
+ }
109
+ end
110
110
 
111
- def binding_from_exception(exception)
112
- exception.__web_console_bindings_stack[0]
113
- end
111
+ def binding_from_exception(exception)
112
+ exception.__web_console_bindings_stack[0]
113
+ end
114
114
  end
115
115
  end
@@ -2,8 +2,9 @@ module ActionDispatch
2
2
  class ExceptionWrapper
3
3
  def extract_sources
4
4
  exception.backtrace.map do |trace|
5
- file, line = trace.split(":")
5
+ file, line = trace.split(":")
6
6
  line_number = line.to_i
7
+
7
8
  {
8
9
  code: source_fragment(file, line_number) || {},
9
10
  file: file,
@@ -0,0 +1 @@
1
+ //= require ./web_console
@@ -0,0 +1,41 @@
1
+ //= require term
2
+
3
+ ;(function(BaseTerminal) {
4
+
5
+ // Expose the main WebConsole namespace.
6
+ var WebConsole = this.WebConsole = {};
7
+
8
+ // Follow term.js example and expose inherits and EventEmitter.
9
+ var inherits = WebConsole.inherits = BaseTerminal.inherits;
10
+ var EventEmitter = WebConsole.EventEmitter = BaseTerminal.EventEmitter;
11
+
12
+ var Terminal = WebConsole.Terminal = function(options) {
13
+ if (typeof options === 'number') {
14
+ return BaseTerminal.apply(this, arguments);
15
+ }
16
+
17
+ BaseTerminal.call(this, options || (options = {}));
18
+
19
+ this.open();
20
+
21
+ if (!(options.rows || options.cols) || !options.geometry) {
22
+ this.fitScreen();
23
+ }
24
+ };
25
+
26
+ // Make WebConsole.Terminal inherit from BaseTerminal (term.js).
27
+ inherits(Terminal, BaseTerminal);
28
+
29
+ Terminal.prototype.fitScreen = function() {
30
+ var width = Math.floor(this.element.clientWidth / this.cols);
31
+ var height = Math.floor(this.element.clientHeight / this.rows);
32
+
33
+ var rows = Math.floor(window.innerHeight / height);
34
+ var cols = Math.floor(this.parent.clientWidth / width);
35
+
36
+ this.resize(cols, rows);
37
+
38
+ return [cols, rows];
39
+ };
40
+
41
+ }).call(this, Terminal);