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

Support for "validate" helper within rule blocks #679

Open
solnic opened this issue Dec 16, 2020 · 6 comments
Open

Support for "validate" helper within rule blocks #679

solnic opened this issue Dec 16, 2020 · 6 comments

Comments

@solnic
Copy link
Member

solnic commented Dec 16, 2020

Support for executing predicates using validate method within rule blocks will make it much easier to apply various checks with extra conditions:

params do
  optional(:per_page).filled(:integer)
end

rule(:per_page) do
  if key?
    key.failure("must be within 0..20 range") unless validate(gt?: 0, lteq?: 20)
  end
end

See the original conversation: #678

@musaffa
Copy link

musaffa commented Dec 16, 2020

Will it be possible to call validate inside rule block without providing an explicit key failure as shown above? Predicate macros and custom registered macros have key failures defined in them already.

@flash-gordon
Copy link
Member

smth like valid?(gt?: 0, lteq?: 20). I'm not sure if it should be done in a single PR

@solnic
Copy link
Member Author

solnic commented Dec 17, 2020

Will it be possible to call validate inside rule block without providing an explicit key failure as shown above?

@musaffa yes! I just updated the example but I think @flash-gordon has a point and we should have valid? too and I agree it should be in a separate PR as it would be a distinct new feature too.

@zavan
Copy link

zavan commented Nov 16, 2022

I monkey-patched Evaluator to add validate as a proof of concept:

module Dry
  module Validation
    class Evaluator
      def validate(*args)
        macros = args.each_with_object([]) do |spec, macros|
          case spec
          when Hash
            spec.each do |k, v|
              macros << [k, v.is_a?(Array) ? v : [v]]
            end
          else
            macros << Array(spec)
          end
        end
  
        macros.each do |args|
          macro = macro(*args.flatten(1))
          instance_exec(**macro.extract_block_options(_options.merge(macro: macro)), &macro.block)
        end
      end
    end
  end
end

Then you can do:

rule(:age) do
  validate(:filled?, gt?: 18)
end

I just took these methods from Rule to prepare the macros and this from Evaluator to run the macros and merged them.

I want to refactor it, write tests and docs and open a PR, but I wanted to clear this out with y'all first: I think in Rule we just assign @macros as it's passed (@macros = macros) here and here and move all the macro parsing to Evaluator. Sounds good?

@zavan
Copy link

zavan commented Nov 16, 2022

I forked and created a branch if you want to take a look: main...zavan:dry-validation:macros-within-rule

No tests yet and it breaks the existing ones relying on Contract doubles, as contract is expected to respond to #macro.

@solnic
Copy link
Member Author

solnic commented Nov 26, 2022

It would be great to have this. If you could open a PR with fixed tests that would be awesome.

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

No branches or pull requests

4 participants