Skip to content

Commit 6c3e910

Browse files
committed
Raise on non-existent kwargs
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.
1 parent d10f76f commit 6c3e910

13 files changed

Lines changed: 89 additions & 2 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Added
44

55
- Support for Ruby 3.4.
6+
- Added per-filter option validation. Each filter type now validates its own specific options and raises `ArgumentError` when passed unrecognized options.
67

78
## Fixed
89

lib/active_interaction/filter.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ def factory(slug)
5151
CLASSES.fetch(slug) { raise MissingFilterError, slug.inspect }
5252
end
5353

54+
# Returns the list of allowed options for this filter type.
55+
#
56+
# @return [Array<Symbol>]
57+
def allowed_options
58+
%i[desc default]
59+
end
60+
5461
private
5562

5663
# @param slug [Symbol]
@@ -66,6 +73,7 @@ def register(slug)
6673
#
6774
# @option options [Object] :default Fallback value to use when given `nil`.
6875
def initialize(name, options = {}, &block)
76+
validate_options!(options)
6977
@name = name
7078
@options = options.dup
7179
@filters = {}
@@ -229,6 +237,12 @@ def describe(value)
229237
"(Object doesn't support #inspect)"
230238
end
231239

240+
def validate_options!(options)
241+
if (invalid_options = options.keys - self.class.allowed_options).any?
242+
raise ArgumentError, "invalid options: #{invalid_options.join(', ')}"
243+
end
244+
end
245+
232246
def raw_default(context)
233247
value = options.fetch(:default)
234248
return value unless value.is_a?(Proc)

lib/active_interaction/filters/abstract_date_time_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ module ActiveInteraction
88
#
99
# @private
1010
class AbstractDateTimeFilter < Filter
11+
def self.allowed_options
12+
super + %i[format]
13+
end
14+
1115
def database_column_type
1216
self.class.slug
1317
end

lib/active_interaction/filters/array_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class ArrayFilter < Filter
3838

3939
register :array
4040

41+
def self.allowed_options
42+
super + %i[index_errors]
43+
end
44+
4145
def process(value, context)
4246
input = super
4347

lib/active_interaction/filters/decimal_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class Base # rubocop:disable Lint/EmptyClass
1919
class DecimalFilter < AbstractNumericFilter
2020
register :decimal
2121

22+
def self.allowed_options
23+
super + %i[digits]
24+
end
25+
2226
private
2327

2428
def digits

lib/active_interaction/filters/hash_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ class HashFilter < Filter
2525

2626
register :hash
2727

28+
def self.allowed_options
29+
super + %i[strip]
30+
end
31+
2832
def process(value, context) # rubocop:disable Metrics/AbcSize
2933
input = super
3034

lib/active_interaction/filters/integer_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ class Base # rubocop:disable Lint/EmptyClass
2020
class IntegerFilter < AbstractNumericFilter
2121
register :integer
2222

23+
def self.allowed_options
24+
super + %i[base]
25+
end
26+
2327
private
2428

2529
def base

lib/active_interaction/filters/interface_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class Base # rubocop:disable Lint/EmptyClass
2828
class InterfaceFilter < Filter
2929
register :interface
3030

31+
def self.allowed_options
32+
super + %i[from methods]
33+
end
34+
3135
def initialize(name, options = {}, &block)
3236
if options.key?(:methods) && options.key?(:from)
3337
raise InvalidFilterError,

lib/active_interaction/filters/object_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class Base # rubocop:disable Lint/EmptyClass
2828
class ObjectFilter < Filter
2929
register :object
3030

31+
def self.allowed_options
32+
super + %i[class converter]
33+
end
34+
3135
private
3236

3337
def klass

lib/active_interaction/filters/record_filter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class Base # rubocop:disable Lint/EmptyClass
3030
class RecordFilter < Filter
3131
register :record
3232

33+
def self.allowed_options
34+
super + %i[class finder]
35+
end
36+
3337
private
3438

3539
def klass

0 commit comments

Comments
 (0)