Git Product home page Git Product logo

hash_validator's Introduction

Hash Validator

Gem Travis Coveralls Maintainability

Ruby library to validate hashes (Hash) against user-defined requirements

Installation

Add this line to your application's Gemfile:

gem 'hash_validator'

And then execute:

$ bundle

Or install it yourself as:

$ gem install hash_validator

Example

# Validations hash
validations = {
  user: {
    first_name: String,
    last_name:  'string',
    age:        'numeric',
    likes:      'array'
  }
}

# Hash to validate
hash = {
  foo: 1,
  bar: 'baz',
  user: {
    first_name: 'James',
    last_name:  12345
  }
}

validator = HashValidator.validate(hash, validations)

validator.valid?
  # => false

validator.errors
  # {
      :user => {
          :last_name => "string required",
                :age => "numeric required",
              :likes => "array required"
      }
    }

Usage

Define a validation hash which will be used to validate. This has can be nested as deeply as required using the following values to validate specific value types:

  • array
  • boolean
  • complex
  • enumerable
  • float
  • integer
  • numeric
  • range
  • rational
  • regexp
  • string
  • symbol
  • time
  • required: just requires any value to be present for the designated key.
  • hashes are validates by nesting validations, or if just the presence of a hash is required {} can be used.

On top of the pre-defined simple types, classes can be used directly (e.g. String) to validate the presence of a value of a desired class.

Additional validations exist to validate beyond simple typing, such as:

  • An Enumerable instance: validates that the value is contained within the supplied enumerable.
  • A lambda/Proc instance: validates that the lambda/proc returns true when the value is supplied (lambdas must accept only one argument).
  • A regexp instance: validates that the regex returns a match when the value is supplied (Regexp#match(value) is not nil).
  • email: email address validation (string + email address).

Example use-cases include Ruby APIs (I'm currently using it in a Rails API that I'm building for better error responses to developers).

Custom validations

Allows custom defined validations (must inherit from HashValidator::Validator::Base). Example:

# Define our custom validator
class HashValidator::Validator::OddValidator < HashValidator::Validator::Base
  def initialize
    super('odd')  # The name of the validator
  end

  def validate(key, value, validations, errors)
    unless value.is_a?(Integer) && value.odd?
      errors[key] = presence_error_message
    end
  end
end

# Add the validator
HashValidator.append_validator(HashValidator::Validator::OddValidator.new)

# Now the validator can be used! e.g.
validator = HashValidator.validate({ age: 27 }, { age: 'odd' })
validator.valid?  # => true
validator.errors  # => {}

Multiple validators

Multiple validators can be applied to a single key, e.g.

HashValidator.validate(
  { foo: 73 },
  { foo: HashValidator.multiple('numeric', 1..100) }
)

This is particularly useful when defining custom validators.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

hash_validator's People

Contributors

jamesbrooks avatar peeja avatar tencokacistromy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

hash_validator's Issues

How to use regexp validations?

I'm trying to use regexp validation with the following validation hash:

validations = {
  'health_check' => {
     'protocol' => /^(http|tcp)$/,
     ...
  }
}

When I run validation I got the following error message:

/Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators.rb:18:in 'validator_for': Could not find valid validator for: (?-mix:^(http|tcp)$) (StandardError)
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:21:in `block in validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:20:in `each'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:20:in `validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:21:in `block in validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:20:in `each'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/validators/hash_validator.rb:20:in `validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/base.rb:28:in `validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/base.rb:10:in `initialize'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/base.rb:19:in `new'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator/base.rb:19:in `validate'
    from /Users/lauri/.rvm/gems/ruby-2.3.1/gems/hash_validator-0.6.0/lib/hash_validator.rb:3:in `validate'

Am I doing something wrong or is this a bug?

[enhancement] Exclusive key validation.

This library would benefit from having an option to prohibit a hash from having any keys not explicitly named in the validation hash. For example:

my_hash = { first_name: "John",
            last_name: "Doe",
            invalid: "data that should not be here" }

validation = { first_name: 'string',
               last_name: 'string' }

# Fails because of presence of unexpected key "invalid"
HashValidator.validate(my_hash, validation, exclusive: true)

I can put together a PR if we can agree on the interface.

How can I validate an array of values within a given set?

Hello!

I'm playing around with this great gem but I had a question that I can't figure out yet.

let's say I have a hash like

events: ['foo', 'bar', 'baz']

and I want to validate that the events key is an array and that the values within that array are included in some permitted value how I could achieve that without a proc?

right now my validator looks something like

'events' => lambda { |value|
  value.is_a?(Array) && (value - ['foo', 'bar', 'baz']).empty?
}

which works fine but I was wondering if the DSL allowed for something that could be translated to JSON and passed to my frontend as well.

Needs more examples beyond simple

Suppose I have a hash that has optional keys, but the keys that are provided must be in a list if they are provided.

VALID_FOO = [ONE,TWO]
VALID_BAR = [THREE,FOUR]

valid_hash = { foo: [ONE,TWO], bar: [THREE,FOUR]}
also_valid = {}
also_valid = {foo: [ONE]}
also_valid = {bar: [THREE]}
invalid = {foo: ONE}
invalid_also = {bar: ONE}
invalid_also = {bar: [ONE]}

Thus, bar and foo keys are optional. However, if they exist, they must be an array, whose values are in VALID_FOO or VALID_BAR as appropriate.

How would we specify that validation?

Enumeration support

It would be great if you could specify an enumeration for validation purposes, where the value must exist in the enumeration. You could use an array to specify the accepted values:

{
  status: [:new, :open, :closed]
}

Requied field bug when evaluating value is boolean "false"

valid = { "value" => "required" }

test1 = { "value" => false }
test2 = { "value" => true }
test3 = { "value" => "Fruitbat" }

HashValidator.validate(test3,valid).valid?
=> true
HashValidator.validate(test2,valid).valid?
=> true
HashValidator.validate(test1,valid).valid?
=> false

All of the 3 evaluations should validate true.

Add 'hash' type to stop validation recursion

First of all, very nice gem!

Use case: { access_token: 'string', action: 'string', params: 'hash' }
I want to make sure I only have these three keys in my hash, but the validation for the params will be done in another part of the code. Is it possible to implement this with the current API? I tried using a '{}' but it fails since it continue the validation on the inner hash.

This would be specially useful with the strict flag true. In a non strict validation, I could omit the params key, but in a strict validation I could not find a way to express this.

If you guys agree this is a good problem to solve, let me know and I'd love to implement the PR.

Cheers

Conditional and referential validations

How do you validate something like:

{
  'married' => 'boolean',
  'spouse_name' => 'string if married otherwise nil'
}

Or:

{
   'pets' => 'array'
   'favorite_pet' => 'string that is in "pets"'
}

Feature Request: Union

Hello james! I have a feature request. Most modern languages have a concept named union types:

The type is an element of a set. I know it's easy to write with as a lambda. But it's way better to read, when you have a notation like HashValidator::Union[*typesl]. Another name could be HashValidator::Or.

class Email; attr_accessor :text; end

# Validations hash
validators = {  email: HashValidator::Union[String, Email] }

# First case, it's a String
user1 =  { email: '[email protected]' }
HashValidator.validate(user1, validations)

# Second case, it's an Email
email = Email.new
email.text = '[email protected]'
user2 =  { email: email }
HashValidator.validate(user2, validations)

Append Validator Doesn't Work

Append validator doesn't work when adding custom validations. You have multiple people (myself included) forking the repository to add custom validators because when you append the validator using your method, it appends it to the list, but then can't find that validator. If you try and append it again, it indicates the validator has already been appended.

Hopefully you can check this out because I (and I'm sure many others) would be really happy to be able to use the custom validations without forking the repository.

...and it's also really annoying to debug so it should be fixed :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.