module Kernel

Public Instance Methods

__caller_file__(caller_depth=0) click to toggle source

Provides caller file starting 1 level above caller of this method.

Example:

# File Name: lib/example.rb
puts __caller_file__

prints out `lib/example.rb`

# File lib/puts_debuggerer/core_ext/kernel.rb, line 129
def __caller_file__(caller_depth=0)
  regex = RUBY_ENGINE == 'opal' ? PutsDebuggerer::STACK_TRACE_CALL_SOURCE_FILE_REGEX_OPAL : PutsDebuggerer::STACK_TRACE_CALL_SOURCE_FILE_REGEX
  caller[caller_depth] && caller[caller_depth][regex, 1]
end
__caller_line_number__(caller_depth=0) click to toggle source

Provides caller line number starting 1 level above caller of this method.

Example:

# lib/example.rb                        # line 1
puts "Print out __caller_line_number__" # line 2
puts __caller_line_number__             # line 3

prints out `3`

# File lib/puts_debuggerer/core_ext/kernel.rb, line 115
def __caller_line_number__(caller_depth=0)
  return if RUBY_ENGINE == 'opal'
  caller[caller_depth] && caller[caller_depth][PutsDebuggerer::STACK_TRACE_CALL_LINE_NUMBER_REGEX, 1].to_i
end
__caller_source_line__(caller_depth=0, source_line_count=nil, source_file=nil, source_line_number=nil) click to toggle source

Provides caller source line starting 1 level above caller of this method.

Example:

puts __caller_source_line__

prints out `puts caller_source_line`

# File lib/puts_debuggerer/core_ext/kernel.rb, line 143
def __caller_source_line__(caller_depth=0, source_line_count=nil, source_file=nil, source_line_number=nil)
  source_line_number ||= __caller_line_number__(caller_depth+1)
  source_file ||= __caller_file__(caller_depth+1)
  source_line = ''
  if defined?(Pry)
    @pry_instance ||= Pry.new
    source_line = Pry::Command::Hist.new(pry_instance: @pry_instance).call.instance_variable_get(:@buffer).split("\n")[source_line_number - 1] # TODO handle multi-lines in source_line_count
  elsif defined?(IRB)
    source_line = TOPLEVEL_BINDING.receiver.conf.io.line(source_line_number) # TODO handle multi-lines in source_line_count
  else
    source_line = PutsDebuggerer::SourceFile.new(source_file).source(source_line_count, source_line_number)
  end
  source_line
end
caller() click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 91
def caller
  begin
    raise 'error'
  rescue => e
    e.backtrace[2..-1]
  end
end
pd(*objects) click to toggle source

Prints object with bonus info such as file name, line number and source expression. Optionally prints out header and footer. Lookup PutsDebuggerer attributes for more details about configuration options.

Simply invoke global `pd` method anywhere you'd like to see line number and source code with output. If the argument is a pure string, the print out is simplified by not showing duplicate source.

Quickly locate printed lines using Find feature (e.g. CTRL+F) by looking for:

  • [PD]

  • file:line_number

  • ruby expression.

This gives you the added benefit of easily removing your pd statements later on from the code.

Happy puts_debuggerering!

Example Code:

# /Users/User/finance_calculator_app/pd_test.rb # line 1
bug = 'beattle'                                 # line 2
pd "Show me the source of the bug: #{bug}"      # line 3
pd 'What line number am I?'                     # line 4

Example Printout:

[PD] /Users/User/finance_calculator_app/pd_test.rb:3
   > pd "Show me the source of the bug: #{bug}"
  => "Show me the source of the bug: beattle"
[PD] /Users/User/finance_calculator_app/pd_test.rb:4 "What line number am I?"
# File lib/puts_debuggerer/core_ext/kernel.rb, line 33
def pd(*objects)
  options = PutsDebuggerer.determine_options(objects) || {}
  object = PutsDebuggerer.determine_object(objects)
  run_at = PutsDebuggerer.determine_run_at(options)
  printer = PutsDebuggerer.determine_printer(options)
  pd_inspect = options.delete(:pd_inspect)
  logger_formatter_decorated = PutsDebuggerer.printer.is_a?(Logger) && PutsDebuggerer.printer.formatter != PutsDebuggerer.logger_original_formatter
  logging_layouts_decorated = PutsDebuggerer.printer.is_a?(Logging::Logger) && PutsDebuggerer.printer.appenders.map(&:layout) != (PutsDebuggerer.logging_original_layouts.values)

  string = nil
  if PutsDebuggerer::RunDeterminer.run_pd?(object, run_at)
    __with_pd_options__(options) do |print_engine_options|
      run_number = PutsDebuggerer::RunDeterminer.run_number(object, run_at)
      formatter_pd_data = __build_pd_data__(object, print_engine_options: print_engine_options, source_line_count: PutsDebuggerer.source_line_count, run_number: run_number, pd_inspect: pd_inspect, logger_formatter_decorated: logger_formatter_decorated, logging_layouts_decorated: logging_layouts_decorated)
      stdout = $stdout
      $stdout = sio = StringIO.new
      PutsDebuggerer.formatter.call(formatter_pd_data)
      $stdout = stdout
      string = sio.string
      if RUBY_ENGINE == 'opal' && object.is_a?(Exception)
        $stderr.puts(string)
      else
        if PutsDebuggerer.printer.is_a?(Proc)
          PutsDebuggerer.printer.call(string)
        elsif PutsDebuggerer.printer.is_a?(Logger)
          logger_formatter = PutsDebuggerer.printer.formatter
          begin
            PutsDebuggerer.printer.formatter = PutsDebuggerer.logger_original_formatter
            PutsDebuggerer.printer.debug(string)
          ensure
            PutsDebuggerer.printer.formatter = logger_formatter
          end
        elsif PutsDebuggerer.printer.is_a?(Logging::Logger)
          logging_layouts = PutsDebuggerer.printer.appenders.reduce({}) do |hash, appender|
            hash.merge(appender => appender.layout)
          end
          begin
            PutsDebuggerer.logging_original_layouts.each do |appender, original_layout|
              appender.layout = original_layout
            end
            PutsDebuggerer.printer.debug(string)
          ensure
            PutsDebuggerer.logging_original_layouts.each do |appender, original_layout|
              appender.layout = logging_layouts[appender]
            end
          end
        elsif PutsDebuggerer.printer != false
          send(PutsDebuggerer.send(:printer), string)
        end
      end
    end
  end

  printer ? object : string
end
pd_inspect() click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 100
def pd_inspect
  pd self, printer: false, pd_inspect: true
end
Also aliased as: pdi
pdi()
Alias for: pd_inspect

Private Instance Methods

__build_pd_data__(object, print_engine_options:nil, source_line_count:nil, run_number:nil, pd_inspect:false, logger_formatter_decorated:false, logging_layouts_decorated:false) click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 169
def __build_pd_data__(object, print_engine_options:nil, source_line_count:nil, run_number:nil, pd_inspect:false, logger_formatter_decorated:false, logging_layouts_decorated:false)
  depth = RUBY_ENGINE == 'opal' ? PutsDebuggerer::CALLER_DEPTH_ZERO_OPAL : PutsDebuggerer::CALLER_DEPTH_ZERO
  if pd_inspect
    depth += 1
    depth += 4 if logger_formatter_decorated
    depth += 8 if logging_layouts_decorated
  end

  pd_data = {
    announcer: PutsDebuggerer.announcer,
    file: __caller_file__(depth)&.sub(PutsDebuggerer.app_path.to_s, ''),
    line_number: __caller_line_number__(depth),
    pd_expression: __caller_pd_expression__(depth, source_line_count),
    run_number: run_number,
    object: object,
    object_printer: PutsDebuggerer::OBJECT_PRINTER_DEFAULT.call(object, print_engine_options, source_line_count, run_number)
  }
  pd_data[:caller] = __caller_caller__(depth)
  ['header', 'wrapper', 'footer'].each do |boundary_option|
    pd_data[boundary_option.to_sym] = PutsDebuggerer.send(boundary_option) if PutsDebuggerer.send("#{boundary_option}?")
  end
  pd_data
end
__caller_caller__(depth) click to toggle source

Returns the caller stack trace of the caller of pd

# File lib/puts_debuggerer/core_ext/kernel.rb, line 194
def __caller_caller__(depth)
  return unless PutsDebuggerer.caller?
  start_depth = depth.to_i + 1
  caller_depth = PutsDebuggerer.caller == -1 ? -1 : (start_depth + PutsDebuggerer.caller)
  caller[start_depth..caller_depth].to_a
end
__caller_pd_expression__(depth=0, source_line_count=nil) click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 205
def __caller_pd_expression__(depth=0, source_line_count=nil)
  # Caller Source Line Depth 2 = 1 to pd method + 1 to caller
  source_line = __caller_source_line__(depth+1, source_line_count)
  source_line = __extract_pd_expression__(source_line)
  source_line = source_line.gsub(/(^'|'$)/, '"') if source_line.start_with?("'") && source_line.end_with?("'")
  source_line = source_line.gsub(/(^\(|\)$)/, '') if source_line.start_with?("(") && source_line.end_with?(")")
  source_line
end
__extract_pd_expression__(source_line) click to toggle source

Extracts pd source line expression.

Example:

extract_pd_expression(“pd (x=1)”)

outputs `(x=1)`

# File lib/puts_debuggerer/core_ext/kernel.rb, line 221
def __extract_pd_expression__(source_line)
  source_line.to_s.strip
end
__format_pd_expression__(expression, object) click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 201
def __format_pd_expression__(expression, object)
  "\n   > #{expression}\n  =>"
end
__with_pd_options__(options=nil) { |print_engine_options| ... } click to toggle source
# File lib/puts_debuggerer/core_ext/kernel.rb, line 160
def __with_pd_options__(options=nil)
  options ||= {}
  permanent_options = PutsDebuggerer.options
  PutsDebuggerer.options = options.select {|option, _| PutsDebuggerer.options.keys.include?(option)}
  print_engine_options = options.delete_if {|option, _| PutsDebuggerer.options.keys.include?(option)}
  yield print_engine_options
  PutsDebuggerer.options = permanent_options
end