web-console 2.0.0 → 2.1.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +132 -85
  3. data/lib/web_console.rb +14 -13
  4. data/lib/web_console/errors.rb +7 -0
  5. data/lib/web_console/{repl.rb → evaluator.rb} +7 -10
  6. data/lib/web_console/helper.rb +22 -0
  7. data/lib/web_console/integration.rb +8 -0
  8. data/lib/web_console/{core_ext/exception → integration}/cruby.rb +0 -0
  9. data/lib/web_console/integration/jruby.rb +111 -0
  10. data/lib/web_console/integration/rubinius.rb +66 -0
  11. data/lib/web_console/middleware.rb +117 -0
  12. data/lib/web_console/railtie.rb +61 -0
  13. data/lib/web_console/request.rb +30 -0
  14. data/lib/web_console/session.rb +65 -0
  15. data/lib/web_console/template.rb +49 -0
  16. data/lib/web_console/templates/_inner_console_markup.html +3 -0
  17. data/lib/web_console/templates/_markup.html +4 -0
  18. data/lib/web_console/templates/_prompt_box_markup.html +2 -0
  19. data/lib/web_console/templates/console.js +373 -0
  20. data/lib/web_console/templates/error_page.js +83 -0
  21. data/lib/web_console/templates/index.html +8 -0
  22. data/lib/web_console/templates/layouts/inlined_string.erb +1 -0
  23. data/lib/web_console/templates/layouts/javascript.erb +5 -0
  24. data/lib/web_console/templates/main.js +24 -0
  25. data/lib/web_console/templates/style.css +9 -0
  26. data/lib/web_console/version.rb +1 -1
  27. data/lib/web_console/whiny_request.rb +38 -0
  28. data/lib/web_console/whitelist.rb +42 -0
  29. data/test/dummy/config/environments/test.rb +0 -4
  30. data/test/dummy/log/development.log +7075 -0
  31. data/test/dummy/log/test.log +66006 -0
  32. data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  33. data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  34. data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  35. data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  36. data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  37. data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  38. data/test/support/scenarios/bad_custom_error_scenario.rb +17 -0
  39. data/test/support/scenarios/basic_nested_scenario.rb +15 -0
  40. data/test/support/scenarios/custom_error_scenario.rb +11 -0
  41. data/test/support/scenarios/eval_nested_scenario.rb +15 -0
  42. data/test/support/scenarios/flat_scenario.rb +9 -0
  43. data/test/support/scenarios/reraised_scenario.rb +21 -0
  44. data/test/test_helper.rb +50 -3
  45. data/test/web_console/evaluator_test.rb +73 -0
  46. data/test/web_console/helper_test.rb +76 -0
  47. data/test/web_console/integration_test.rb +47 -0
  48. data/test/web_console/middleware_test.rb +116 -0
  49. data/test/web_console/railtie_test.rb +99 -0
  50. data/test/web_console/request_test.rb +52 -0
  51. data/test/web_console/session_test.rb +59 -0
  52. data/test/web_console/whiny_request_test.rb +33 -0
  53. data/test/web_console/whitelist_test.rb +43 -0
  54. metadata +66 -56
  55. data/lib/action_dispatch/debug_exceptions.rb +0 -105
  56. data/lib/action_dispatch/exception_wrapper.rb +0 -38
  57. data/lib/action_dispatch/templates/rescues/_request_and_response.html.erb +0 -34
  58. data/lib/action_dispatch/templates/rescues/_request_and_response.text.erb +0 -23
  59. data/lib/action_dispatch/templates/rescues/_source.erb +0 -29
  60. data/lib/action_dispatch/templates/rescues/_trace.html.erb +0 -72
  61. data/lib/action_dispatch/templates/rescues/_trace.text.erb +0 -9
  62. data/lib/action_dispatch/templates/rescues/_web_console.html.erb +0 -420
  63. data/lib/action_dispatch/templates/rescues/diagnostics.html.erb +0 -18
  64. data/lib/action_dispatch/templates/rescues/diagnostics.text.erb +0 -9
  65. data/lib/action_dispatch/templates/rescues/layout.erb +0 -160
  66. data/lib/action_dispatch/templates/rescues/missing_template.html.erb +0 -13
  67. data/lib/action_dispatch/templates/rescues/missing_template.text.erb +0 -3
  68. data/lib/action_dispatch/templates/rescues/routing_error.html.erb +0 -34
  69. data/lib/action_dispatch/templates/rescues/routing_error.text.erb +0 -11
  70. data/lib/action_dispatch/templates/rescues/template_error.html.erb +0 -22
  71. data/lib/action_dispatch/templates/rescues/template_error.text.erb +0 -7
  72. data/lib/action_dispatch/templates/rescues/unknown_action.html.erb +0 -6
  73. data/lib/action_dispatch/templates/rescues/unknown_action.text.erb +0 -3
  74. data/lib/action_dispatch/templates/routes/_route.html.erb +0 -16
  75. data/lib/action_dispatch/templates/routes/_table.html.erb +0 -200
  76. data/lib/assets/javascripts/web-console.js +0 -1
  77. data/lib/assets/javascripts/web_console.js +0 -41
  78. data/lib/web_console/controller_helpers.rb +0 -46
  79. data/lib/web_console/core_ext/exception.rb +0 -7
  80. data/lib/web_console/core_ext/exception/jruby.rb +0 -25
  81. data/lib/web_console/core_ext/exception/rubinius.rb +0 -32
  82. data/lib/web_console/engine.rb +0 -47
  83. data/lib/web_console/repl_session.rb +0 -89
  84. data/lib/web_console/unsupported_platforms.rb +0 -28
  85. data/lib/web_console/view_helpers.rb +0 -16
  86. data/test/action_pack/exception_wrapper_test.rb +0 -26
  87. data/test/controllers/tests_controller_test.rb +0 -41
  88. data/test/web_console/core_ext/exception_test.rb +0 -46
  89. data/test/web_console/engine_test.rb +0 -108
  90. data/test/web_console/repl_session_test.rb +0 -32
  91. data/test/web_console/repl_test.rb +0 -75
@@ -0,0 +1,17 @@
1
+ module WebConsole
2
+ class BadCustomErrorScenario
3
+ class Error < StandardError
4
+ def initialize(*)
5
+ # Bad exceptions are exceptions that don't call super in there
6
+ # #initialize method.
7
+ end
8
+ end
9
+
10
+ def call
11
+ raise Error
12
+ rescue => exc
13
+ exc
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,15 @@
1
+ module WebConsole
2
+ class BasicNestedScenario
3
+ def call
4
+ raise_an_error
5
+ rescue => exc
6
+ exc
7
+ end
8
+
9
+ private
10
+
11
+ def raise_an_error
12
+ raise
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module WebConsole
2
+ class CustomErrorScenario
3
+ Error = Class.new(StandardError)
4
+
5
+ def call
6
+ raise Error
7
+ rescue => exc
8
+ exc
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module WebConsole
2
+ class EvalNestedScenario
3
+ def call
4
+ tap { raise_an_error_in_eval }
5
+ rescue => exc
6
+ exc
7
+ end
8
+
9
+ private
10
+
11
+ def raise_an_error_in_eval
12
+ eval 'raise', binding, __FILE__, __LINE__
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module WebConsole
2
+ class FlatScenario
3
+ def call
4
+ raise
5
+ rescue => exc
6
+ exc
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module WebConsole
2
+ class ReraisedScenario
3
+ def call
4
+ reraise_an_error
5
+ rescue => exc
6
+ exc
7
+ end
8
+
9
+ private
10
+
11
+ def raise_an_error_in_eval
12
+ method_that_raises
13
+ rescue => exc
14
+ raise exc
15
+ end
16
+
17
+ def method_that_raises
18
+ raise
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,8 @@
1
- require 'simplecov'
2
- SimpleCov.start 'rails'
1
+ case RUBY_ENGINE
2
+ when 'ruby', 'rbx'
3
+ require 'simplecov'
4
+ SimpleCov.start 'rails'
5
+ end
3
6
 
4
7
  # Configure Rails Environment
5
8
  ENV["RAILS_ENV"] = "test"
@@ -19,10 +22,54 @@ module SilenceRailsDomTesting
19
22
  end
20
23
  end
21
24
 
22
- ActionController::TestCase.class_eval do
25
+ # Allows you to specify test to run only on specific Ruby platforms.
26
+ #
27
+ # Example:
28
+ #
29
+ # test 'CRuby specific feature', only: :ruby
30
+ # test 'CRuby and JRuby specific feature', only: %w(ruby jruby)
31
+ #
32
+ # If the :only option isn't present, the test is defined for all the platforms.
33
+ module PlatformSpecificTestMacro
34
+ def test(name, options = {})
35
+ platforms = Array(options[:only]).map(&:to_s)
36
+
37
+ if platforms.blank? || RUBY_ENGINE.in?(platforms)
38
+ super(name)
39
+ end
40
+ end
41
+ end
42
+
43
+ ActiveSupport::TestCase.class_eval do
44
+ extend PlatformSpecificTestMacro
45
+ end
46
+
47
+ ActionDispatch::IntegrationTest.class_eval do
23
48
  include SilenceRailsDomTesting
24
49
  end
25
50
 
51
+ # A copy of Kernel#capture in active_support/core_ext/kernel/reporting.rb as
52
+ # its getting deprecated past 4.2. Its not thread safe, but I don't need it to
53
+ # be in the tests
54
+ def capture(stream)
55
+ stream = stream.to_s
56
+ captured_stream = Tempfile.new(stream)
57
+ stream_io = eval("$#{stream}")
58
+ origin_stream = stream_io.dup
59
+ stream_io.reopen(captured_stream)
60
+
61
+ yield
62
+
63
+ stream_io.rewind
64
+ return captured_stream.read
65
+ ensure
66
+ captured_stream.close
67
+ captured_stream.unlink
68
+ stream_io.reopen(origin_stream)
69
+ end
70
+
71
+ alias silence capture
72
+
26
73
  # Load fixtures from the engine
27
74
  if ActiveSupport::TestCase.method_defined?(:fixture_path=)
28
75
  ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+
3
+ module WebConsole
4
+ class EvaluatorTest < ActiveSupport::TestCase
5
+ class TestError < StandardError
6
+ def backtrace
7
+ [
8
+ "/web-console/lib/web_console/repl.rb:16:in `eval'",
9
+ "/web-console/lib/web_console/repl.rb:16:in `eval'"
10
+ ]
11
+ end
12
+ end
13
+
14
+ class BadlyDefinedError < StandardError
15
+ def backtrace
16
+ nil
17
+ end
18
+ end
19
+
20
+ setup do
21
+ @repl1 = @repl = Evaluator.new
22
+ @repl2 = Evaluator.new
23
+ end
24
+
25
+ test 'sending input returns the result as output' do
26
+ assert_equal "=> 42\n", @repl.eval('foo = 42')
27
+ end
28
+
29
+ test 'preserves the session in the binding' do
30
+ assert_equal "=> 42\n", @repl.eval('foo = 42')
31
+ assert_equal "=> 50\n", @repl.eval('foo + 8')
32
+ end
33
+
34
+ test 'session preservation requires same bindings' do
35
+ assert_equal "=> 42\n", @repl1.eval('foo = 42')
36
+ assert_equal "=> 42\n", @repl2.eval('foo')
37
+ end
38
+
39
+ test 'formats exceptions similarly to IRB' do
40
+ repl = Evaluator.new(binding)
41
+
42
+ assert_equal <<-END.strip_heredoc, repl.eval("raise TestError, 'panic'")
43
+ #{TestError.name}: panic
44
+ \tfrom /web-console/lib/web_console/repl.rb:16:in `eval'
45
+ \tfrom /web-console/lib/web_console/repl.rb:16:in `eval'
46
+ END
47
+ end
48
+
49
+ test 'no backtrace is shown if exception backtrace is blank' do
50
+ repl = Evaluator.new(binding)
51
+
52
+ assert_equal <<-END.strip_heredoc, repl.eval("raise BadlyDefinedError")
53
+ #{BadlyDefinedError.name}: #{BadlyDefinedError.name}
54
+ END
55
+ end
56
+
57
+ test 'Evaluator callers are cleaned up of unneeded backtraces', only: :ruby do
58
+ # Those have to be on the same line to get the same trace.
59
+ repl, trace = Evaluator.new(binding), current_trace
60
+
61
+ assert_equal <<-END.strip_heredoc, repl.eval("raise")
62
+ RuntimeError:
63
+ \tfrom #{trace}
64
+ END
65
+ end
66
+
67
+ private
68
+
69
+ def current_trace
70
+ caller.first
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+
3
+ module WebConsole
4
+ class HelperTest < ActionDispatch::IntegrationTest
5
+ class BaseApplication
6
+ include Helper
7
+
8
+ def call(env)
9
+ Rack::Response.new(<<-HTML.strip_heredoc).finish
10
+ <html>
11
+ <head>
12
+ <title>Hello world</title>
13
+ </head>
14
+ <body>
15
+ <p id="hello-world">Hello world</p>
16
+ </body>
17
+ </html>
18
+ HTML
19
+ end
20
+
21
+ private
22
+
23
+ def request
24
+ Request.new(@env)
25
+ end
26
+ end
27
+
28
+ class SingleConsoleApplication < BaseApplication
29
+ def call(env)
30
+ @env = env
31
+
32
+ console
33
+
34
+ super
35
+ end
36
+ end
37
+
38
+ class MultipleConsolesApplication < BaseApplication
39
+ def call(env)
40
+ @env = env
41
+
42
+ console
43
+ console
44
+
45
+ super
46
+ end
47
+ end
48
+
49
+ setup do
50
+ Request.stubs(:whitelisted_ips).returns(IPAddr.new('0.0.0.0/0'))
51
+
52
+ @app = Middleware.new(SingleConsoleApplication.new)
53
+ end
54
+
55
+ test 'renders a console into a view' do
56
+ get '/', nil, 'CONTENT_TYPE' => 'text/html'
57
+
58
+ assert_select '#console'
59
+ end
60
+
61
+ test 'raises an error when trying to spawn a console more than once' do
62
+ @app = Middleware.new(MultipleConsolesApplication.new)
63
+
64
+ assert_raises(DoubleRenderError) do
65
+ get '/', nil, 'CONTENT_TYPE' => 'text/html'
66
+ end
67
+ end
68
+
69
+ test "doesn't hijack current view" do
70
+ get '/', nil, 'CONTENT_TYPE' => 'text/html'
71
+
72
+ assert_select '#hello-world'
73
+ assert_select '#console'
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ module WebConsole
4
+ class IntegrationTest < ActiveSupport::TestCase
5
+ test 'Exception#bindings returns all the bindings of where the error originated' do
6
+ exc = FlatScenario.new.call
7
+
8
+ assert_equal 4, exc.bindings.first.eval('__LINE__')
9
+ end
10
+
11
+ test 'Exception#bindings returns all the bindings for a custom error' do
12
+ exc = CustomErrorScenario.new.call
13
+
14
+ assert_equal 6, exc.bindings.first.eval('__LINE__')
15
+ end
16
+
17
+ test 'Exception#bindings returns all the bindings for a bad custom error' do
18
+ exc = BadCustomErrorScenario.new.call
19
+
20
+ assert_equal 11, exc.bindings.first.eval('__LINE__')
21
+ end
22
+
23
+ test 'Exception#bindings goes down the stack' do
24
+ exc = BasicNestedScenario.new.call
25
+
26
+ assert_equal 12, exc.bindings.first.eval('__LINE__')
27
+ end
28
+
29
+ test 'Exception#bindings inside of an eval' do
30
+ exc = EvalNestedScenario.new.call
31
+
32
+ assert_equal 12, exc.bindings.first.eval('__LINE__')
33
+ end
34
+
35
+ test "re-raising doesn't lose Exception#bindings information" do
36
+ exc = ReraisedScenario.new.call
37
+
38
+ assert_equal 4, exc.bindings.first.eval('__LINE__')
39
+ end
40
+
41
+ test 'Exception#bindings is empty when exception is still not raised' do
42
+ exc = RuntimeError.new
43
+
44
+ assert_equal [], exc.bindings
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,116 @@
1
+ require 'test_helper'
2
+
3
+ module WebConsole
4
+ class MiddlewareTest < ActionDispatch::IntegrationTest
5
+ class Application
6
+ def call(env)
7
+ Rack::Response.new(<<-HTML.strip_heredoc).finish
8
+ <html>
9
+ <head>
10
+ <title>Hello world</title>
11
+ </head>
12
+ <body>
13
+ <p id="hello-world">Hello world</p>
14
+ </body>
15
+ </html>
16
+ HTML
17
+ end
18
+ end
19
+
20
+ setup do
21
+ Request.stubs(:whitelisted_ips).returns(IPAddr.new('0.0.0.0/0'))
22
+
23
+ @app = Middleware.new(Application.new)
24
+ end
25
+
26
+ test 'render console in an html application from web_console.binding' do
27
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'web_console.binding' => binding
28
+
29
+ assert_select '#console'
30
+ end
31
+
32
+ test 'render console in an html application from web_console.exception' do
33
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'web_console.exception' => raise_exception
34
+
35
+ assert_select '#console'
36
+ end
37
+
38
+ test 'prioritizes web_console.exception over web_console.binding' do
39
+ exception = raise_exception
40
+
41
+ Session.expects(:from_exception).with(exception)
42
+
43
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'web_console.binding' => binding, 'web_console.exception' => exception
44
+ end
45
+
46
+ test 'render console in an html application with non text/html' do
47
+ get '/', nil, 'CONTENT_TYPE' => 'application/xhtml+xml', 'web_console.binding' => binding
48
+
49
+ assert_select '#console'
50
+ end
51
+
52
+ test "doesn't render console in non html application" do
53
+ get '/', nil, 'CONTENT_TYPE' => 'application/json', 'web-console.binding' => binding
54
+
55
+ assert_select '#console', 0
56
+ end
57
+
58
+ test "doesn't render console from non whitelisted IP" do
59
+ Request.stubs(:whitelisted_ips).returns(IPAddr.new('127.0.0.1'))
60
+
61
+ silence(:stderr) do
62
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'REMOTE_ADDR' => '1.1.1.1', 'web-console.binding' => binding
63
+ end
64
+
65
+ assert_select '#console', 0
66
+ end
67
+
68
+ test "doesn't render console without a web_console.binding or web_console.exception" do
69
+ get '/', nil, 'CONTENT_TYPE' => 'text/html'
70
+
71
+ assert_select '#console', 0
72
+ end
73
+
74
+ test 'can evaluate code and return it as a JSON' do
75
+ session, line = Session.new(binding), __LINE__
76
+
77
+ Session.stubs(:from_binding).returns(session)
78
+
79
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'web-console.binding' => binding
80
+ xhr :put, "/repl_sessions/#{session.id}", { input: '__LINE__' }
81
+
82
+ assert_equal({ output: "=> #{line}\n" }.to_json, response.body)
83
+ end
84
+
85
+ test 'can switch bindings on error pages' do
86
+ session = Session.new(exception = raise_exception)
87
+
88
+ Session.stubs(:from_exception).returns(session)
89
+
90
+ get '/', nil, 'CONTENT_TYPE' => 'text/html', 'web-console.exception' => exception
91
+ xhr :post, "/repl_sessions/#{session.id}/trace", { frame_id: 1 }
92
+
93
+ assert_equal({ ok: true }.to_json, response.body)
94
+ end
95
+
96
+ test 'unavailable sessions respond to the user with a message' do
97
+ xhr :put, '/repl_sessions/no_such_session', { input: '__LINE__' }
98
+
99
+ assert_equal(404, response.status)
100
+ end
101
+
102
+ test 'unavailable sessions can occur on binding switch' do
103
+ xhr :post, "/repl_sessions/no_such_session/trace", { frame_id: 1 }
104
+
105
+ assert_equal(404, response.status)
106
+ end
107
+
108
+ private
109
+
110
+ def raise_exception
111
+ raise
112
+ rescue => exc
113
+ exc
114
+ end
115
+ end
116
+ end