Module: Utils::IRB::Shell

Includes:
FileUtils, SearchUI, Tins::Find
Included in:
Object
Defined in:
lib/utils/irb/shell.rb,
lib/utils/irb/shell.rb,
lib/utils/irb/shell/wrappers.rb

Overview

shell command integration.

Defined Under Namespace

Classes: ConstantWrapper, MethodWrapper, WrapperBase

Constant Summary collapse

Infinity =

I like to define the infinite.

1.0 / 0

Instance Method Summary collapse

Instance Method Details

#ai(query, command: false, respond: false, parse: false, dir: ?.) ⇒ String?

The ai method interacts with an Ollama chat service to process queries and optionally return responses.

This method constructs command-line arguments for the ollama_chat_send utility based on the provided options, executes the command with the query as input, and returns the response if requested.

Parameters:

  • query (String)

    the input query to send to the Ollama chat service

  • command (TrueClass, FalseClass) (defaults to: false)

    whether to treat the query as a command

  • respond (TrueClass, FalseClass) (defaults to: false)

    whether to capture and return the response from the service

  • parse (TrueClass, FalseClass) (defaults to: false)

    whether to parse the response

  • dir (String) (defaults to: ?.)

    the directory to use for the operation

Returns:

  • (String, nil)

    the response from the Ollama chat service if respond is true, otherwise nil



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/utils/irb/shell.rb', line 88

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

#capture_output(with_stderr = false) {|void| ... } ⇒ String

The capture_output method captures stdout and optionally stderr output during code execution.

This method temporarily redirects standard output (and optionally standard error) to a temporary file, executes the provided block, and then returns the captured output as a string.

Parameters:

  • with_stderr (TrueClass, FalseClass) (defaults to: false)

    whether to also capture standard error output

Yields:

  • (void)

    the block of code to execute while capturing output

Returns:

  • (String)

    the captured output as a string



314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/utils/irb/shell.rb', line 314

def capture_output(with_stderr = false)
  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

#ed(*files) ⇒ Object

The ed method opens files for editing using the system editor.

This method provides a convenient way to edit files by invoking the configured editor. When called without arguments, it edits the current object’s representation. When called with file arguments, it edits those specific files.

Parameters:

  • files (Array)

    an array of file paths to be edited



601
602
603
604
605
606
607
# File 'lib/utils/irb/shell.rb', line 601

def ed(*files)
  if files.empty?
    $editor.full?(:edit, self)
  else
    $editor.full?(:edit, *files)
  end
end

#irb_all_class_instance_methods(obj = self) ⇒ Array

This method obtains the complete list of instance methods available for the specified object’s class, then processes them through the irb_wrap_methods helper to prepare them for interactive use in IRB.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose class instance methods are to be retrieved

Returns:

  • (Array)

    an array of wrapped method objects suitable for IRB interaction



147
148
149
150
# File 'lib/utils/irb/shell.rb', line 147

def irb_all_class_instance_methods(obj = self)
  methods = obj.class.instance_methods
  irb_wrap_methods obj, methods
end

#irb_all_instance_methods(modul = self) ⇒ Array

The irb_all_instance_methods method retrieves all instance methods defined on a module.

This method collects the instance methods from the specified module and wraps them for enhanced interactive exploration in IRB. It is designed to provide a more user-friendly interface for examining module methods within the interactive Ruby environment.

Parameters:

  • modul (Object) (defaults to: self)

    the module from which to retrieve instance methods

Returns:

  • (Array)

    an array of wrapped method objects suitable for IRB interaction



176
177
178
179
# File 'lib/utils/irb/shell.rb', line 176

def irb_all_instance_methods(modul = self)
  methods = modul.instance_methods
  irb_wrap_methods modul, methods, true
end

#irb_all_methods(obj = self) ⇒ Array

The irb_all_methods method retrieves all methods available on an object.

This method collects all methods associated with the given object (including its singleton methods) and wraps them for enhanced interactive exploration in IRB. It provides a comprehensive list of methods that can be used to understand the object’s capabilities and interface.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose methods are to be retrieved

Returns:

  • (Array)

    an array of wrapped method objects for interactive use



209
210
211
212
# File 'lib/utils/irb/shell.rb', line 209

def irb_all_methods(obj = self)
  methods = obj.methods
  irb_wrap_methods obj, methods
end

#irb_class_instance_methods(obj = self) ⇒ Array

The irb_class_instance_methods method retrieves instance methods defined directly in the class of the given object, excluding inherited methods, and wraps them for enhanced interactive exploration in IRB environment.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose class instance methods are to be retrieved

Returns:

  • (Array)

    an array of wrapped method objects suitable for IRB interaction



160
161
162
163
# File 'lib/utils/irb/shell.rb', line 160

def irb_class_instance_methods(obj = self)
  methods = obj.class.instance_methods(false)
  irb_wrap_methods obj, methods
end

#irb_clientUtils::IRB::IRBServer

The irb_client method provides access to an IRB server client instance.

This method creates and returns a new IRB server client by first loading the configuration from standard paths and then using the configured server URL to initialize the client.

Returns:

  • (Utils::IRB::IRBServer)

    a new IRB server client instance configured with the URL from the application’s configuration



588
589
590
591
# File 'lib/utils/irb/shell.rb', line 588

def irb_client
  config = Utils::ConfigFile.new.tap(&:configure_from_paths)
  Utils::IRB::IRBServer.new(url: config.irb_server_url)
end

#irb_constants(modul = self) ⇒ Array<ConstantWrapper>

The irb_constants method retrieves and wraps all constants from a given module.

This method collects all constants defined in the specified module, creates ConstantWrapper instances for each constant, and returns them sorted in ascending order.

Parameters:

  • modul (Object) (defaults to: self)

    the module from which to retrieve constants

Returns:

  • (Array<ConstantWrapper>)

    an array of ConstantWrapper objects representing the constants in the module, sorted alphabetically



275
276
277
278
279
280
281
# File 'lib/utils/irb/shell.rb', line 275

def irb_constants(modul = self)
  if modul.respond_to?(:constants)
    modul.constants.map { |c| ConstantWrapper.new(modul.const_get(c), c) }.sort
  else
    warn "#{modul} does not respond to constants method"
  end
end

#irb_current_snippetString?

The irb_current_snippet method retrieves the current code snippet stored in the IRB server.

This method accesses the IRB server instance and returns the snippet that has been stored for execution, or nil if no snippet is currently stored or if the server is not available.

Returns:

  • (String, nil)

    the current code snippet stored in the IRB server, or nil if not available



562
563
564
# File 'lib/utils/irb/shell.rb', line 562

def irb_current_snippet
  irb_server&.snippet
end

#irb_instance_methods(modul = self) ⇒ Array

Return instance methods defined in module modul without the inherited/mixed in methods. The irb_instance_methods method retrieves instance methods defined directly in a module.

This method fetches all instance methods that are explicitly defined within the specified module, excluding inherited methods. It then wraps these methods for enhanced interactive exploration within the IRB environment.

Parameters:

  • modul (Object) (defaults to: self)

    the module from which to retrieve instance methods

Returns:

  • (Array)

    an array of wrapped method objects suitable for IRB interaction



192
193
194
195
# File 'lib/utils/irb/shell.rb', line 192

def irb_instance_methods(modul = self)
  methods = modul.instance_methods(false)
  irb_wrap_methods modul, methods, true
end

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

Note:

This method uses fuzzy matching to help find files when typing partial names. It respects the terminal height to limit the number of displayed results.

The irb_load! method loads Ruby files by their names into the current environment through an interactive selection interface.

This method takes a glob pattern and finds matching Ruby files, then presents an interactive search interface for selecting which file to load. It ensures that each file is loaded only once by tracking loaded files using their paths. The method outputs messages to standard error indicating which file has been successfully loaded.

Examples:

# Load a file interactively with default glob pattern
irb_load!

# Load files matching a custom pattern
irb_load!('app/models/**/*.rb')

# Set environment variable for default pattern
ENV['UTILS_IRB_LOAD_GLOB'] = 'lib/**/*.rb'
irb_load!

Parameters:

  • glob (String) (defaults to: ENV.fetch('UTILS_IRB_LOAD_GLOB', 'lib/**/*.rb'))

    the glob pattern to search for Ruby files (defaults to ENV or ‘lib/*/.rb’)

Returns:

  • (Boolean)

    true if a file was successfully loaded, false if no file was selected or loaded

See Also:

  • for the interactive search interface implementation
  • for the fuzzy matching algorithm


513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'lib/utils/irb/shell.rb', line 513

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

#irb_methods(obj = self) ⇒ Array

The irb_methods method retrieves instance methods defined in the class hierarchy excluding those inherited from ancestor classes.

This method computes a list of instance methods that are directly defined in the class of the given object, excluding any methods that are inherited from its superclass or modules. It then wraps these methods for enhanced display in IRB.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose class methods are to be examined

Returns:

  • (Array)

    an array of wrapped method objects for display in IRB



225
226
227
228
229
230
# File 'lib/utils/irb/shell.rb', line 225

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

#irb_open(url = nil, &block) ⇒ Object

The irb_open method opens a URL or executes a block to capture output and open it.

This method provides a way to open URLs or capture the output of a block and open it in the default application. If a URL is provided, it directly opens the URL. If a block is given, it captures the output of the block, writes it to a temporary file, and opens that file. If neither is provided, it raises an error.

Parameters:

  • url (String, nil) (defaults to: nil)

    the URL to open

  • block (Proc, nil)

    the block to capture output from



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/utils/irb/shell.rb', line 123

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

#irb_read(filename, chunk_size = 8_192) {|chunk| ... } ⇒ String?

The irb_read method reads the contents of a file either entirely or in chunks. When a block is provided, it reads the file in chunks of the specified size and yields each chunk to the block. If no block is given, it reads the entire file content at once and returns it as a string.

block is provided

otherwise nil

Parameters:

  • filename (String)

    the path to the file to be read

  • chunk_size (Integer) (defaults to: 8_192)

    the size of each chunk to read when a

Yields:

  • (chunk)

    yields each chunk of the file to the block

Yield Parameters:

  • chunk (String)

    a portion of the file content

Returns:

  • (String, nil)

    the entire file content if no block is given,



468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/utils/irb/shell.rb', line 468

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

#irb_serverUtils::IRB::IRBServer

The irb_server method provides access to an IRB server instance for interactive Ruby sessions.

This method ensures that a single IRB server instance is created and started for the current process, loading the configuration from standard paths and using the configured server URL.

Returns:



545
546
547
548
549
550
551
# File 'lib/utils/irb/shell.rb', line 545

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

#irb_server_stopnil

The irb_server_stop method sends a stop command to the IRB server client.

This method accesses the IRB client instance and invokes the stop_server method on it, which gracefully shuts down the IRB server process.

Returns:

  • (nil)

    always returns nil after sending the stop command to the server



575
576
577
# File 'lib/utils/irb/shell.rb', line 575

def irb_server_stop
  irb_client.stop_server
end

#irb_singleton_methods(obj = self) ⇒ Array

The irb_singleton_methods method retrieves singleton methods associated with an object.

This method collects all singleton methods defined on the specified object, excluding inherited methods, and prepares them for display in an interactive Ruby environment.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose singleton methods are to be retrieved

Returns:

  • (Array)

    an array of singleton method names associated with the object



242
243
244
# File 'lib/utils/irb/shell.rb', line 242

def irb_singleton_methods(obj = self)
  irb_wrap_methods obj, obj.methods(false)
end

#irb_subclasses(klass = self) ⇒ Array<ConstantWrapper>

The irb_subclasses method retrieves and wraps subclass information for a given class.

This method fetches the subclasses of the specified class and creates ConstantWrapper instances for each subclass, allowing them to be sorted and displayed in a structured format.

representing the subclasses

Parameters:

  • klass (Object) (defaults to: self)

    the class object to retrieve subclasses from

Returns:



294
295
296
# File 'lib/utils/irb/shell.rb', line 294

def irb_subclasses(klass = self)
  klass.subclasses.map { |c| ConstantWrapper.new(eval(c), c) }.sort
end

#irb_time(n = 1) {|block| ... } ⇒ Object

The irb_time method measures the execution time of a block and outputs the duration to standard error.

to 1

Parameters:

  • n (Integer) (defaults to: 1)

    the number of times to execute the block, defaults

Yields:

  • (block)

    the block to be executed and timed



354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/utils/irb/shell.rb', line 354

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

#irb_time_result(n = 1) {|i| ... } ⇒ Object

The irb_time_result method executes a block n times while measuring execution time and returns the result of the last execution.

Parameters:

  • n (Integer) (defaults to: 1)

    the number of times to execute the block

Yields:

  • (i)

Returns:

  • (Object)

    the result of the last block execution



375
376
377
378
379
# File 'lib/utils/irb/shell.rb', line 375

def irb_time_result(n = 1)
  r = nil
  irb_time(n) { |i| r = yield(i) }
  r
end

#irb_time_watch(duration = 1) {|i| ... } ⇒ Object

The irb_time_watch method monitors and reports performance metrics over time.

This method continuously measures the output of a provided block, calculating differences and rates of change between successive measurements. It tracks these metrics and displays them with timing information, useful for observing how values evolve during execution.

measurements

Parameters:

  • duration (Integer) (defaults to: 1)

    the time interval in seconds between

Yields:

  • (i)

    the block to be measured, receiving the iteration count as an argument



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/utils/irb/shell.rb', line 393

def irb_time_watch(duration = 1)
  normalize = -> value { value.ask_and_send(:to_f) || 0.0 }
  start = Time.now
  pre = nil
  avg = Hash.new
  i = 0
  fetch_next = -> cur do
    pre = cur.map(&normalize)
    i += 1
    sleep duration
  end
  loop do
    cur = [ yield(i) ].flatten.map(&normalize)
    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

#irb_toggle_loggingTrueClass, FalseClass

The irb_toggle_logging method toggles the logging configuration for ActiveRecord.

This method manages the logger setting for ActiveRecord by switching between a custom logger and the previously configured logger. It returns true when switching to the custom logger, and false when reverting to the original logger.

the custom logger, false if it was reverted to the original logger

Returns:

  • (TrueClass, FalseClass)

    true if the logger was switched to



621
622
623
624
625
626
627
628
629
630
# File 'lib/utils/irb/shell.rb', line 621

def irb_toggle_logging
  if ActiveRecord::Base.logger != $logger
    $old_logger = ActiveRecord::Base.logger
    ActiveRecord::Base.logger = $logger
    true
  else
    ActiveRecord::Base.logger = $old_logger
    false
  end
end

#irb_wrap_methods(obj = self, methods = methods(), modul = false) ⇒ Array

The irb_wrap_methods method creates wrapped method objects for introspection.

This method takes a set of method names and wraps them in a way that allows for easier inspection and display within an IRB session. It handles potential errors during the wrapping process by rescuing exceptions and filtering out invalid entries.

Parameters:

  • obj (Object) (defaults to: self)

    the object whose methods are being wrapped

  • methods (Array) (defaults to: methods())

    the array of method names to wrap

  • modul (TrueClass, FalseClass) (defaults to: false)

    flag indicating if the methods are module methods

Returns:

  • (Array)

    an array of wrapped method objects sorted in ascending order



258
259
260
261
262
# File 'lib/utils/irb/shell.rb', line 258

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

#irb_write(filename, text = nil) {|| ... } ⇒ Object

The irb_write method writes text to a file or executes a block to generate content for writing.

This method provides a convenient way to write content to a file, either by passing the text directly or by executing a block that generates the content. It uses secure file writing to ensure safety.

written nil if using a block

Parameters:

  • filename (String)

    the path to the file where content will be

  • text (String, nil) (defaults to: nil)

    the text content to write to the file, or

Yields:

  • ()

    a block that generates content to be written to the file



445
446
447
448
449
450
451
# File 'lib/utils/irb/shell.rb', line 445

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

#less(with_stderr = false) {|void| ... } ⇒ Object

Use pager on the output of the commands given in the block. The less method executes a block and outputs its result through the pager.

This method runs the provided block in a controlled environment, captures its output, and streams that output through the system’s configured pager for display.

Parameters:

  • with_stderr (TrueClass, FalseClass) (defaults to: false)

    whether to include standard error in the capture

Yields:

  • (void)


339
340
341
342
343
344
345
# File 'lib/utils/irb/shell.rb', line 339

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

#ri(*patterns, doc: 'ri') ⇒ Object

The ri method invokes the ri documentation tool to display help information for the specified patterns. It automatically determines the pattern to search for when none are provided. The method handles different types of patterns including modules, objects that respond to to_str, and other objects. Documentation is displayed through the system’s ri command with output piped to the pager.

Parameters:

  • patterns (Array)

    the patterns to search for in the documentation

  • doc (String) (defaults to: 'ri')

    the documentation command to execute (defaults to ‘ri’)



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/utils/irb/shell.rb', line 44

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

#yri(*patterns) ⇒ Object

The yri method invokes the ri documentation tool with yri as the documenter to display help information for the specified patterns.

Parameters:

  • patterns (Array<String>)

    the patterns to look up documentation for



66
67
68
# File 'lib/utils/irb/shell.rb', line 66

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