Skip to content

Commit 479a8cd

Browse files
committed
Add params validation and method wrapping logic
Adds the validation logic that integrates with dry-schema: - validate_params instance method that validates input against the schema - Method wrapping via create_validator_for that prepends validation to wrapped methods - Handles both positional hash and keyword argument calling styles - Integration with PrependManager to apply validation before StepsMethodPrepender - Returns Failure[:invalid_params, errors] when validation fails - Adds dry-schema development dependency to Gemfile
1 parent 6342c38 commit 479a8cd

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ end
2222

2323
group :development, :test do
2424
gem "activerecord"
25+
gem "dry-schema"
2526
gem "rom-sql"
2627
gem "sequel"
2728
gem "sqlite3"

lib/dry/operation/extensions/params.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@ module Extensions
1818
module Params
1919
def self.included(klass)
2020
klass.extend(ClassMethods)
21+
klass.prepend(InstanceMethods)
22+
end
23+
24+
# Instance methods for params validation
25+
module InstanceMethods
26+
include Dry::Monads::Result::Mixin
27+
28+
# Validates input against the params schema
29+
#
30+
# @param input [Hash] The input to validate
31+
# @return [Dry::Monads::Result] Success with validated params or Failure with errors
32+
# @api private
33+
def validate_params(input)
34+
schema = self.class._params_schema
35+
36+
return Success(input) unless schema
37+
38+
result = schema.call(input)
39+
40+
if result.success?
41+
Success(result.to_h)
42+
else
43+
Failure[:invalid_params, result.errors.to_h]
44+
end
45+
end
2146
end
2247

2348
# Class methods added to the operation class
@@ -30,13 +55,48 @@ module ClassMethods
3055
# @return [Dry::Schema::Params] The compiled schema
3156
def params(&block)
3257
@_params_schema = Dry::Schema.Params(&block)
58+
_apply_params_validation
3359
end
3460

3561
# @api private
3662
def _params_schema
3763
@_params_schema
3864
end
3965

66+
# @api private
67+
def _params_validated_methods
68+
@_params_validated_methods ||= []
69+
end
70+
71+
# @api private
72+
def _apply_params_validation
73+
methods_to_wrap = instance_variable_get(:@_prepend_manager)
74+
&.instance_variable_get(:@methods_to_prepend) || []
75+
76+
methods_to_wrap.each do |method_name|
77+
next if _params_validated_methods.include?(method_name)
78+
next unless instance_methods.include?(method_name)
79+
80+
prepend(Params.create_validator_for(method_name))
81+
_params_validated_methods << method_name
82+
end
83+
end
84+
85+
# @api private
86+
def method_added(method_name)
87+
if @_params_schema
88+
methods_to_wrap = instance_variable_get(:@_prepend_manager)
89+
&.instance_variable_get(:@methods_to_prepend) || []
90+
91+
if methods_to_wrap.include?(method_name) && !_params_validated_methods.include?(method_name)
92+
prepend(Params.create_validator_for(method_name))
93+
_params_validated_methods << method_name
94+
end
95+
end
96+
97+
super
98+
end
99+
40100
# @api private
41101
def inherited(subclass)
42102
super
@@ -45,6 +105,34 @@ def inherited(subclass)
45105
end
46106
end
47107
end
108+
109+
# @api private
110+
# Creates a module that wraps a method to add params validation
111+
def self.create_validator_for(method_name)
112+
Module.new do
113+
define_method(method_name) do |input = {}, *rest, **kwargs, &block|
114+
# Handle Ruby 3+ keyword argument behavior
115+
use_kwargs = input.empty? && !kwargs.empty? && rest.empty?
116+
actual_input = use_kwargs ? kwargs : input
117+
118+
validation_result = validate_params(actual_input)
119+
120+
case validation_result
121+
when Dry::Monads::Success
122+
validated_input = validation_result.value!
123+
124+
# Pass validated params in the same format as received
125+
if use_kwargs
126+
super(**validated_input, &block)
127+
else
128+
super(validated_input, *rest, **kwargs, &block)
129+
end
130+
when Dry::Monads::Failure
131+
throw_failure(validation_result)
132+
end
133+
end
134+
end
135+
end
48136
end
49137
end
50138
end

0 commit comments

Comments
 (0)