# frozen_string_literal: false # # irb/workspace-binding.rb - # by Keiju ISHITSUKA(keiju@ruby-lang.org) # require "delegate" IRB::TOPLEVEL_BINDING = binding module IRB # :nodoc: class WorkSpace # Creates a new workspace. # # set self to main if specified, otherwise # inherit main from TOPLEVEL_BINDING. def initialize(*main) if main[0].kind_of?(Binding) @binding = main.shift elsif IRB.conf[:SINGLE_IRB] @binding = TOPLEVEL_BINDING else case IRB.conf[:CONTEXT_MODE] when 0 # binding in proc on TOPLEVEL_BINDING @binding = eval("proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__) when 1 # binding in loaded file require "tempfile" f = Tempfile.open("irb-binding") f.print <IRB.conf[:__MAIN__] attr_reader :main # Evaluate the given +statements+ within the context of this workspace. def evaluate(statements, file = __FILE__, line = __LINE__) eval(statements, @binding, file, line) end def local_variable_set(name, value) @binding.local_variable_set(name, value) end def local_variable_get(name) @binding.local_variable_get(name) end # error message manipulator # WARN: Rails patches this method to filter its own backtrace. Be cautious when changing it. # See: https://github.com/rails/rails/blob/main/railties/lib/rails/commands/console/console_command.rb#L8:~:text=def,filter_backtrace def filter_backtrace(bt) return nil if bt =~ /\/irb\/.*\.rb/ return nil if bt =~ /\/irb\.rb/ return nil if bt =~ /tool\/lib\/.*\.rb|runner\.rb/ # for tests in Ruby repository case IRB.conf[:CONTEXT_MODE] when 1 return nil if bt =~ %r!/tmp/irb-binding! when 3 bt = bt.sub(/:\s*in `irb_binding'/, '') end bt end def code_around_binding file, pos = @binding.source_location if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file] code = ::SCRIPT_LINES__[file].join('') else begin code = File.read(file) rescue SystemCallError return end end lines = Color.colorize_code(code).lines pos -= 1 start_pos = [pos - 5, 0].max end_pos = [pos + 5, lines.size - 1].min line_number_fmt = Color.colorize("%#{end_pos.to_s.length}d", [:BLUE, :BOLD]) fmt = " %2s #{line_number_fmt}: %s" body = (start_pos..end_pos).map do |current_pos| sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos]) end.join("") "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n" end end end