Skip to content

Conversation

@smcabrera
Copy link

@smcabrera smcabrera commented Feb 17, 2025

closes #585

Long-time listener first-time caller! We use active_interaction at work and it's been a big help for us using command objects in a standardized way, kudos.

See the issue for a description of what I'm trying to do here. I'm new so let me know if there are changes I can make to match the project better.

@smcabrera smcabrera changed the base branch from main to next February 17, 2025 04:31
Comment on lines 39 to 51
ALLOWED_KWARGS = %i[
desc
default
index_errors
strip
format
digits
base
from
methods
class
converter
].freeze
Copy link
Author

Choose a reason for hiding this comment

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

These were all the options I could find from the those mentioned in the docs.

Not all of these options are possible for every kind of filter; a more sophisticated version of this would verify that the given option was possible for the filter, but I wanted to stand up a PR to see what people think first.

Copy link
Owner

Choose a reason for hiding this comment

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

I do think we should have these be per filter. If we're going to check we should be as accurate as we can be.

def add_filter(klass, name, options, &block)
raise InvalidFilterError, %("#{name}" is a reserved name) if Inputs.reserved?(name)
if (invalid_options = options.keys - ALLOWED_KWARGS).any?
raise InvalidFilterError, "invalid options: #{invalid_options.join(', ')}"
Copy link
Author

Choose a reason for hiding this comment

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

Is the right exception to use? Also I wanted to make sure the options were in the message to aid in debugging but not sure if the format should change.

Copy link
Owner

Choose a reason for hiding this comment

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

Ruby throws an ArgumentError for methods with invalid keyword arguments:

* def foo(bar:)
*   puts bar
> end
=> :foo
> foo(bar: 'hi', baz: 'yo')
(irb):10:in 'foo': unknown keyword: :baz (ArgumentError)
        from (irb):13:in '<main>'
        ...

I think replicating this makes the most sense.

Comment on lines 80 to 84
# rubocop:disable Style/MissingRespondToMissing
def method_missing(*args, &block)
super(*args) do |klass, names, options|
super do |klass, names, options|
Copy link
Author

Choose a reason for hiding this comment

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

I ran rake and rubocop complained about this one, although it seems unrelated to any of my changes, not sure why it wouldn't have come up before 🤔

Copy link
Owner

Choose a reason for hiding this comment

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

I can look into this.

Comment on lines -14 to +15
string :attribute, defualt: nil
array :array, defualt: nil
string :attribute, default: nil
array :array, default: nil
Copy link
Author

Choose a reason for hiding this comment

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

I wasn't sure if this misspelling was intentional since the spec is about errors. But it still passes after fixing it (and my change would break it). @AaronLasseigne you would know better than I would.

Copy link
Owner

Choose a reason for hiding this comment

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

Not intentional 😬, maybe this PR is a good idea!

# @param options [Hash]
def add_filter(klass, name, options, &block)
raise InvalidFilterError, %("#{name}" is a reserved name) if Inputs.reserved?(name)
if (invalid_options = options.keys - ALLOWED_KWARGS).any?
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment on the implementation specifically. Using constant ALLOWED_KWARGS makes it impossible to extend functionality with new behavior. Consider using methods, as they can be extended.

def add_filter(klass, name, options, &block)
raise InvalidFilterError, %("#{name}" is a reserved name) if Inputs.reserved?(name)
if (invalid_options = options.keys - ALLOWED_KWARGS).any?
raise InvalidFilterError, "invalid options: #{invalid_options.join(', ')}"
Copy link
Contributor

@antulik antulik Feb 23, 2025

Choose a reason for hiding this comment

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

Filter option validation is more suitable for Filter classes as each filter can validate its own options. Consider moving them there.

@AaronLasseigne
Copy link
Owner

Sorry I've been slow to get to this. Life and all. I like the idea but I have a few comments that I'll note.

@smcabrera smcabrera force-pushed the main branch 2 times, most recently from 72aa881 to 10245e7 Compare December 31, 2025 20:36
Currently filters will allow you to include keyword arguments that don't exist, leading to potentially confusing outcomes for users.
This change makes it so that unsupported keyword arguments will raise an
exception, while still allowing users to extend the available options if needed.
Comment on lines +54 to +57
# Returns the list of allowed options for this filter type.
#
# @return [Array<Symbol>]
def allowed_options
Copy link
Author

Choose a reason for hiding this comment

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

I didn't replicate this comment on all the subclass methods, but I could if we think that's valuable

@smcabrera
Copy link
Author

smcabrera commented Dec 31, 2025

Trying to see if I can close up some open PRs before the new year 😅

I made a few changes in response to feedback

  1. I turned the constant level out arguments into a class method so that it could be overridden. HT @antulik for the feedback
  2. I defined a method on the superclass and allowed the individual filter subclasses to define their own set. This allows filters to find only the options that are valid for them, making this validation more precise. HT @AaronLasseigne for the feedback
  3. Updated the exception raised to be the ArgumentError that Ruby itself raises for invalid keyword arguments. HT @AaronLasseigne for the feedback.

Also added something to the changelog, @AaronLasseigne may have thoughts on what's the best way to summarize this change as I don't think I've committed to this project before

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-existent filter arguments

3 participants