All Files
(
100.0%
covered at
28.85
hits/line
)
16 files in total.
235 relevant lines,
235 lines covered and
0 lines missed.
(
100.0%
)
17 total branches,
17 branches covered and
0 branches missed.
(
100.0%
)
-
# frozen_string_literal: true
-
-
1
require "irb"
-
1
require "zeitwerk"
-
-
1
Zeitwerk::Loader.new.then do |loader|
-
1
loader.inflector.inflect "irb" => "IRB"
-
1
loader.tag = "irb-kit"
-
1
loader.push_dir "#{__dir__}/.."
-
1
loader.setup
-
end
-
-
1
module IRB
-
# Main namespace.
-
1
module Kit
-
1
def self.loader registry = Zeitwerk::Registry
-
3
@loader ||= registry.loaders.each.find { |loader| loader.tag == "irb-kit" }
-
end
-
-
1
def self.register_commands(*) = Register.new(IRB::Command, :Commands).call(*)
-
-
1
def self.register_helpers(*) = Register.new(IRB::HelperMethod, :Helpers).call(*)
-
-
1
def self.prompt = @prompt ||= Prompter.new.call
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Commands
-
# Answers descendants of a class.
-
1
class Descendants < IRB::Command::Base
-
1
MONIKER = :descendants
-
-
1
category "Kit"
-
-
1
description "Show class descendants."
-
-
1
help_message <<~BODY
-
Usage: descendants <class>
-
-
Examples:
-
-
descendants Object
-
descendants IO
-
descendants Ractor::Error
-
BODY
-
-
1
def initialize context, handler: Handlers::Descender.new
-
1
super context
-
1
@handler = handler
-
end
-
-
1
def execute(name) = handler.call(name)
-
-
1
private
-
-
1
attr_reader :handler
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Provides default functionality for all handlers.
-
1
class Abstract
-
1
def initialize io: STDOUT
-
29
@io = io
-
end
-
-
1
def call
-
1
fail NoMethodError,
-
"`#{self.class}##{__method__} #{method(__method__).parameters}` must be implemented."
-
end
-
-
1
protected
-
-
1
attr_reader :io
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles copying content to the macOS clipboard.
-
1
class Clipper < Abstract
-
1
def initialize(processor: IO, **)
-
4
@processor = processor
-
4
super(**)
-
end
-
-
1
def call(*lines)
-
3
processor.popen("pbcopy", "w") { |clipboard| clipboard.write lines.join("\n") }
-
2
io.puts "Copied to clipboard."
-
rescue Errno::ENOENT
-
1
io.puts "ERROR: Unable to copy since `pbcopy` is only supported on macOS."
-
end
-
-
1
private
-
-
1
attr_reader :processor
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles editing of constant source code.
-
1
class ConstantEditor < Abstract
-
1
def initialize(editor: Editor.new, **)
-
3
@editor = editor
-
3
super(**)
-
end
-
-
1
def call name
-
2
editor.call(*Object.const_source_location(name))
-
rescue NameError
-
1
io.puts "ERROR (invalid constant): #{name.inspect}."
-
end
-
-
1
private
-
-
1
attr_reader :editor
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles finding the descendants of a class.
-
1
class Descender < Abstract
-
1
def initialize(collector: ObjectSpace, **)
-
4
@collector = collector
-
4
super(**)
-
end
-
-
1
def call name
-
7
then: 1
else: 2
collect(name).then { |all| all.empty? ? "No descendants found." : all.join("\n") }
-
3
.then { |result| io.puts result }
-
rescue NameError
-
1
io.puts "ERROR: #{name.inspect} doesn't exist."
-
end
-
-
1
private
-
-
1
attr_reader :collector
-
-
1
def collect name
-
4
superclass = Object.const_get name
-
-
3
collector.each_object(Class)
-
6288
.select { |subclass| subclass < superclass }
-
3
.tap { |descendants| descendants.delete superclass }
-
.map(&:to_s)
-
.sort
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles editing of source code.
-
1
class Editor < Abstract
-
1
def initialize(environment: ENV, kernel: Kernel, **)
-
6
@environment = environment
-
6
@kernel = kernel
-
6
super(**)
-
end
-
-
1
def call path, line = nil
-
4
path_and_line = [path, line].join ":"
-
-
4
then: 3
if path && Pathname(path).exist?
-
3
io.puts "Editing: #{path_and_line}..."
-
3
kernel.system %(#{environment.fetch "EDITOR"} #{path_and_line})
-
else: 1
else
-
1
io.puts "ERROR (invalid path): #{path}."
-
end
-
1
rescue KeyError then io.puts "ERROR: The `EDITOR` environment variable must be defined."
-
end
-
-
1
private
-
-
1
attr_reader :environment, :kernel
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles editing of method source code.
-
1
class MethodEditor < Abstract
-
1
def initialize(editor: Editor.new, **)
-
3
@editor = editor
-
3
super(**)
-
end
-
-
1
def call object, name
-
2
editor.call(*object.method(name).source_location)
-
rescue NameError
-
1
io.puts "ERROR: Undefined method `#{name.inspect}` for `#{object.inspect}`."
-
end
-
-
1
private
-
-
1
attr_reader :editor
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles pasting content from the macOS clipboard.
-
1
class Paster < Abstract
-
1
def initialize(processor: IO, **)
-
3
@processor = processor
-
3
super(**)
-
end
-
-
1
def call
-
2
processor.popen "pbpaste", "r", &:read
-
rescue Errno::ENOENT
-
1
io.puts "ERROR: Unable to paste since `pbpaste` is only supported on macOS."
-
end
-
-
1
private
-
-
1
attr_reader :processor
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Handlers
-
# Handles searching an object's methods by pattern.
-
1
class Searcher < Abstract
-
1
def initialize(matcher: Regexp, **)
-
5
@matcher = matcher
-
5
super(**)
-
end
-
-
1
def call object, pattern
-
4
object.methods
-
.grep(matcher.new(pattern))
-
.join("\n")
-
3
then: 1
else: 2
.then { |result| result.empty? ? io.puts("No matches found.") : io.puts(result) }
-
rescue TypeError
-
1
io.puts "ERROR: Use only a string or regular expression for the pattern."
-
end
-
-
1
private
-
-
1
attr_reader :matcher
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Helpers
-
# Copies input to macOS clipboard.
-
1
class Clip < IRB::HelperMethod::Base
-
1
MONIKER = :clip
-
-
1
description "Copy input to macOS clipboard. DEPRECATED."
-
-
1
def initialize handler: Handlers::Clipper.new
-
1
super()
-
1
@handler = handler
-
end
-
-
1
def execute(*)
-
2
warn "`clip` is deprecated, use IRB's native `copy` helper instead.",
-
category: :deprecated
-
-
2
handler.call(*)
-
end
-
-
1
private
-
-
1
attr_reader :handler
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "pathname"
-
-
1
module IRB
-
1
module Kit
-
1
module Helpers
-
# Edits the source code of a constant or method.
-
1
class EditSource < IRB::HelperMethod::Base
-
1
MONIKER = :esource
-
-
1
description "Edit the source code of a constant or method in your default editor."
-
-
1
def initialize constant_handler: Handlers::ConstantEditor.new,
-
method_handler: Handlers::MethodEditor.new
-
1
super()
-
1
@constant_handler = constant_handler
-
1
@method_handler = method_handler
-
end
-
-
1
def execute(*arguments)
-
5
in: 2
case arguments
-
2
in: 2
in [name] then puts constant_handler.call(name)
-
2
else: 1
in [object, name] then puts method_handler.call(object, name)
-
1
else puts "ERROR: Invalid constant or method for arguments: #{arguments.inspect}."
-
end
-
end
-
-
1
private
-
-
1
attr_reader :constant_handler, :method_handler
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Helpers
-
# Pastes last entry from macOS clipboard.
-
1
class Paste < IRB::HelperMethod::Base
-
1
MONIKER = :paste
-
-
1
description "Paste last entry from macOS clipboard."
-
-
1
def initialize handler: Handlers::Paster.new
-
1
super()
-
1
@handler = handler
-
end
-
-
1
def execute = handler.call
-
-
1
private
-
-
1
attr_reader :handler
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
1
module Helpers
-
# Search an object's methods by pattern.
-
1
class Search < IRB::HelperMethod::Base
-
1
MONIKER = :search
-
-
1
description "Search an object's methods by pattern."
-
-
1
def initialize handler: Handlers::Searcher.new
-
1
super()
-
1
@handler = handler
-
end
-
-
1
def execute(*) = handler.call(*)
-
-
1
private
-
-
1
attr_reader :handler
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
# Dynamically computes prompt based environment.
-
1
class Prompter
-
1
COLORS = {green: 32, red: 31}.freeze
-
-
1
def initialize version = RUBY_VERSION, delimiter: "|", colors: COLORS
-
8
super()
-
8
@version = version
-
8
@delimiter = delimiter
-
8
@colors = colors
-
end
-
-
1
def call
-
8
then: 2
if defined? Hanami::VERSION
-
2
else: 6
details Hanami::VERSION, Hanami.app.name.delete_suffix("::App"), Hanami.env
-
6
then: 2
elsif defined? Rails
-
2
else: 4
details Rails.version, Rails.application.class.module_parent_name, Rails.env
-
4
else version_with_optional_project
-
end
-
end
-
-
1
private
-
-
1
attr_reader :version, :delimiter, :colors
-
-
1
def details framework_version, application_name, environment
-
4
[version, framework_version, application_name.downcase, color(environment)].join delimiter
-
end
-
-
1
def color environment
-
4
then: 2
else: 2
code = environment.to_sym == :production ? red : green
-
4
"\e[#{code}m#{environment}\e[0m"
-
end
-
-
1
def version_with_optional_project
-
4
File.basename(`git rev-parse --show-toplevel 2> /dev/null`.strip)
-
.downcase
-
4
.then { |project| [version, project].reject(&:empty?).join delimiter }
-
end
-
-
1
def green = colors.fetch __method__
-
-
1
def red = colors.fetch __method__
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module IRB
-
1
module Kit
-
# Loads extensions for namespace.
-
1
class Register
-
1
ALL = [:all].freeze
-
-
1
def initialize registrar, namespace, all: ALL
-
7
@registrar = registrar
-
7
@namespace = IRB::Kit.const_get namespace
-
7
@all = all
-
end
-
-
8
then: 3
else: 4
def call(*monikers) = monikers == all ? maximum : only(*monikers)
-
-
1
private
-
-
1
attr_reader :registrar, :namespace, :all
-
-
10
def maximum = constants.each { |helper| registrar.register helper::MONIKER, helper }
-
-
1
def only(*monikers)
-
17
constants.select { |helper| monikers.include? helper::MONIKER }
-
4
.then { |selected| monikers.zip selected }
-
3
.each { |moniker, helper| registrar.register moniker, helper }
-
end
-
-
23
def constants = namespace.constants.sort.map { |name| namespace.const_get name }
-
end
-
end
-
end