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

Add exact_match to settings, defaulting to inexact matching #154

Merged
merged 8 commits into from
May 3, 2024

Conversation

nanobowers
Copy link
Collaborator

Add support for inexact long-option matches, inspired by Perl's Getopt::Long.

Allows the user to provide a leading substring of characters for a long-option so long as it is not ambiguous which option it references
E.g. if you have options cake and carrot,

  • ✔️ --car, --carr, --carro, --carrot can enable carrot
  • ✔️ --cak, --cake can enable cake
  • --ca is invalid because it is ambiguous.

The behavior is not enabled for --no options due to concerns over confusion.
The exact_match behavior is defaulted to true, but can be turned off by passing in settings. exact_match: false

Additional tests were added to clarify behavior around the settings hash.

@miq-bot add-label enhancement
@miq-bot add-reviewer @Fryguy

@Fryguy
Copy link
Member

Fryguy commented May 3, 2024

I was on the fence on this one, but this part changed my mind, so overall I'm good with this idea:

The exact_match behavior is defaulted to true, but can be turned off by passing in settings. exact_match: false

lib/optimist.rb Outdated Show resolved Hide resolved
lib/optimist.rb Outdated
## Otherwise, we raise an error that the partially given option was ambiguous.
def perform_inexact_match(arg, partial_match) # :nodoc:
return @long[partial_match] if @long.has_key?(partial_match)
partially_matched_keys = @long.keys.grep(/^#{partial_match}/)
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to escape the partial match? Command-line wise, I'm not sure if weird characters can get in there, but it might make sense to be defensive anyway.

Suggested change
partially_matched_keys = @long.keys.grep(/^#{partial_match}/)
partially_matched_keys = @long.keys.grep(/^#{Regexp.escape(partial_match)}/)

Example of the difference:

[1] pry(main)> partial_match = ".o"
[2] pry(main)> "foo".match?(/^#{partial_match}")
=> true
[3] pry(main)> "foo".match?(/^#{Regexp.escape(partial_match)}/)
=> false

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

actually wondering if this should be a select with start_with? regex may be overkill here

lib/optimist.rb Outdated
@@ -316,10 +331,14 @@ def parse(cmdline = ARGV)
else raise CommandlineError, "invalid argument syntax: '#{arg}'"
end

sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to check if the string starts with --no- or just includes --no-? The regex right now is the latter, but I don 't think that's what we want.

Regardless, I don't see us using any regex special chars nor the result from this, so I think we could use .start_with? or .include? respectively, with a string "--no-"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hrm, interesting. Agree and we can do this as part of this PR or another.

lib/optimist.rb Outdated Show resolved Hide resolved
lib/optimist.rb Outdated Show resolved Hide resolved
Comment on lines +784 to +788
## test-only access reader method so that we dont have to
## expose settings in the public API.
class Optimist::Parser
def get_settings_for_testing ; return @settings ;end
end
Copy link
Member

Choose a reason for hiding this comment

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

Is it a problem to expose settings in the public API? I'm wondering if we should just allow it?

Copy link
Member

Choose a reason for hiding this comment

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

(Note: it's fine for this PR to keep them private, and I won't hold up merge for that)

Comment on lines +790 to +792
def test_two_arguments_passed_through_block
newp = Parser.new(:abcd => 123, :efgh => "other" ) do |i|
end
Copy link
Member

Choose a reason for hiding this comment

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

This is interesting - I actually thought this should raise an exception. (We can discuss separately, I won't hold up the PR for this)

@Fryguy
Copy link
Member

Fryguy commented May 3, 2024

This is really nice. My only hangup is that I think the default of exact_match should be true, to maintain consistency with previous optimist versions.

nanobowers and others added 3 commits May 3, 2024 12:46
Co-authored-by: Jason Frey <fryguy9@gmail.com>
Co-authored-by: Jason Frey <fryguy9@gmail.com>
Co-authored-by: Jason Frey <fryguy9@gmail.com>
@nanobowers
Copy link
Collaborator Author

note to self: will need to update the tests to handle the flipped default...

@Fryguy Fryguy merged commit 6944cdb into ManageIQ:master May 3, 2024
12 checks passed
@Fryguy Fryguy self-assigned this May 3, 2024
Fryguy added a commit that referenced this pull request Nov 11, 2024
Added:
- Align the short and long forms into their own columns in the help output (#145 - thanks akhoury6)
- Add support for DidYouMean when long options are spelled incorrectly (#150 - thanks nanobowers)
- Using `permitted:` restricts the allowed values that a end-user inputs to a pre-defined list (#147 - thanks akhoury6)
- Add exact_match to settings, defaulting to inexact matching (#154 - thanks nanobowers)
- Add setting to disable implicit short options (#155 - thanks nanobowers)
- Add alt longname and multiple char support (#151 - thanks nanobowers)
- Permitted regexp/range support (#158, #159- thanks nanobowers)
- Add some examples (#161 - thanks nanobowers)

Changed:
- Enable frozen_string_literal for future-ruby support (#149, #153  - thanks nanobowers)
- Refactor constraints (#156 - thanks nanobowers)
- Fix assert_raises to assert_raises_errmatch (#160 - thanks nanobowers)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants