Skip to content

Instantly share code, notes, and snippets.

@alazycoder101
Last active July 21, 2024 15:48
Show Gist options
  • Save alazycoder101/31ad1f478b78ec6336c7950badae8236 to your computer and use it in GitHub Desktop.
Save alazycoder101/31ad1f478b78ec6336c7950badae8236 to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment