Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move rdoc require out of repeated execution path #416

Merged
merged 3 commits into from
Oct 24, 2022

Conversation

st0012
Copy link
Member

@st0012 st0012 commented Oct 18, 2022

SHOW_DOC_DIALOG will be called repeatedly whenever the corresponding key is pressed, but we only need to require rdoc once. So ideally the require can be put outside of the proc.

And because when rdoc is not available the entire proc will be nonfunctional, we can stop registering the SHOW_DOC_DIALOG if we failed to require rdoc.

@st0012
Copy link
Member Author

st0012 commented Oct 19, 2022

@junaruga I saw #395 and found this potential improvement. Let me know what you think about it :-)

@junaruga
Copy link
Member

Sure. I will check it tomorrow and will let you know it.

@junaruga
Copy link
Member

Now I checked the PR's code.

This PR's intent is to improve the performance, avoid calling the require 'rdoc' repeatedly, because accessing the rdoc files to check if it exists repeatedly is costy. Right?

I suppose if we keep the compatibility from the previous code, when the require 'rdoc' raises the LoadError, we still need to set the nil to the Reline.add_dialog_proc's 2nd argument. So, the code can be below.

      if IRB.conf[:USE_AUTOCOMPLETE]
        dialog = nil 
        begin
          require 'rdoc'
          dialog = SHOW_DOC_DIALOG
        rescue LoadError
        end
        Reline.add_dialog_proc(:show_doc, dialog, Reline::DEFAULT_DIALOG_CONTEXT)
      end 

But if we don't need to call the Reline.add_dialog_proc in the case of the require 'rdoc' raising the LoadError, the current PR looks ok.

SHOW_DOC_DIALOG will be called repeatedly whenever the corresponding key
is pressed, but we only need to require rdoc once. So ideally the
require can be put outside of the proc.

And because when rdoc is not available the entire proc will be
nonfunctional, we can stop registering the SHOW_DOC_DIALOG if we failed
to require rdoc.
@st0012
Copy link
Member Author

st0012 commented Oct 20, 2022

This PR's intent is to improve the performance, avoid calling the require 'rdoc' repeatedly, because accessing the rdoc files to check if it exists repeatedly is costy. Right?

Yes. Especially in the case when rdoc is not installed, it'll repeatedly raise and rescue LoadError.

I suppose if we keep the compatibility from the previous code, when the require 'rdoc' raises the LoadError, we still need to set the nil to the Reline.add_dialog_proc's 2nd argument.

Actually, the dialog can't be nil because when being rendered it'll cause error at this line:

/Users/st0012/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/reline-0.3.1/lib/reline/line_editor.rb:588:in `instance_exec': no block given (LocalJumpError)

So my test cases were actually misleading and I've updated them.

If we still want to have the :show_proc dialog registered for compatibility reason, we can use Proc.new {} instead.

But if we don't need to call the Reline.add_dialog_proc in the case of the require 'rdoc' raising the LoadError

I think we don't need to call Reline.add_dialog_proc in that case tbh. Because reline iterates through registered dialogs in every rendering and performs certain computation even when if the dialog proc is empty, it should be avoided when possible.

@junaruga
Copy link
Member

Yes. Especially in the case when rdoc is not installed, it'll repeatedly raise and rescue LoadError.

Ah, ok. That process looks costy.

Actually, the dialog can't be nil because when being rendered it'll cause error at this line:

Oh I see. Thanks for finding the issue.

If we still want to have the :show_proc dialog registered for compatibility reason, we can use Proc.new {} instead.

The :show_proc dialog? You meant :show_doc dialog?

Right now it's not easy to test the non-rdoc case. When we create the Ruby RPM package in the Fedora project, we make the separated rdoc RPM package as a soft (weak or optional) dependency. In the situation, I can test it the case. So, right now I am ok to merge this PR.

I think we don't need to call Reline.add_dialog_proc in that case tbh. Because reline iterates through registered dialogs in every rendering and performs certain computation even when if the dialog proc is empty, it should be avoided when possible.

OK. Thanks for checking it.

@st0012
Copy link
Member Author

st0012 commented Oct 20, 2022

The :show_proc dialog? You meant :show_doc dialog?

Yes 🤦‍♂️

Right now it's not easy to test the non-rdoc case.

Yeah I'm aware of that. I'll see if having unit-tests like TestRelineInputMethod makes implementing the conditional mocking you mentioned in #396 easier.

@junaruga
Copy link
Member

junaruga commented Oct 21, 2022

Yeah I'm aware of that. I'll see if having unit-tests like TestRelineInputMethod makes implementing the conditional mocking you mentioned in #396 easier.

OK. That's great for you to work on covering the no-rdoc case.
Maintainers for the IRB, could you review this PR?

@st0012
Copy link
Member Author

st0012 commented Oct 21, 2022

@junaruga I've added a case for the rdoc missing scenario based on your snippet in #395 (comment). Let me know if that's an acceptable approach to you.

IRB.conf[:USE_AUTOCOMPLETE] = true

without_rdoc do
IRB::RelineInputMethod.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert commands should be in the wethout_rdoc block shouldn't be?

      without_rdoc do
        IRB::RelineInputMethod.new
        assert Reline.autocompletion
        # doesn't register show_doc dialog
        assert_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc
      end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it doesn't need to be? Because Reline's state isn't affected by the without_rdoc block. We just need to make sure the logic that changes Reline's state is inside the block.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you are right. Yes, you don't need to move the assertions.

Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
end

def without_rdoc(&block)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving the without_rdoc method to the common file test/lib/helper.rb, as the logic: require 'rdoc' and resure LoadError is in other parts too?

$ grep -r rdoc lib/
lib/irb/cmd/help.rb:        require 'rdoc/ri/driver'
lib/irb/completion.rb:        require 'rdoc'
lib/irb/easter-egg.rb:          require "rdoc"
lib/irb/input-method.rb:          require 'rdoc'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to leave it to the next PR (which I'll open after this is merged) because the goal of this one is to move out of the require "rdoc". Increasing the coverage is just a good addition. WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with you. It can be the next PR. Without the test_initialization_with_use_autocomplete_but_without_rdoc test in this PR, it's still better than the current situation.

@junaruga
Copy link
Member

I've added a case for the rdoc missing scenario based on your snippet in #395 (comment). Let me know if that's an acceptable approach to you.

Thanks for that! That looks great. I like the approach of the without_rdoc as a direction. I commented. I am not sure if the test with the without_rdoc works on Bundler on RubyGems to pass the CI after moving the assertions to the inside of the without_rdoc.

@st0012
Copy link
Member Author

st0012 commented Oct 21, 2022

cc @peterzhu2118

Copy link
Member

@peterzhu2118 peterzhu2118 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you!

@peterzhu2118 peterzhu2118 merged commit daa1ea1 into ruby:master Oct 24, 2022
@st0012 st0012 deleted the follow-#395 branch October 24, 2022 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants