mega-clean-box 0.0.1

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/mega-clean-box.gemspec +12 -0
  3. data/web-console-4.3.0/CHANGELOG.markdown +201 -0
  4. data/web-console-4.3.0/MIT-LICENSE +20 -0
  5. data/web-console-4.3.0/README.markdown +193 -0
  6. data/web-console-4.3.0/Rakefile +29 -0
  7. data/web-console-4.3.0/lib/web-console.rb +3 -0
  8. data/web-console-4.3.0/lib/web_console/context.rb +45 -0
  9. data/web-console-4.3.0/lib/web_console/errors.rb +9 -0
  10. data/web-console-4.3.0/lib/web_console/evaluator.rb +42 -0
  11. data/web-console-4.3.0/lib/web_console/exception_mapper.rb +56 -0
  12. data/web-console-4.3.0/lib/web_console/extensions.rb +34 -0
  13. data/web-console-4.3.0/lib/web_console/injector.rb +32 -0
  14. data/web-console-4.3.0/lib/web_console/interceptor.rb +17 -0
  15. data/web-console-4.3.0/lib/web_console/locales/en.yml +15 -0
  16. data/web-console-4.3.0/lib/web_console/middleware.rb +137 -0
  17. data/web-console-4.3.0/lib/web_console/permissions.rb +42 -0
  18. data/web-console-4.3.0/lib/web_console/railtie.rb +88 -0
  19. data/web-console-4.3.0/lib/web_console/request.rb +46 -0
  20. data/web-console-4.3.0/lib/web_console/session.rb +80 -0
  21. data/web-console-4.3.0/lib/web_console/source_location.rb +12 -0
  22. data/web-console-4.3.0/lib/web_console/tasks/extensions.rake +62 -0
  23. data/web-console-4.3.0/lib/web_console/tasks/templates.rake +50 -0
  24. data/web-console-4.3.0/lib/web_console/template.rb +24 -0
  25. data/web-console-4.3.0/lib/web_console/templates/_inner_console_markup.html.erb +8 -0
  26. data/web-console-4.3.0/lib/web_console/templates/_markup.html.erb +5 -0
  27. data/web-console-4.3.0/lib/web_console/templates/_prompt_box_markup.html.erb +2 -0
  28. data/web-console-4.3.0/lib/web_console/templates/console.js.erb +1024 -0
  29. data/web-console-4.3.0/lib/web_console/templates/error_page.js.erb +69 -0
  30. data/web-console-4.3.0/lib/web_console/templates/index.html.erb +12 -0
  31. data/web-console-4.3.0/lib/web_console/templates/layouts/inlined_string.erb +1 -0
  32. data/web-console-4.3.0/lib/web_console/templates/layouts/javascript.erb +5 -0
  33. data/web-console-4.3.0/lib/web_console/templates/main.js.erb +1 -0
  34. data/web-console-4.3.0/lib/web_console/templates/regular_page.js.erb +24 -0
  35. data/web-console-4.3.0/lib/web_console/templates/style.css.erb +182 -0
  36. data/web-console-4.3.0/lib/web_console/testing/erb_precompiler.rb +27 -0
  37. data/web-console-4.3.0/lib/web_console/testing/fake_middleware.rb +44 -0
  38. data/web-console-4.3.0/lib/web_console/testing/helper.rb +11 -0
  39. data/web-console-4.3.0/lib/web_console/version.rb +5 -0
  40. data/web-console-4.3.0/lib/web_console/view.rb +58 -0
  41. data/web-console-4.3.0/lib/web_console/whiny_request.rb +33 -0
  42. data/web-console-4.3.0/lib/web_console.rb +37 -0
  43. metadata +82 -0
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # Injects content into a Rack body.
5
+ class Injector
6
+ def initialize(body, headers)
7
+ @body = "".dup
8
+
9
+ body.each { |part| @body << part }
10
+ body.close if body.respond_to?(:close)
11
+
12
+ @headers = headers
13
+ end
14
+
15
+ def inject(content)
16
+ # Set content-length header to the size of the current body
17
+ # + the extra content. Otherwise the response will be truncated.
18
+ if @headers[Rack::CONTENT_LENGTH]
19
+ @headers[Rack::CONTENT_LENGTH] = (@body.bytesize + content.bytesize).to_s
20
+ end
21
+
22
+ [
23
+ if position = @body.rindex("</body>")
24
+ [ @body.insert(position, content) ]
25
+ else
26
+ [ @body << content ]
27
+ end,
28
+ @headers
29
+ ]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ module WebConsole
2
+ module Interceptor
3
+ def self.call(request, error)
4
+ backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
5
+
6
+ # Get the original exception if ExceptionWrapper decides to follow it.
7
+ Thread.current[:__web_console_exception] = error
8
+
9
+ # ActionView::Template::Error bypass ExceptionWrapper original
10
+ # exception following. The backtrace in the view is generated from
11
+ # reaching out to original_exception in the view.
12
+ if error.is_a?(ActionView::Template::Error)
13
+ Thread.current[:__web_console_exception] = error.cause
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ en:
2
+ errors:
3
+ unavailable_session: |
4
+ Session %{id} is no longer available in memory.
5
+
6
+ If you happen to run on a multi-process server (like Unicorn or Puma) the process
7
+ this request hit doesn't store %{id} in memory. Consider turning the number of
8
+ processes/workers to one (1) or using a different server in development.
9
+
10
+ unacceptable_request: |
11
+ A supported version is expected in the Accept header.
12
+
13
+ connection_refused: |
14
+ Oops! Failed to connect to the Web Console middleware.
15
+ Please make sure a rails development server is running.
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/strip"
4
+
5
+ module WebConsole
6
+ class Middleware
7
+ TEMPLATES_PATH = File.expand_path("../templates", __FILE__)
8
+
9
+ cattr_accessor :mount_point, default: "/__web_console"
10
+ cattr_accessor :whiny_requests, default: true
11
+
12
+ def initialize(app)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ app_exception = catch :app_exception do
18
+ request = create_regular_or_whiny_request(env)
19
+ return call_app(env) unless request.permitted?
20
+
21
+ if id = id_for_repl_session_update(request)
22
+ return update_repl_session(id, request)
23
+ elsif id = id_for_repl_session_stack_frame_change(request)
24
+ return change_stack_trace(id, request)
25
+ end
26
+
27
+
28
+ status, headers, body = call_app(env)
29
+
30
+ if (session = Session.from(Thread.current)) && acceptable_content_type?(headers)
31
+ headers["x-web-console-session-id"] = session.id
32
+ headers["x-web-console-mount-point"] = mount_point
33
+
34
+ template = Template.new(env, session)
35
+ body, headers = Injector.new(body, headers).inject(template.render("index"))
36
+ end
37
+
38
+ [ status, headers, body ]
39
+ end
40
+ rescue => e
41
+ WebConsole.logger.error("\n#{e.class}: #{e}\n\tfrom #{e.backtrace.join("\n\tfrom ")}")
42
+ raise e
43
+ ensure
44
+ # Clean up the fiber locals after the session creation. Object#console
45
+ # uses those to communicate the current binding or exception to the middleware.
46
+ Thread.current[:__web_console_exception] = nil
47
+ Thread.current[:__web_console_binding] = nil
48
+
49
+ raise app_exception if Exception === app_exception
50
+ end
51
+
52
+ private
53
+
54
+ def acceptable_content_type?(headers)
55
+ headers[Rack::CONTENT_TYPE].to_s.include?("html")
56
+ end
57
+
58
+ def json_response(opts = {})
59
+ status = opts.fetch(:status, 200)
60
+ headers = { Rack::CONTENT_TYPE => "application/json; charset = utf-8" }
61
+ body = yield.to_json
62
+
63
+ [ status, headers, [ body ] ]
64
+ end
65
+
66
+ def json_response_with_session(id, request, opts = {})
67
+ return respond_with_unavailable_session(id) unless session = Session.find(id)
68
+
69
+ json_response(opts) { yield session }
70
+ end
71
+
72
+ def create_regular_or_whiny_request(env)
73
+ request = Request.new(env)
74
+ whiny_requests ? WhinyRequest.new(request) : request
75
+ end
76
+
77
+ def repl_sessions_re
78
+ @_repl_sessions_re ||= %r{#{mount_point}/repl_sessions/(?<id>[^/]+)}
79
+ end
80
+
81
+ def update_re
82
+ @_update_re ||= %r{#{repl_sessions_re}\z}
83
+ end
84
+
85
+ def binding_change_re
86
+ @_binding_change_re ||= %r{#{repl_sessions_re}/trace\z}
87
+ end
88
+
89
+ def id_for_repl_session_update(request)
90
+ if request.xhr? && request.put?
91
+ update_re.match(request.path) { |m| m[:id] }
92
+ end
93
+ end
94
+
95
+ def id_for_repl_session_stack_frame_change(request)
96
+ if request.xhr? && request.post?
97
+ binding_change_re.match(request.path) { |m| m[:id] }
98
+ end
99
+ end
100
+
101
+ def update_repl_session(id, request)
102
+ json_response_with_session(id, request) do |session|
103
+ if input = request.params[:input]
104
+ { output: session.eval(input) }
105
+ elsif input = request.params[:context]
106
+ { context: session.context(input) }
107
+ end
108
+ end
109
+ end
110
+
111
+ def change_stack_trace(id, request)
112
+ json_response_with_session(id, request) do |session|
113
+ session.switch_binding_to(request.params[:frame_id], request.params[:exception_object_id])
114
+
115
+ { ok: true }
116
+ end
117
+ end
118
+
119
+ def respond_with_unavailable_session(id)
120
+ json_response(status: 404) do
121
+ { output: format(I18n.t("errors.unavailable_session"), id: id) }
122
+ end
123
+ end
124
+
125
+ def respond_with_unacceptable_request
126
+ json_response(status: 406) do
127
+ { output: I18n.t("errors.unacceptable_request") }
128
+ end
129
+ end
130
+
131
+ def call_app(env)
132
+ @app.call(env)
133
+ rescue => e
134
+ throw :app_exception, e
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+
5
+ module WebConsole
6
+ class Permissions
7
+ # IPv4 and IPv6 localhost should be always allowed.
8
+ ALWAYS_PERMITTED_NETWORKS = %w( 127.0.0.0/8 ::1 ::ffff:127.0.0.0/104 )
9
+
10
+ def initialize(networks = nil)
11
+ @networks = normalize_networks(networks).map(&method(:coerce_network_to_ipaddr)).uniq
12
+ end
13
+
14
+ def include?(network)
15
+ @networks.any? { |permission| permission.include?(network.to_s) }
16
+ rescue IPAddr::InvalidAddressError
17
+ false
18
+ end
19
+
20
+ def to_s
21
+ @networks.map(&method(:human_readable_ipaddr)).join(", ")
22
+ end
23
+
24
+ private
25
+
26
+ def normalize_networks(networks)
27
+ Array(networks).concat(ALWAYS_PERMITTED_NETWORKS)
28
+ end
29
+
30
+ def coerce_network_to_ipaddr(network)
31
+ if network.is_a?(IPAddr)
32
+ network
33
+ else
34
+ IPAddr.new(network)
35
+ end
36
+ end
37
+
38
+ def human_readable_ipaddr(ipaddr)
39
+ ipaddr.to_range.to_s.split("..").uniq.join("/")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module WebConsole
6
+ class Railtie < ::Rails::Railtie
7
+ config.web_console = ActiveSupport::OrderedOptions.new
8
+
9
+ initializer "web_console.initialize" do
10
+ require "bindex"
11
+ require "web_console/extensions"
12
+
13
+ ActionDispatch::DebugExceptions.register_interceptor(Interceptor)
14
+ end
15
+
16
+ initializer "web_console.development_only" do
17
+ unless (config.web_console.development_only == false) || Rails.env.development?
18
+ abort <<-END.strip_heredoc
19
+ Web Console is activated in the #{Rails.env} environment. This is
20
+ usually a mistake. To ensure it's only activated in development
21
+ mode, move it to the development group of your Gemfile:
22
+
23
+ gem 'web-console', group: :development
24
+
25
+ If you still want to run it in the #{Rails.env} environment (and know
26
+ what you are doing), put this in your Rails application
27
+ configuration:
28
+
29
+ config.web_console.development_only = false
30
+ END
31
+ end
32
+ end
33
+
34
+ initializer "web_console.insert_middleware" do |app|
35
+ app.middleware.insert_before ActionDispatch::DebugExceptions, Middleware
36
+ end
37
+
38
+ initializer "web_console.mount_point" do
39
+ if mount_point = config.web_console.mount_point
40
+ Middleware.mount_point = mount_point.chomp("/")
41
+ end
42
+
43
+ if root = Rails.application.config.relative_url_root
44
+ Middleware.mount_point = File.join(root, Middleware.mount_point)
45
+ end
46
+ end
47
+
48
+ initializer "web_console.template_paths" do
49
+ if template_paths = config.web_console.template_paths
50
+ Template.template_paths.unshift(*Array(template_paths))
51
+ end
52
+ end
53
+
54
+ initializer "web_console.deprecator" do |app|
55
+ app.deprecators[:web_console] = WebConsole.deprecator if app.respond_to?(:deprecators)
56
+ end
57
+
58
+ initializer "web_console.permissions" do
59
+ permissions = web_console_permissions
60
+ Request.permissions = Permissions.new(permissions)
61
+ end
62
+
63
+ def web_console_permissions
64
+ case
65
+ when config.web_console.permissions
66
+ config.web_console.permissions
67
+ when config.web_console.allowed_ips
68
+ config.web_console.allowed_ips
69
+ when config.web_console.whitelisted_ips
70
+ WebConsole.deprecator.warn(<<-MSG.squish)
71
+ The config.web_console.whitelisted_ips is deprecated and will be ignored in future release of web_console.
72
+ Please use config.web_console.allowed_ips instead.
73
+ MSG
74
+ config.web_console.whitelisted_ips
75
+ end
76
+ end
77
+
78
+ initializer "web_console.whiny_requests" do
79
+ if config.web_console.key?(:whiny_requests)
80
+ Middleware.whiny_requests = config.web_console.whiny_requests
81
+ end
82
+ end
83
+
84
+ initializer "i18n.load_path" do
85
+ config.i18n.load_path.concat(Dir[File.expand_path("../locales/*.yml", __FILE__)])
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ class Request < ActionDispatch::Request
5
+ cattr_accessor :permissions, default: Permissions.new
6
+
7
+ def permitted?
8
+ permissions.include?(strict_remote_ip)
9
+ end
10
+
11
+ def strict_remote_ip
12
+ GetSecureIp.new(self, permissions).to_s
13
+ rescue ActionDispatch::RemoteIp::IpSpoofAttackError
14
+ "[Spoofed]"
15
+ end
16
+
17
+ private
18
+
19
+ class GetSecureIp < ActionDispatch::RemoteIp::GetIp
20
+ def initialize(req, proxies)
21
+ # After rails/rails@07b2ff0 ActionDispatch::RemoteIp::GetIp initializes
22
+ # with a ActionDispatch::Request object instead of plain Rack
23
+ # environment hash. Keep both @req and @env here, so we don't if/else
24
+ # on Rails versions.
25
+ @req = req
26
+ @env = req.env
27
+ @check_ip = true
28
+ @proxies = proxies
29
+ end
30
+
31
+ # Used by rails <= 8.1
32
+ def filter_proxies(ips)
33
+ ips.reject do |ip|
34
+ @proxies.include?(ip)
35
+ end
36
+ end
37
+
38
+ # Used by rails > 8.1.
39
+ def first_non_proxy(ips)
40
+ ips.find do |ip|
41
+ !@proxies.include?(ip)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # A session lets you persist an +Evaluator+ instance in memory associated
5
+ # with multiple bindings.
6
+ #
7
+ # Each newly created session is persisted into memory and you can find it
8
+ # later by its +id+.
9
+ #
10
+ # A session may be associated with multiple bindings. This is used by the
11
+ # error pages only, as currently, this is the only client that needs to do
12
+ # that.
13
+ class Session
14
+ cattr_reader :inmemory_storage, default: {}
15
+
16
+ class << self
17
+ # Finds a persisted session in memory by its id.
18
+ #
19
+ # Returns a persisted session if found in memory.
20
+ # Raises NotFound error unless found in memory.
21
+ def find(id)
22
+ inmemory_storage[id]
23
+ end
24
+
25
+ # Create a Session from an binding or exception in a storage.
26
+ #
27
+ # The storage is expected to respond to #[]. The binding is expected in
28
+ # :__web_console_binding and the exception in :__web_console_exception.
29
+ #
30
+ # Can return nil, if no binding or exception have been preserved in the
31
+ # storage.
32
+ def from(storage)
33
+ if exc = storage[:__web_console_exception]
34
+ new(ExceptionMapper.follow(exc))
35
+ elsif binding = storage[:__web_console_binding]
36
+ new([[binding]])
37
+ end
38
+ end
39
+ end
40
+
41
+ # An unique identifier for every REPL.
42
+ attr_reader :id
43
+
44
+ def initialize(exception_mappers)
45
+ @id = SecureRandom.hex(16)
46
+
47
+ @exception_mappers = exception_mappers
48
+ @evaluator = Evaluator.new(@current_binding = exception_mappers.first.first)
49
+
50
+ store_into_memory
51
+ end
52
+
53
+ # Evaluate +input+ on the current Evaluator associated binding.
54
+ #
55
+ # Returns a string of the Evaluator output.
56
+ def eval(input)
57
+ @evaluator.eval(input)
58
+ end
59
+
60
+ # Switches the current binding to the one at specified +index+.
61
+ #
62
+ # Returns nothing.
63
+ def switch_binding_to(index, exception_object_id)
64
+ bindings = ExceptionMapper.find_binding(@exception_mappers, exception_object_id)
65
+
66
+ @evaluator = Evaluator.new(@current_binding = bindings[index.to_i])
67
+ end
68
+
69
+ # Returns context of the current binding
70
+ def context(objpath)
71
+ Context.new(@current_binding).extract(objpath)
72
+ end
73
+
74
+ private
75
+
76
+ def store_into_memory
77
+ inmemory_storage[id] = self
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ class SourceLocation
5
+ def initialize(binding)
6
+ @binding = binding
7
+ end
8
+
9
+ def path() @binding.source_location.first end
10
+ def lineno() @binding.source_location.last end
11
+ end
12
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :ext do
4
+ rootdir = Pathname("extensions")
5
+
6
+ desc "Build Chrome Extension"
7
+ task chrome: "chrome:build"
8
+
9
+ namespace :chrome do
10
+ dist = Pathname("dist/crx")
11
+ extdir = rootdir.join(dist)
12
+ manifest_json = rootdir.join("chrome/manifest.json")
13
+
14
+ directory extdir
15
+
16
+ task build: [ extdir, "lib:templates" ] do
17
+ cd rootdir do
18
+ cp_r [ "img/", "tmp/lib/" ], dist
19
+ `cd chrome && git ls-files`.split("\n").each do |src|
20
+ dest = dist.join(src)
21
+ mkdir_p dest.dirname
22
+ cp Pathname("chrome").join(src), dest
23
+ end
24
+ end
25
+ end
26
+
27
+ # Generate a .crx file.
28
+ task crx: [ :build, :npm ] do
29
+ out = "crx-web-console-#{JSON.parse(File.read(manifest_json))["version"]}.crx"
30
+ cd(extdir) { sh "node \"$(npm bin)/crx\" pack ./ -p ../crx-web-console.pem -o ../#{out}" }
31
+ end
32
+
33
+ # Generate a .zip file for Chrome Web Store.
34
+ task zip: [ :build ] do
35
+ version = JSON.parse(File.read(manifest_json))["version"]
36
+ cd(extdir) { sh "zip -r ../crx-web-console-#{version}.zip ./" }
37
+ end
38
+
39
+ desc "Launch a browser with the chrome extension."
40
+ task run: [ :build ] do
41
+ cd(rootdir) { sh "sh ./script/run_chrome.sh --load-extension=#{dist}" }
42
+ end
43
+ end
44
+
45
+ task :npm do
46
+ cd(rootdir) { sh "npm install --silent" }
47
+ end
48
+
49
+ namespace :lib do
50
+ templates = Pathname("lib/web_console/templates")
51
+ tmplib = rootdir.join("tmp/lib/")
52
+ js_erb = FileList.new(templates.join("**/*.js.erb"))
53
+ dirs = js_erb.pathmap("%{^#{templates},#{tmplib}}d")
54
+
55
+ task templates: dirs + js_erb.pathmap("%{^#{templates},#{tmplib}}X")
56
+
57
+ dirs.each { |d| directory d }
58
+ rule ".js" => [ "%{^#{tmplib},#{templates}}X.js.erb" ] do |t|
59
+ File.write(t.name, WebConsole::Testing::ERBPrecompiler.new(t.source).build)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+
5
+ namespace :templates do
6
+ desc "Run tests for templates"
7
+ task test: [ :daemonize, :npm, :rackup, :wait, :mocha, :kill, :exit ]
8
+ task serve: [ :npm, :rackup ]
9
+
10
+ workdir = Pathname(EXPANDED_CWD).join("test/templates")
11
+ pid = Pathname(Dir.tmpdir).join("web_console_test.pid")
12
+ runner = URI.parse("http://#{ENV['IP'] || '127.0.0.1'}:#{ENV['PORT'] || 29292}/html/test_runner.html")
13
+ rackup = "rackup --host #{runner.host} --port #{runner.port}"
14
+ result = nil
15
+
16
+ def need_to_wait?(uri)
17
+ Net::HTTP.start(uri.host, uri.port) { |http| http.get(uri.path) }
18
+ rescue Errno::ECONNREFUSED
19
+ retry if yield
20
+ end
21
+
22
+ task :daemonize do
23
+ rackup += " -D --pid #{pid}"
24
+ end
25
+
26
+ task :npm do
27
+ Dir.chdir(workdir) { system "npm install --silent" }
28
+ end
29
+
30
+ task :rackup do
31
+ Dir.chdir(workdir) { system rackup }
32
+ end
33
+
34
+ task :wait do
35
+ cnt = 0
36
+ need_to_wait?(runner) { sleep 1; cnt += 1; cnt < 5 }
37
+ end
38
+
39
+ task :mocha do
40
+ Dir.chdir(workdir) { result = system("npx mocha-headless-chrome -f #{runner} -r dot") }
41
+ end
42
+
43
+ task :kill do
44
+ system "kill #{File.read pid}"
45
+ end
46
+
47
+ task :exit do
48
+ exit result
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # A facade that handles template rendering and composition.
5
+ #
6
+ # It introduces template helpers to ease the inclusion of scripts only on
7
+ # Rails error pages.
8
+ class Template
9
+ # Lets you customize the default templates folder location.
10
+ cattr_accessor :template_paths, default: [ File.expand_path("../templates", __FILE__) ]
11
+
12
+ def initialize(env, session)
13
+ @env = env
14
+ @session = session
15
+ @mount_point = Middleware.mount_point
16
+ end
17
+
18
+ # Render a template (inferred from +template_paths+) as a plain string.
19
+ def render(template)
20
+ view = View.with_empty_template_cache.with_view_paths(template_paths, instance_values)
21
+ view.render(template: template, layout: false)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ <div class='resizer layer'></div>
2
+ <div class='console-outer layer'>
3
+ <div class='console-actions'>
4
+ <div class='close-button button' title='close'>&times;</div>
5
+ </div>
6
+ <div class='console-inner'></div>
7
+ </div>
8
+ <input class='clipboard' type='text'>
@@ -0,0 +1,5 @@
1
+ <div id="console"
2
+ data-mount-point='<%= @mount_point %>'
3
+ data-session-id='<%= @session.id %>'
4
+ data-prompt-label='>> '>
5
+ </div>
@@ -0,0 +1,2 @@
1
+ <span class='console-prompt-label'></span>
2
+ <pre class='console-prompt-display'></pre>