Skip to content

Commit

Permalink
Add SourceFinder#resolve_rdoc_path
Browse files Browse the repository at this point in the history
  • Loading branch information
st0012 committed Aug 30, 2024
1 parent 06eb0bf commit 388fd0d
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
40 changes: 40 additions & 0 deletions lib/irb/source_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,46 @@ def initialize(irb_context)
@irb_context = irb_context
end

def resolve_rdoc_path(signature, super_level = 0)
case signature
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
eval_receiver_or_owner(signature) # trigger autoload
*parts, name = signature.split('::', -1)
base =
if parts.empty? # ConstName
find_const_owner(name)
elsif parts == [''] # ::ConstName
Object
else # ConstPath::ConstName
eval_receiver_or_owner(parts.join('::'))
end

if base == Object
"#{name}.html"
else
base.name.split("::").join("/") + "/#{name}.html"
end
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
owner = eval_receiver_or_owner(Regexp.last_match[:owner])
method = Regexp.last_match[:method]
return unless owner.respond_to?(:instance_method)
method = method_target(owner, super_level, method, "owner")
return unless method
owner.name.split("::").join("/") + ".html#method-i-#{method.name}"
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
receiver = eval_receiver_or_owner(Regexp.last_match[:receiver] || 'self')
method = Regexp.last_match[:method]
return unless receiver.respond_to?(method, true)
method = method_target(receiver, super_level, method, "receiver")
return unless method

method_type_flag = method.owner.singleton_class? ? "c" : "i"
receiver.name.split("::").join("/") + ".html#method-#{method_type_flag}-#{method.name}"
end
rescue EvaluationError
nil
end

def find_source(signature, super_level = 0)
case signature
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
Expand Down
55 changes: 55 additions & 0 deletions test/irb/test_source_finder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require "irb"

require_relative "helper"

module TestIRB
class SourceFinderTest < TestCase
def setup
IRB.init_config(nil)
IRB.conf[:USE_SINGLELINE] = false
IRB.conf[:VERBOSE] = false
IRB.conf[:USE_PAGER] = false
workspace = IRB::WorkSpace.new(Object.new)
@context = IRB::Context.new(nil, workspace)

@get_screen_size = Reline.method(:get_screen_size)
Reline.instance_eval { undef :get_screen_size }
def Reline.get_screen_size
[36, 80]
end
save_encodings

@source_finder = IRB::SourceFinder.new(@context)
end

def teardown
Reline.instance_eval { undef :get_screen_size }
Reline.define_singleton_method(:get_screen_size, @get_screen_size)
restore_encodings
end

def test_resolve_rdoc_path_for_constant
assert_equal "String.html", @source_finder.resolve_rdoc_path("String")
assert_equal "String.html", @source_finder.resolve_rdoc_path("::String")
assert_equal "IRB/Context.html", @source_finder.resolve_rdoc_path("IRB::Context")
end

def test_resolve_rdoc_path_for_instance_method
assert_equal "String.html#method-i-upcase", @source_finder.resolve_rdoc_path("String#upcase")
end

def test_resolve_rdoc_path_for_class_method
assert_equal "String.html#method-c-new", @source_finder.resolve_rdoc_path("String.new")
end

def test_resolve_rdoc_path_for_nonexistent_constant
assert_nil @source_finder.resolve_rdoc_path("NonexistentConstant")
end

def test_resolve_rdoc_path_for_nonexistent_method
assert_nil @source_finder.resolve_rdoc_path("String#nonexistent_method")
end
end
end

0 comments on commit 388fd0d

Please sign in to comment.