Skip to content

Conversation

jgaskins
Copy link
Owner

Following a conversation on The Practical Dev, I began thinking that maybe validations on the output aren't a terrible idea. If the contract between an API and a client says that some number will be a float in the range of 0.0...1.0, checking that it's an instance of Float is not good enough to comply with that contract.

This PR (in its current state) is an example of how declaring that could look:

class PostPrimalizer < Primalize::Single
  attributes(
    upvote_percentage: validate(float) { |percentage| (0...1).cover? percentage },
  )
end

A few things I'm unsure of:

  • Naming of validate. It is a validation, but so are the type and structure checks. This is intended for the value of primitives, but that's really the only difference.
  • The block has a different meaning here than for the other DSL methods. It's a pass/fail depending on truthiness of the return value rather than transforming what it receives. It makes sense with that context, but divergence from the convention feels weird.
  • Error messages can't be as nice as for other DSL methods because we can't show why it failed validation, just that it did.

The only thing I can think of to improve on these is to make it work something like this:

attributes(
  number: value(integer, between: 0..10),
  email: value(string, match: /\w@\w/),
)

That means we have to define a bunch of special-case matchers, but it would let the error messages look good, we wouldn't have to have a different meaning for the block, and it's also another naming suggestion for the DSL method.

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.

1 participant