tiny-pro-sys 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/tiny-pro-sys.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 +151 -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,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # A context lets you get object names related to the current session binding.
5
+ class Context
6
+ def initialize(binding)
7
+ @binding = binding
8
+ end
9
+
10
+ # Extracts entire objects which can be called by the current session unless
11
+ # the inputs is present.
12
+ #
13
+ # Otherwise, it extracts methods and constants of the object specified by
14
+ # the input.
15
+ def extract(input = nil)
16
+ input.present? ? local(input) : global
17
+ end
18
+
19
+ private
20
+
21
+ GLOBAL_OBJECTS = [
22
+ "instance_variables",
23
+ "local_variables",
24
+ "methods",
25
+ "class_variables",
26
+ "Object.constants",
27
+ "global_variables"
28
+ ]
29
+
30
+ def global
31
+ GLOBAL_OBJECTS.map { |cmd| eval(cmd) }
32
+ end
33
+
34
+ def local(input)
35
+ [
36
+ eval("#{input}.methods").map { |m| "#{input}.#{m}" },
37
+ eval("#{input}.constants").map { |c| "#{input}::#{c}" },
38
+ ]
39
+ end
40
+
41
+ def eval(cmd)
42
+ @binding.eval(cmd) rescue []
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # The base class for every Web Console related error.
5
+ Error = Class.new(StandardError)
6
+
7
+ # Raised when there is an attempt to render a console more than once.
8
+ DoubleRenderError = Class.new(Error)
9
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ # Simple Ruby code evaluator.
5
+ #
6
+ # This class wraps a +Binding+ object and evaluates code inside of it. The
7
+ # difference of a regular +Binding+ eval is that +Evaluator+ will always
8
+ # return a string and will format exception output.
9
+ class Evaluator
10
+ # Cleanses exceptions raised inside #eval.
11
+ cattr_reader :cleaner, default: begin
12
+ cleaner = ActiveSupport::BacktraceCleaner.new
13
+ cleaner.add_silencer { |line| line.start_with?(File.expand_path("..", __FILE__)) }
14
+ cleaner
15
+ end
16
+
17
+ def initialize(binding = TOPLEVEL_BINDING)
18
+ @binding = binding
19
+ end
20
+
21
+ def eval(input)
22
+ # Binding#source_location is available since Ruby 2.6.
23
+ if @binding.respond_to? :source_location
24
+ "=> #{@binding.eval(input, *@binding.source_location).inspect}\n"
25
+ else
26
+ "=> #{@binding.eval(input).inspect}\n"
27
+ end
28
+ rescue Exception => exc
29
+ format_exception(exc)
30
+ end
31
+
32
+ private
33
+
34
+ def format_exception(exc)
35
+ backtrace = cleaner.clean(Array(exc.backtrace) - caller)
36
+
37
+ format = "#{exc.class.name}: #{exc}\n".dup
38
+ format << backtrace.map { |trace| "\tfrom #{trace}\n" }.join
39
+ format
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebConsole
4
+ class ExceptionMapper
5
+ attr_reader :exc
6
+
7
+ def self.follow(exc)
8
+ mappers = [new(exc)]
9
+
10
+ while cause = (cause || exc).cause
11
+ mappers << new(cause)
12
+ end
13
+
14
+ mappers
15
+ end
16
+
17
+ def self.find_binding(mappers, exception_object_id)
18
+ mappers.detect do |exception_mapper|
19
+ exception_mapper.exc.object_id == exception_object_id.to_i
20
+ end || mappers.first
21
+ end
22
+
23
+ def initialize(exception)
24
+ @backtrace = exception.backtrace
25
+ @bindings = exception.bindings
26
+ @exc = exception
27
+ end
28
+
29
+ def first
30
+ guess_the_first_application_binding || @bindings.first
31
+ end
32
+
33
+ def [](index)
34
+ guess_binding_for_index(index) || @bindings[index]
35
+ end
36
+
37
+ private
38
+
39
+ def guess_binding_for_index(index)
40
+ file, line = @backtrace[index].to_s.split(":")
41
+ line = line.to_i
42
+
43
+ @bindings.find do |binding|
44
+ source_location = SourceLocation.new(binding)
45
+ source_location.path == file && source_location.lineno == line
46
+ end
47
+ end
48
+
49
+ def guess_the_first_application_binding
50
+ @bindings.find do |binding|
51
+ source_location = SourceLocation.new(binding)
52
+ source_location.path.to_s.start_with?(Rails.root.to_s)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ module_function
5
+
6
+ # Instructs Web Console to render a console in the specified binding.
7
+ #
8
+ # If +binding+ isn't explicitly given it will default to the binding of the
9
+ # previous frame. E.g. the one that invoked +console+.
10
+ #
11
+ # Raises +DoubleRenderError+ if a more than one +console+ invocation per
12
+ # request is detected.
13
+ def console(binding = Bindex.current_bindings.second)
14
+ raise WebConsole::DoubleRenderError if Thread.current[:__web_console_binding]
15
+
16
+ Thread.current[:__web_console_binding] = binding
17
+
18
+ # Make sure nothing is rendered from the view helper. Otherwise
19
+ # you're gonna see unexpected #<Binding:0x007fee4302b078> in the
20
+ # templates.
21
+ nil
22
+ end
23
+ end
24
+
25
+ class Binding
26
+ # Instructs Web Console to render a console in the current binding, without
27
+ # the need to unroll the stack.
28
+ #
29
+ # Raises +DoubleRenderError+ if a more than one +console+ invocation per
30
+ # request is detected.
31
+ def console
32
+ Kernel.console(self)
33
+ end
34
+ end
@@ -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