module Utils::IRB::Shell

def ai(query, command: false, respond: false, parse: false, dir: ?.)

Returns:
  • (String, nil) - the response from the Ollama chat service if

Parameters:
  • dir (String) -- the directory to use for the operation
  • parse (TrueClass, FalseClass) -- whether to parse the response
  • respond (TrueClass, FalseClass) -- whether to capture and return
  • command (TrueClass, FalseClass) -- whether to treat the query as
  • query (String) -- the input query to send to the Ollama chat
def ai(query, command: false, respond: false, parse: false, dir: ?.)
  dir = File.expand_path(dir)
  args = {
    ?r => respond,
    ?t => command,
    ?p => parse,
    ?d => dir,
  }
  args = args.map { |k, v|
    v == false and next
    v == true ? "-#{k}" : [ "-#{k}", v.to_s ]
  }.flatten.compact
  args.unshift 'ollama_chat_send'
  response = nil
  IO.popen(Shellwords.join(args), 'r+') do |io|
    io.write query
    io.close_write
    if respond
      response = io.read
    end
  end
  response
end

def capture_output(with_stderr = false)

Returns:
  • (String) - the captured output as a string

Other tags:
    Yield: - the block of code to execute while capturing output

Parameters:
  • with_stderr (TrueClass, FalseClass) -- whether to also capture standard error output
def capture_output(with_stderr = false)
  require 'tempfile'
  begin
    old_stdout, $stdout = $stdout, Tempfile.new('irb')
    if with_stderr
      old_stderr, $stderr = $stderr, $stdout
    end
    yield
  ensure
    $stdout, temp = old_stdout, $stdout
    with_stderr and $stderr = old_stderr
  end
  temp.rewind
  temp.read
end

def ed(*files)

Parameters:
  • files (Array) -- an array of file paths to be edited
def ed(*files)
  if files.empty?
    $editor.full?(:edit, self)
  else
    $editor.full?(:edit, *files)
  end
end

def irb_all_class_instance_methods(obj = self)

Returns:
  • (Array) - an array of wrapped method objects suitable for IRB interaction

Parameters:
  • obj (Object) -- the object whose class instance methods are to be retrieved
def irb_all_class_instance_methods(obj = self)
  methods = obj.class.instance_methods
  irb_wrap_methods obj, methods
end

def irb_all_instance_methods(modul = self)

Returns:
  • (Array) - an array of wrapped method objects suitable for IRB interaction

Parameters:
  • modul (Object) -- the module from which to retrieve instance methods
def irb_all_instance_methods(modul = self)
  methods = modul.instance_methods
  irb_wrap_methods modul, methods, true
end

def irb_all_methods(obj = self)

Returns:
  • (Array) - an array of wrapped method objects for interactive use

Parameters:
  • obj (Object) -- the object whose methods are to be retrieved
def irb_all_methods(obj = self)
  methods = obj.methods
  irb_wrap_methods obj, methods
end

def irb_class_instance_methods(obj = self)

Returns:
  • (Array) - an array of wrapped method objects suitable for IRB interaction

Parameters:
  • obj (Object) -- the object whose class instance methods are to be retrieved
def irb_class_instance_methods(obj = self)
  methods = obj.class.instance_methods(false)
  irb_wrap_methods obj, methods
end

def irb_client

Returns:
  • (Utils::IRB::IRBServer) - a new IRB server client instance configured
def irb_client
  config = Utils::ConfigFile.new.tap(&:configure_from_paths)
  Utils::IRB::IRBServer.new(url: config.irb_server_url)
end

def irb_constants(modul = self)

Returns:
  • (Array) - an array of ConstantWrapper objects

Parameters:
  • modul (Object) -- the module from which to retrieve constants
def irb_constants(modul = self)
  modul.constants.map { |c| ConstantWrapper.new(modul.const_get(c), c) }.sort
end

def irb_instance_methods(modul = self)

Returns:
  • (Array) - an array of wrapped method objects suitable for IRB interaction

Parameters:
  • modul (Object) -- the module from which to retrieve instance methods
def irb_instance_methods(modul = self)
  methods = modul.instance_methods(false)
  irb_wrap_methods modul, methods, true
end

def irb_load!(glob = ENV.fetch('UTILS_IRB_LOAD_GLOB', 'lib/**/*.rb'))

Other tags:
    See: Amatch::PairDistance - for the fuzzy matching algorithm
    See: SearchUI - for the interactive search interface implementation

Other tags:
    Note: - This method uses fuzzy matching to help find files when typing

Returns:
  • (Boolean) - true if a file was successfully loaded, false if no file

Parameters:
  • glob (String) -- the glob pattern to search for Ruby files (defaults to
def irb_load!(glob = ENV.fetch('UTILS_IRB_LOAD_GLOB', 'lib/**/*.rb'))
  files = Dir.glob(glob)
  found = Search.new(
    match: -> answer {
      matcher = Amatch::PairDistance.new(answer.downcase)
      matches = files.map { |n| [ n, -matcher.similar(n.downcase) ] }.
        sort.select { _2 < 0 }.sort_by(&:last).map(&:first)
      matches.empty? and matches = files
      matches.first(Tins::Terminal.lines - 1)
    },
    query: -> _answer, matches, selector {
      matches.each_with_index.
      map { |m, i| i == selector ? "→ " + Search.on_blue(m) : "  " + m } * ?\n
    },
    found: -> _answer, matches, selector {
      matches[selector]
    },
    output: STDOUT
  ).start
  found or return false
  load found
end

def irb_methods(obj = self)

Returns:
  • (Array) - an array of wrapped method objects for display in IRB

Parameters:
  • obj (Object) -- the object whose class methods are to be examined
def irb_methods(obj = self)
  methods = obj.class.ancestors[1..-1].inject(obj.methods) do |all, a|
    all -= a.instance_methods
  end
  irb_wrap_methods obj, methods
end

def irb_open(url = nil, &block)

Parameters:
  • block (Proc, nil) -- the block to capture output from
  • url (String, nil) -- the URL to open
def irb_open(url = nil, &block)
  case
  when url
    system 'open', url
  when block
    Tempfile.open('wb') do |t|
      t.write capture_output(&block)
      t.rewind
      system 'open', t.path
    end
  when url = receiver_unless_main(method(__method__))
    irb_open url
  else
    raise ArgumentError, 'need an url or block'
  end
end

def irb_read(filename, chunk_size = 8_192)

Returns:
  • (String, nil) - the entire file content if no block is given,

Other tags:
    Yieldparam: chunk - a portion of the file content

Other tags:
    Yield: - yields each chunk of the file to the block

Parameters:
  • chunk_size (Integer) -- the size of each chunk to read when a
  • filename (String) -- the path to the file to be read
def irb_read(filename, chunk_size = 8_192)
  if block_given?
    File.open(filename) do |file|
      until file.eof?
        yield file.read(chunk_size)
      end
    end
    nil
  else
    File.read filename
  end
end

def irb_server

Returns:
  • (Utils::IRB::IRBServer) - the IRB server instance, initialized
def irb_server
  unless @irb_server
    config = Utils::ConfigFile.new.tap(&:configure_from_paths)
    @irb_server = Utils::IRB::IRBServer.new(url: config.irb_server_url).start
  end
  @irb_server
end

def irb_server_stop

Returns:
  • (nil) - always returns nil after sending the stop command to
def irb_server_stop
  irb_client.stop_server
end

def irb_singleton_methods(obj = self)

Returns:
  • (Array) - an array of singleton method names associated with the object

Parameters:
  • obj (Object) -- the object whose singleton methods are to be retrieved
def irb_singleton_methods(obj = self)
  irb_wrap_methods obj, obj.methods(false)
end

def irb_subclasses(klass = self)

Returns:
  • (Array) - an array of ConstantWrapper objects

Parameters:
  • klass (Object) -- the class object to retrieve subclasses from
def irb_subclasses(klass = self)
  klass.subclasses.map { |c| ConstantWrapper.new(eval(c), c) }.sort
end

def irb_time(n = 1, &block)

Other tags:
    Yield: - the block to be executed and timed

Parameters:
  • n (Integer) -- the number of times to execute the block, defaults
def irb_time(n = 1, &block)
  s = Time.now
  n.times(&block)
  d = Time.now - s
ensure
  d ||= Time.now - s
  if n == 1
    warn "Took %.3fs seconds." % d
  else
    warn "Took %.3fs seconds, %.3fs per call (avg)." % [ d, d / n ]
  end
end

def irb_time_result(n = 1)

Returns:
  • (Object) - the result of the last block execution

Other tags:
    Yield: -

Parameters:
  • n (Integer) -- the number of times to execute the block
def irb_time_result(n = 1)
  r = nil
  irb_time(n) { |i| r = yield(i) }
  r
end

def irb_time_watch(duration = 1)

Other tags:
    Yield: - the block to be measured, receiving the iteration count as an argument

Parameters:
  • duration (Integer) -- the time interval in seconds between
def irb_time_watch(duration = 1)
  start = Time.now
  pre = nil
  avg = Hash.new
  i = 0
  fetch_next = -> cur do
    pre = cur.map(&:to_f)
    i += 1
    sleep duration
  end
  loop do
    cur = [ yield(i) ].flatten
    unless pre
      fetch_next.(cur)
      redo
    end
    expired = Time.now - start
    diffs = cur.zip(pre).map { |c, p| c - p }
    rates = diffs.map { |d| d / duration }
    durs = cur.zip(rates).each_with_index.map { |(c, r), i|
      if r < 0
        x = c.to_f / -r
        a = avg[i].to_f
        a -= a / 2
        a += x / 2
        d = Tins::Duration.new(a)
        ds = d.to_s
        ds.singleton_class { define_method(:to_f) { d.to_f } }
        avg[i] = ds
      end
      avg[i]
    }
    warn "#{expired} #{cur.zip(diffs, rates, durs) * ' '} 𝝙 / per sec."
    fetch_next.(cur)
    sleep duration
  end
end

def irb_toggle_logging

Returns:
  • (TrueClass, FalseClass) - true if the logger was switched to
def irb_toggle_logging
  require 'logger'
  if ActiveRecord::Base.logger != $logger
    $old_logger = ActiveRecord::Base.logger
    ActiveRecord::Base.logger = $logger
    true
  else
    ActiveRecord::Base.logger = $old_logger
    false
  end
end

def irb_wrap_methods(obj = self, methods = methods(), modul = false)

Returns:
  • (Array) - an array of wrapped method objects sorted in ascending order

Parameters:
  • modul (TrueClass, FalseClass) -- flag indicating if the methods are module methods
  • methods (Array) -- the array of method names to wrap
  • obj (Object) -- the object whose methods are being wrapped
def irb_wrap_methods(obj = self, methods = methods(), modul = false)
  methods.map do |name|
    MethodWrapper.new(obj, name, modul) rescue nil
  end.compact.sort!
end

def irb_write(filename, text = nil, &block)

Other tags:
    Yield: - a block that generates content to be written to the file

Parameters:
  • text (String, nil) -- the text content to write to the file, or
  • filename (String) -- the path to the file where content will be
def irb_write(filename, text = nil, &block)
  if text.nil? && block
    File.secure_write filename, nil, 'wb', &block
  else
    File.secure_write filename, text, 'wb'
  end
end

def less(with_stderr = false, &block)

Other tags:
    Yield: -

Parameters:
  • with_stderr (TrueClass, FalseClass) -- whether to include standard error in the capture
def less(with_stderr = false, &block)
  IO.popen($pager, 'w') do |f|
    f.write capture_output(with_stderr, &block)
    f.close_write
  end
  nil
end

def receiver_unless_main(method, &block)

Returns:
  • (String, nil) - the receiver name if it is not 'main', otherwise nil

Parameters:
  • block (Proc) -- an optional block to execute with the receiver name
  • method (Method) -- the method object to inspect
def receiver_unless_main(method, &block)
  receiver_name = method.receiver.to_s
  if receiver_name != 'main'
    if block
      block.(receiver_name)
    else
      receiver_name
    end
  end
end

def ri(*patterns, doc: 'ri')

Parameters:
  • doc (String) -- the documentation command to execute (defaults to 'ri')
  • patterns (Array) -- the patterns to search for in the documentation
def ri(*patterns, doc: 'ri')
  patterns.empty? and
    receiver_unless_main(method(__method__)) do |pattern|
      return ri(pattern, doc: doc)
    end
  patterns.map! { |p|
    case
    when Module === p
      p.name
    when p.respond_to?(:to_str)
      p.to_str
    else
      p.class.name
    end
  }
  system "#{doc} #{patterns.map { |p| "'#{p}'" } * ' ' } | #$pager"
end

def yri(*patterns)

Parameters:
  • patterns (Array) -- the patterns to look up documentation for
def yri(*patterns)
  ri(*patterns, doc: 'yri')
end