DEV Community

Lazy coder
Lazy coder

Posted on

irbrc to help with your efficiency


IRB.conf[:PROMPT][:DEV] = { # name of prompt mode
  :AUTO_INDENT => false,          # disables auto-indent mode
  :PROMPT_I =>  ">> ",            # simple prompt
  :PROMPT_S => nil,               # prompt for continuated strings
  :PROMPT_C => nil,               # prompt for continuated statement
  :RETURN => "    ==>%s\n"        # format to return value
}

#IRB.conf[:PROMPT_MODE] = :MY_PROMPT

# Tracking and Debugging Helpers

# Log method calls with their arguments
# Usage: track_method_calls(User, :save)
def track_method_calls(klass, method_name)
  klass.class_eval do
    old_method = instance_method(method_name)
    define_method(method_name) do |*args, &block|
      puts "Calling #{klass}##{method_name} with args: #{args.inspect}"
      old_method.bind(self).call(*args, &block)
    end
  end
end

# Track SQL queries
# Usage: track_sql_queries
def track_sql_queries
  ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
    event = ActiveSupport::Notifications::Event.new(*args)
    puts "SQL Query: #{event.payload[:sql]}"
    puts "Duration: #{event.duration.round(2)} ms"
    puts "---"
  end
end

# Count method calls
# Usage: count_method_calls(User, :update)
def count_method_calls(klass, method_name)
  count = 0
  klass.class_eval do
    old_method = instance_method(method_name)
    define_method(method_name) do |*args, &block|
      count += 1
      puts "#{klass}##{method_name} called #{count} times"
      old_method.bind(self).call(*args, &block)
    end
  end
end

# Track object allocations
# Usage: track_allocations { your_code_here }
def track_allocations
  require 'objspace'
  GC.disable
  before = ObjectSpace.count_objects
  yield
  after = ObjectSpace.count_objects
  puts "Object allocations:"
  after.each do |key, value|
    diff = value - before[key]
    puts "  #{key}: #{diff}" if diff != 0
  end
ensure
  GC.enable
end

# Profile code execution
# Usage: profile_code { your_code_here }
def profile_code
  require 'ruby-prof'
  RubyProf.start
  yield
  result = RubyProf.stop
  printer = RubyProf::FlatPrinter.new(result)
  printer.print(STDOUT)
end

# Track method execution time
# Usage: track_time(User, :expensive_method)
def track_time(klass, method_name)
  klass.class_eval do
    old_method = instance_method(method_name)
    define_method(method_name) do |*args, &block|
      start_time = Time.now
      result = old_method.bind(self).call(*args, &block)
      end_time = Time.now
      puts "#{klass}##{method_name} took #{(end_time - start_time) * 1000.0} ms"
      result
    end
  end
end

# Log instance variable changes
# Usage: track_ivar_changes(user, :name)
def track_ivar_changes(object, ivar_name)
  object.define_singleton_method("#{ivar_name}=") do |value|
    old_value = instance_variable_get("@#{ivar_name}")
    instance_variable_set("@#{ivar_name}", value)
    puts "#{object.class}##{ivar_name} changed from #{old_value.inspect} to #{value.inspect}"
  end
end


# Memory usage tracker
# Usage: track_memory { your_code_here }
def track_memory
  memory_before = `ps -o rss= -p #{Process.pid}`.to_i
  yield
  memory_after = `ps -o rss= -p #{Process.pid}`.to_i
  puts "Memory usage increased by #{memory_after - memory_before} KB"
end


def compare_methods(count = 1, *methods)
  require 'benchmark'
  Benchmark.bmbm do |b|
    methods.each do |method|
      b.report(method) { count.times { send(method) } }
    end
  end
  nil
end

def pp_hash(hash, indent=1)
  hash.each do |k, v|
    print "  " * indent
    if v.is_a?(Hash)
      puts "#{k}:"
      pp_hash(v, indent+1)
    else
      puts "#{k}: #{v}"
    end
  end
end

def measure_allocation
  before = GC.stat(:total_allocated_objects)
  yield
  after = GC.stat(:total_allocated_objects)
  puts "Allocated objects: #{after - before}"
end

def http_get(url)
  require 'httparty'
  response = HTTParty.get(url)
  puts "Status: #{response.code}"
  puts "Body: #{response.body}"
end

def explore_relation(relation)
  puts "SQL: #{relation.to_sql}"
  puts "Explained:"
  puts relation.explain
end

def parse_json(json_string)
  require 'json'
  JSON.pretty_generate(JSON.parse(json_string))
end

def list_constants(mod)
  mod.constants.sort.each do |const|
    puts "#{const} = #{mod.const_get(const)}"
  end
end

# Usage: class_hierarchy(Array)
def class_hierarchy(klass)
  hierarchy = [klass]
  while (klass = klass.superclass)
    hierarchy << klass
  end
  hierarchy.each_with_index do |k, i|
    puts "#{' ' * i}#{k}"
  end
end

# Usage: method_info("hello", :upcase)
def method_info(obj, method_name)
  method = obj.method(method_name)
  puts "Name: #{method.name}"
  puts "Owner: #{method.owner}"
  puts "Parameters: #{method.parameters}"
  puts "Arity: #{method.arity}"
  puts "Source Location: #{method.source_location&.join(':')}"
end

# Usage: set_breakpoint(User, :save)
def set_breakpoint(klass, method_name)
  require 'pry'
  klass.send(:define_method, method_name) do |*args, &block|
    binding.pry
    super(*args, &block)
  end
end

# Usage: list_instance_variables(some_object)
def list_instance_variables(obj)
  obj.instance_variables.each do |var|
    puts "#{var}: #{obj.instance_variable_get(var).inspect}"
  end
end

# Usage: show_ancestors(Array)
def show_ancestors(klass)
  puts "Ancestors:"
  klass.ancestors.each { |ancestor| puts "  #{ancestor}" }
  puts "\nIncluded Modules:"
  (klass.ancestors - klass.superclass.ancestors - [klass]).each { |mod| puts "  #{mod}" }
end

# Usage: list_constants
def list_constants
  Module.constants.sort.each do |constant|
    puts constant
  end
end

# Usage: explore_methods("hello")
def explore_methods(obj)
  methods = {
    instance: obj.methods - Object.methods,
    inherited: obj.methods & Object.methods,
    singleton: obj.singleton_methods
  }

  methods.each do |category, method_list|
    puts "#{category.to_s.capitalize} methods:"
    method_list.sort.each { |method| puts "  #{method}" }
    puts
  end
end

# Usage: show_method_source(Array, :map)
def show_method_source(obj, method_name)
  require 'pry'
  obj.method(method_name).source.display
end

# Usage: list_classes
def list_classes
  Object.constants
    .select { |c| Object.const_get(c).is_a? Class }
    .sort
    .each { |klass| puts klass }
end

# Usage: method_location(Array, :map)
def method_location(obj, method_name)
  file, line = obj.method(method_name).source_location
  puts "Defined in #{file}:#{line}"
end

# Usage: subclasses_of(ActiveRecord::Base)
def subclasses_of(klass)
  ObjectSpace.each_object(Class).select { |k| k < klass }
end

def track_changes(target, method_name)
  original_value = target.send(method_name.to_s.sub('=', ''))
  puts "Starting to track changes to #{target}.#{method_name}"
  puts "Initial value: #{original_value.class}"

  trace = TracePoint.new(:line) do |tp|
    #next unless tp.method_id.to_s == method_name.to_s && tp.self.instance_of?(target.class) && tp.self == target
    next unless tp.self.instance_of?(target.class) && tp.self == target && tp.method_id.to_s.include?(method_name.to_s.sub('=', ''))

    current_value = target.send(method_name.to_s.sub('=', ''))
    if current_value != original_value
      puts "\nChange detected in #{target}.#{method_name}:"
      puts "  From: #{original_value.class}"
      puts "  To:   #{current_value.class}"
      puts "  At:   #{tp.path}:#{tp.lineno}"
      puts "  Backtrace:"
      puts caller[0..5].map { |line| "    #{line}" }
      puts '-'*60
      original_value = current_value
    end
  end

  trace.enable
  puts "Tracking enabled. Run 'trace.disable' to stop tracking."

  trace  # Return the trace object so it can be disabled later
end

def track_method(klass, method_name, process=nil)
  trace = TracePoint.new(:call) do |tp|
    next unless tp.method_id.to_s == method_name.to_s

    next unless (klass.is_a?(Class) ? tp.self.is_a?(klass) : tp.self == klass)

    puts '-'*20
    puts "#{tp.path}:#{tp.lineno}"
    puts "#{tp.defined_class}##{tp.method_id}" if tp.defined_class
    process.call if process
  end

  trace.enable
  if block_given?
    yield
    trace.disable
  else
    puts "Tracking enabled. Run 'trace.disable' to stop tracking."
  end

  trace  # Return the trace object so it can be disabled later
end

Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay